diff options
Diffstat (limited to 'src')
191 files changed, 5891 insertions, 6225 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b3e05f60f..e113f2d88 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -31,7 +31,6 @@ function(tinyusb_sources_get OUTPUT_VAR) ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/midi/midi_host.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/midi/midi2_host.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/msc/msc_host.c - ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/vendor/vendor_host.c # typec ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/typec/usbc.c PARENT_SCOPE diff --git a/src/class/audio/audio.h b/src/class/audio/audio.h index 428391bb2..82db9ed9e 100644 --- a/src/class/audio/audio.h +++ b/src/class/audio/audio.h @@ -1,26 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * Copyright (c) 2020 Reinhard Panhuber - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-FileCopyrightText: Copyright (c) 2020 Reinhard Panhuber + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -102,6 +83,71 @@ typedef enum { AUDIO_TERM_TYPE_OUT_LOW_FRQ_EFFECTS_SPEAKER = 0x0307, } audio_terminal_output_type_t; +/// 2.4 - Audio Class-Bi-directional Terminal Types UAC2 +typedef enum +{ + AUDIO_TERM_TYPE_BI_DIRECTIONAL_UNDEFINED = 0x0400, + AUDIO_TERM_TYPE_BI_DIRECTIONAL_HEADSET_HAND_HELD = 0x0401, + AUDIO_TERM_TYPE_BI_DIRECTIONAL_HEADSET_MOUNTED = 0x0402, + AUDIO_TERM_TYPE_BI_DIRECTIONAL_SPEAKERPHONE = 0x0403, + AUDIO_TERM_TYPE_BI_DIRECTIONAL_SPEAKERPHONE_ECHO_SUPPRESS = 0x0404, + AUDIO_TERM_TYPE_BI_DIRECTIONAL_SPEAKERPHONE_ECHO_CANCEL = 0x0405, +} audio_terminal_bi_directional_type_t; + +/// 2.5 - Audio Class-Telephone Terminal Types UAC2 +typedef enum +{ + AUDIO_TERM_TYPE_TELEPHONE_UNDEFINED = 0x0500, + AUDIO_TERM_TYPE_TELEPHONE_PHONE_LINE = 0x0501, + AUDIO_TERM_TYPE_TELEPHONE_TELEPHONE = 0x0502, + AUDIO_TERM_TYPE_TELEPHONE_DOWN_LINE_PHONE = 0x0503, +} audio_terminal_telephony_type_t; + +/// 2.6 - Audio Class-External Types UAC2 +typedef enum +{ + AUDIO_TERM_TYPE_EXTERNAL_UNDEFINED = 0x0600, + AUDIO_TERM_TYPE_EXTERNAL_ANALOG_CONNECTOR = 0x0601, + AUDIO_TERM_TYPE_EXTERNAL_DIGITAL_AUDIO = 0x0602, + AUDIO_TERM_TYPE_EXTERNAL_LINE_CONNECTOR = 0x0603, + AUDIO_TERM_TYPE_EXTERNAL_LEGACY_AUDIO_CONNECTOR = 0x0604, + AUDIO_TERM_TYPE_EXTERNAL_SPDIF_INTERFACE = 0x0605, + AUDIO_TERM_TYPE_EXTERNAL_1394_DA_STREAM = 0x0606, + AUDIO_TERM_TYPE_EXTERNAL_1394_DV_STREAM_SOUNDTRACK = 0x0607, + AUDIO_TERM_TYPE_EXTERNAL_ADAT_LIGHTPIPE = 0x0608, + AUDIO_TERM_TYPE_EXTERNAL_TDIF = 0x0609, + AUDIO_TERM_TYPE_EXTERNAL_MADI = 0x060A, +} audio_terminal_external_type_t; + +/// 2.7 - Audio Class-Embedded Types UAC2 +typedef enum +{ + AUDIO_TERM_TYPE_EMBEDDED_UNDEFINED = 0x0700, + AUDIO_TERM_TYPE_EMBEDDED_LEVEL_CALIBRATION_NOISE_SOURCE = 0x0701, + AUDIO_TERM_TYPE_EMBEDDED_EQUALIZATION_NOISE = 0x0702, + AUDIO_TERM_TYPE_EMBEDDED_CD_PLAYER = 0x0703, + AUDIO_TERM_TYPE_EMBEDDED_DAT = 0x0704, + AUDIO_TERM_TYPE_EMBEDDED_DCC = 0x0705, + AUDIO_TERM_TYPE_EMBEDDED_COMPRESSED_AUDIO_PLAYER = 0x0706, + AUDIO_TERM_TYPE_EMBEDDED_ANALOG_TAPE = 0x0707, + AUDIO_TERM_TYPE_EMBEDDED_PHONOGRAPH = 0x0708, + AUDIO_TERM_TYPE_EMBEDDED_VCR_AUDIO = 0x0709, + AUDIO_TERM_TYPE_EMBEDDED_VIDEO_DISC_AUDIO = 0x070A, + AUDIO_TERM_TYPE_EMBEDDED_DVD_AUDIO = 0x070B, + AUDIO_TERM_TYPE_EMBEDDED_TV_TUNER_AUDIO = 0x070C, + AUDIO_TERM_TYPE_EMBEDDED_SATELLITE_RECEIVER_AUDIO = 0x070D, + AUDIO_TERM_TYPE_EMBEDDED_CABLE_TUNER_AUDIO = 0x070E, + AUDIO_TERM_TYPE_EMBEDDED_DSS_AUDIO = 0x070F, + AUDIO_TERM_TYPE_EMBEDDED_RADIO_RECEIVER = 0x0710, + AUDIO_TERM_TYPE_EMBEDDED_RADIO_TRANSMITTER = 0x0711, + AUDIO_TERM_TYPE_EMBEDDED_MULTI_TRACK_RECORDER = 0x0712, + AUDIO_TERM_TYPE_EMBEDDED_SYNTHESIZER = 0x0713, + AUDIO_TERM_TYPE_EMBEDDED_PIANO = 0x0714, + AUDIO_TERM_TYPE_EMBEDDED_GUITAR = 0x0715, + AUDIO_TERM_TYPE_EMBEDDED_DRUMS = 0x0716, + AUDIO_TERM_TYPE_EMBEDDED_OTHER_MUSICAL_INSTRUMENT = 0x0717, +} audio_terminal_embedded_type_t; + /// Rest is yet to be implemented //--------------------------------------------------------------------+ diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 995bf8a3e..bc4c7e544 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -1,26 +1,8 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2020 Reinhard Panhuber, Jerzy Kasenberg - * Copyright (c) 2023 HiFiPhile - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2020 Reinhard Panhuber, Jerzy Kasenberg + * SPDX-FileCopyrightText: Copyright (c) 2023 HiFiPhile (Zixun LI) + * SPDX-FileCopyrightText: Copyright (c) 2020 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -1179,9 +1161,6 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p is_feedback_ep = (desc_ep->bmAttributes.usage == 1); } - //TODO: We need to set EP non busy since this is not taken care of right now in ep_close() - THIS IS A WORKAROUND! - usbd_edpt_clear_stall(rhport, ep_addr); - #if CFG_TUD_AUDIO_ENABLE_EP_IN // For data or data with implicit feedback IN EP if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && is_data_ep) @@ -1862,7 +1841,7 @@ static bool audiod_calc_tx_packet_sz(audiod_function_t *audio) { static uint16_t audiod_tx_packet_size(const uint16_t *nominal_size, uint16_t data_count, uint16_t fifo_depth, uint16_t fifo_threshold, uint16_t max_depth) { // Flow control need a FIFO size of at least 4*Navg - if (nominal_size[1] && nominal_size[1] <= fifo_depth * 4) { + if (nominal_size[1] && nominal_size[1] * 4 <= fifo_depth) { // Use blackout to prioritize normal size packet static int ctrl_blackout = 0; uint16_t packet_size; diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index 1e0c46915..41cc969d1 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -1,27 +1,8 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2020 Ha Thach (tinyusb.org) - * Copyright (c) 2020 Reinhard Panhuber - * Copyright (c) 2023 HiFiPhile - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2020 Ha Thach (tinyusb.org) + * SPDX-FileCopyrightText: Copyright (c) 2020 Reinhard Panhuber + * SPDX-FileCopyrightText: Copyright (c) 2023 HiFiPhile (Zixun LI) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/bth/bth_device.c b/src/class/bth/bth_device.c index b679d6ab6..f942950c6 100755 --- a/src/class/bth/bth_device.c +++ b/src/class/bth/bth_device.c @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2020 Jerzy Kasenberg - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2020 Jerzy Kasenberg + * SPDX-FileCopyrightText: Copyright (c) 2020 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/bth/bth_device.h b/src/class/bth/bth_device.h index 89a056dc8..f38ebdf45 100755 --- a/src/class/bth/bth_device.h +++ b/src/class/bth/bth_device.h @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2020 Jerzy Kasenberg - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2020 Jerzy Kasenberg + * SPDX-FileCopyrightText: Copyright (c) 2020 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/cdc/cdc.h b/src/class/cdc/cdc.h index 679723ba6..2071ce408 100644 --- a/src/class/cdc/cdc.h +++ b/src/class/cdc/cdc.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index c499756b9..ed050ad03 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -342,9 +323,7 @@ uint16_t cdcd_open(uint8_t rhport, const tusb_desc_interface_t* itf_desc, uint16 tu_edpt_stream_t *stream_tx = &p_cdc->tx_stream; tu_edpt_stream_open(stream_tx, rhport, desc_ep, CFG_TUD_CDC_TX_EPSIZE); - #if CFG_TUD_CDC_TX_PERSISTENT - tu_edpt_stream_write_xfer(stream_tx); // flush pending data - #else + #if !CFG_TUD_CDC_TX_PERSISTENT tu_edpt_stream_clear(stream_tx); #endif } else { diff --git a/src/class/cdc/cdc_device.h b/src/class/cdc/cdc_device.h index 9ac6bc58a..7951be986 100644 --- a/src/class/cdc/cdc_device.h +++ b/src/class/cdc/cdc_device.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 4441222c8..7a979f649 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-FileCopyrightText: Copyright (c) 2024 Heiko Kuester + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. * @@ -732,9 +714,13 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t //--------------------------------------------------------------------+ // Enumeration //--------------------------------------------------------------------+ + static bool open_ep_stream_pair(cdch_interface_t *p_cdc, tusb_desc_endpoint_t const *desc_ep) { for (size_t i = 0; i < 2; i++) { - TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_BULK == desc_ep->bmAttributes.xfer, 0); + // pin bLength so tu_desc_next() below cannot walk the second endpoint past a caller-checked bound + TU_ASSERT(TUH_VALIDATE_BASIC(sizeof(tusb_desc_endpoint_t) == desc_ep->bLength) && + TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_BULK == desc_ep->bmAttributes.xfer, + 0); TU_ASSERT(tuh_edpt_open(p_cdc->daddr, desc_ep)); const uint8_t ep_dir = tu_edpt_dir(desc_ep->bEndpointAddress); tu_edpt_stream_t *stream = (ep_dir == TUSB_DIR_IN) ? &p_cdc->stream.rx : &p_cdc->stream.tx; @@ -840,7 +826,7 @@ static bool set_line_state_on_enum(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { ENUM_SET_LINE_CONTROL, ENUM_SET_LINE_COMPLETE, }; - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + #if defined(CFG_TUH_CDC_LINE_CODING_ON_ENUM) || defined(CFG_TUH_CDC_LINE_CONTROL_ON_ENUM) const uint8_t idx = get_idx_by_ptr(p_cdc); #endif const uintptr_t state = xfer->user_data; @@ -1030,6 +1016,8 @@ static uint16_t acm_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, u const uint8_t *p_desc = (const uint8_t *)itf_desc; const uint8_t *desc_end = p_desc + max_len; + TU_ASSERT(TUH_VALIDATE_BASIC(tu_desc_len(p_desc) <= max_len), 0); + cdch_interface_t *p_cdc = make_new_itf(daddr, itf_desc); TU_VERIFY(p_cdc, 0); p_cdc->serial_drid = SERIAL_DRIVER_ACM; @@ -1038,8 +1026,15 @@ static uint16_t acm_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, u p_desc = tu_desc_next(p_desc); // Communication Functional Descriptors - while ((p_desc < desc_end) && (TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc))) { - if (CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc)) { + // need the 3-byte header (bLength/bDescriptorType/bDescriptorSubType) in bounds before reading it, and a + // fully contained bLength >= 3 both keeps those reads valid and stops a zero-length descriptor from spinning + while ((p_desc < desc_end) && + TUH_VALIDATE_BASIC((size_t)(desc_end - p_desc) >= 3) && + TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && + TUH_VALIDATE_BASIC(tu_desc_len(p_desc) >= 3) && + TUH_VALIDATE_BASIC(tu_desc_len(p_desc) <= (size_t)(desc_end - p_desc))) { + if (CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc) && + TUH_VALIDATE_BASIC(tu_desc_len(p_desc) >= sizeof(cdc_desc_func_acm_t))) { // save ACM bmCapabilities p_cdc->acm.capability = ((cdc_desc_func_acm_t const *) p_desc)->bmCapabilities; } @@ -1049,23 +1044,29 @@ static uint16_t acm_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, u // Open notification endpoint of control interface if any if (itf_desc->bNumEndpoints == 1) { + // whole endpoint descriptor must fit: tuh_edpt_open reads the full struct regardless of bLength + TU_ASSERT(TUH_VALIDATE_BASIC((size_t)(desc_end - p_desc) >= sizeof(tusb_desc_endpoint_t)), 0); TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc), 0); const tusb_desc_endpoint_t *desc_ep = (const tusb_desc_endpoint_t *)p_desc; TU_ASSERT(tuh_edpt_open(daddr, desc_ep), 0); p_cdc->ep_notif = desc_ep->bEndpointAddress; - p_desc = tu_desc_next(p_desc); + // advance by the fixed struct size, not device-supplied bLength, so p_desc stays inside the checked window + p_desc += sizeof(tusb_desc_endpoint_t); } //------------- Data Interface (if any) -------------// - if (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) { + if (TUH_VALIDATE_BASIC((size_t)(desc_end - p_desc) >= sizeof(tusb_desc_interface_t)) && + TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) { const tusb_desc_interface_t *data_itf = (const tusb_desc_interface_t *)p_desc; if (data_itf->bInterfaceClass == TUSB_CLASS_CDC_DATA) { - p_desc = tu_desc_next(p_desc); // next to endpoint descriptor + p_desc += sizeof(tusb_desc_interface_t); // fixed struct size to endpoint descriptor, not device bLength - // data endpoints expected to be in pairs + // open_ep_stream_pair consumes exactly two endpoints; require that count and that both fit before reading them + TU_ASSERT(TUH_VALIDATE_BASIC(data_itf->bNumEndpoints == 2), 0); + TU_ASSERT(TUH_VALIDATE_BASIC((size_t)(desc_end - p_desc) >= 2 * sizeof(tusb_desc_endpoint_t)), 0); TU_ASSERT(open_ep_stream_pair(p_cdc, (const tusb_desc_endpoint_t *)p_desc), 0); - p_desc += data_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t); + p_desc += 2 * sizeof(tusb_desc_endpoint_t); } } @@ -1207,6 +1208,7 @@ static uint16_t ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, TU_VERIFY(itf_desc->bInterfaceSubClass == 0xff && itf_desc->bInterfaceProtocol == 0xff && itf_desc->bNumEndpoints == 2, 0); + TU_VERIFY(TUH_VALIDATE_BASIC(itf_desc->bLength == sizeof(tusb_desc_interface_t)), 0); const uint16_t drv_len = (uint16_t)(sizeof(tusb_desc_interface_t) + itf_desc->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); TU_VERIFY(drv_len <= max_len, 0); @@ -1592,6 +1594,7 @@ enum { static uint16_t cp210x_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len) { // CP210x Interface includes 1 vendor interface + 2 bulk endpoints TU_VERIFY(itf_desc->bInterfaceSubClass == 0 && itf_desc->bInterfaceProtocol == 0 && itf_desc->bNumEndpoints == 2, 0); + TU_VERIFY(TUH_VALIDATE_BASIC(itf_desc->bLength == sizeof(tusb_desc_interface_t)), 0); const uint16_t drv_len = (uint16_t)(sizeof(tusb_desc_interface_t) + itf_desc->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); TU_VERIFY(drv_len <= max_len, 0); @@ -1763,6 +1766,7 @@ enum { static uint16_t ch34x_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len) { // CH34x Interface includes 1 vendor interface + 2 bulk + 1 interrupt endpoints TU_VERIFY(itf_desc->bNumEndpoints == 3, 0); + TU_VERIFY(TUH_VALIDATE_BASIC(itf_desc->bLength == sizeof(tusb_desc_interface_t)), 0); const uint16_t drv_len = (uint16_t)(sizeof(tusb_desc_interface_t) + itf_desc->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); TU_VERIFY(drv_len <= max_len, 0); @@ -2099,6 +2103,7 @@ enum { static uint16_t pl2303_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len) { // PL2303 Interface includes 1 vendor interface + 1 interrupt endpoints + 2 bulk TU_VERIFY(itf_desc->bNumEndpoints == 3, 0); + TU_VERIFY(TUH_VALIDATE_BASIC(itf_desc->bLength == sizeof(tusb_desc_interface_t)), 0); const uint16_t drv_len = (uint16_t)(sizeof(tusb_desc_interface_t) + itf_desc->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); TU_VERIFY(drv_len <= max_len, 0); diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index 1b1709b18..5438c8251 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/cdc/cdc_rndis.h b/src/class/cdc/cdc_rndis.h index fbbd43206..a2d36aa74 100644 --- a/src/class/cdc/cdc_rndis.h +++ b/src/class/cdc/cdc_rndis.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/cdc/serial/ch34x.h b/src/class/cdc/serial/ch34x.h index 0e08b0acd..12fb58c6f 100644 --- a/src/class/cdc/serial/ch34x.h +++ b/src/class/cdc/serial/ch34x.h @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2023 Heiko Kuester - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2023 Heiko Kuester + * SPDX-FileCopyrightText: Copyright (c) 2023 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/cdc/serial/cp210x.h b/src/class/cdc/serial/cp210x.h index a0eff9e40..2f26c405a 100644 --- a/src/class/cdc/serial/cp210x.h +++ b/src/class/cdc/serial/cp210x.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2023 Ha Thach ([email protected]) for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2023 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT */ #ifndef TUSB_CP210X_H diff --git a/src/class/cdc/serial/ftdi_sio.h b/src/class/cdc/serial/ftdi_sio.h index 9bd56cef4..91843d0c4 100644 --- a/src/class/cdc/serial/ftdi_sio.h +++ b/src/class/cdc/serial/ftdi_sio.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2023 Ha Thach ([email protected]) for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2023 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT */ #ifndef TUSB_FTDI_SIO_H diff --git a/src/class/cdc/serial/pl2303.h b/src/class/cdc/serial/pl2303.h index 63910c7bb..f3e77b265 100644 --- a/src/class/cdc/serial/pl2303.h +++ b/src/class/cdc/serial/pl2303.h @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2024 Heiko Kuester - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2024 Heiko Kuester + * SPDX-FileCopyrightText: Copyright (c) 2024 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/dfu/dfu.h b/src/class/dfu/dfu.h index 8cd63656a..a04e2e084 100644 --- a/src/class/dfu/dfu.h +++ b/src/class/dfu/dfu.h @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021 XMOS LIMITED - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021 XMOS LIMITED + * SPDX-FileCopyrightText: Copyright (c) 2021 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/dfu/dfu_device.c b/src/class/dfu/dfu_device.c index ee57621b8..092abed03 100644 --- a/src/class/dfu/dfu_device.c +++ b/src/class/dfu/dfu_device.c @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021 XMOS LIMITED - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021 XMOS LIMITED + * SPDX-FileCopyrightText: Copyright (c) 2021 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -60,9 +42,8 @@ typedef struct { static dfu_state_ctx_t _dfu_ctx; -#if CFG_TUD_DFU_XFER_BUFSIZE > CFG_TUD_ENDPOINT0_BUFSIZE -TU_ATTR_ALIGNED(4) uint8_t _transfer_buf[CFG_TUD_DFU_XFER_BUFSIZE]; -#endif +// Download data must remain valid across the following GETSTATUS control transfer +TU_ATTR_ALIGNED(4) static uint8_t _transfer_buf[CFG_TUD_DFU_XFER_BUFSIZE]; static void reset_state(void) { _dfu_ctx.state = DFU_IDLE; @@ -70,15 +51,6 @@ static void reset_state(void) { _dfu_ctx.flashing_in_progress = false; } -static inline uint8_t* get_xfer_buffer(void) { - // Use EP0 buffer if it is large enough, otherwise use dedicated buffer - #if CFG_TUD_DFU_XFER_BUFSIZE > CFG_TUD_ENDPOINT0_BUFSIZE - return _transfer_buf; - #else - return usbd_get_ctrl_buf(); - #endif -} - static bool reply_getstatus(uint8_t rhport, const tusb_control_request_t* request, dfu_state_t state, dfu_status_t status, uint32_t timeout); static bool process_download_get_status(uint8_t rhport, uint8_t stage, const tusb_control_request_t* request); static bool process_manifest_get_status(uint8_t rhport, uint8_t stage, const tusb_control_request_t* request); @@ -294,10 +266,10 @@ bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control TU_VERIFY(_dfu_ctx.attrs & DFU_ATTR_CAN_UPLOAD); TU_VERIFY(request->wLength <= CFG_TUD_DFU_XFER_BUFSIZE); - const uint16_t xfer_len = tud_dfu_upload_cb(_dfu_ctx.alt, request->wValue, get_xfer_buffer(), + const uint16_t xfer_len = tud_dfu_upload_cb(_dfu_ctx.alt, request->wValue, _transfer_buf, request->wLength); - return tud_control_xfer(rhport, request, get_xfer_buffer(), xfer_len); + return tud_control_xfer(rhport, request, _transfer_buf, xfer_len); } break; @@ -317,7 +289,7 @@ bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control if (request->wLength > 0) { // Download with payload -> transition to DOWNLOAD SYNC _dfu_ctx.state = DFU_DNLOAD_SYNC; - return tud_control_xfer(rhport, request, get_xfer_buffer(), request->wLength); + return tud_control_xfer(rhport, request, _transfer_buf, request->wLength); } else { // Download is complete -> transition to MANIFEST SYNC _dfu_ctx.state = DFU_MANIFEST_SYNC; @@ -391,7 +363,7 @@ static bool process_download_get_status(uint8_t rhport, uint8_t stage, const tus } else if (stage == CONTROL_STAGE_ACK) { if (_dfu_ctx.flashing_in_progress) { _dfu_ctx.state = DFU_DNBUSY; - tud_dfu_download_cb(_dfu_ctx.alt, _dfu_ctx.block, get_xfer_buffer(), _dfu_ctx.length); + tud_dfu_download_cb(_dfu_ctx.alt, _dfu_ctx.block, _transfer_buf, _dfu_ctx.length); } else { _dfu_ctx.state = DFU_DNLOAD_IDLE; } diff --git a/src/class/dfu/dfu_device.h b/src/class/dfu/dfu_device.h index b22b4c450..28dd026a5 100644 --- a/src/class/dfu/dfu_device.h +++ b/src/class/dfu/dfu_device.h @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021 XMOS LIMITED - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021 XMOS LIMITED + * SPDX-FileCopyrightText: Copyright (c) 2021 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/dfu/dfu_rt_device.c b/src/class/dfu/dfu_rt_device.c index a63c23d9a..6fafb8e77 100644 --- a/src/class/dfu/dfu_rt_device.c +++ b/src/class/dfu/dfu_rt_device.c @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Sylvain Munaut <[email protected]> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Sylvain Munaut <[email protected]> + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/dfu/dfu_rt_device.h b/src/class/dfu/dfu_rt_device.h index c4116d8fe..9db90799d 100644 --- a/src/class/dfu/dfu_rt_device.h +++ b/src/class/dfu/dfu_rt_device.h @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Sylvain Munaut <[email protected]> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Sylvain Munaut <[email protected]> + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/hid/hid.h b/src/class/hid/hid.h index 0883d95ac..a6d1dba15 100644 --- a/src/class/hid/hid.h +++ b/src/class/hid/hid.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -387,7 +368,7 @@ typedef enum /// @} //--------------------------------------------------------------------+ -// HID KEYCODE +// HID KEYCODE - defined by HID Usage Table: Keyboard/Keypad Page (0x07) //--------------------------------------------------------------------+ #define HID_KEY_NONE 0x00 #define HID_KEY_A 0x04 @@ -791,11 +772,12 @@ enum { HID_USAGE_PAGE_KEYBOARD = 0x07, HID_USAGE_PAGE_LED = 0x08, HID_USAGE_PAGE_BUTTON = 0x09, - HID_USAGE_PAGE_ORDINAL = 0x0a, - HID_USAGE_PAGE_TELEPHONY = 0x0b, - HID_USAGE_PAGE_CONSUMER = 0x0c, - HID_USAGE_PAGE_DIGITIZER = 0x0d, - HID_USAGE_PAGE_PID = 0x0f, + HID_USAGE_PAGE_ORDINAL = 0x0A, + HID_USAGE_PAGE_TELEPHONY = 0x0B, + HID_USAGE_PAGE_CONSUMER = 0x0C, + HID_USAGE_PAGE_DIGITIZER = 0x0D, + HID_USAGE_PAGE_HAPTIC = 0x0E, + HID_USAGE_PAGE_PID = 0x0F, HID_USAGE_PAGE_UNICODE = 0x10, HID_USAGE_PAGE_SOC = 0x11, HID_USAGE_PAGE_EYE_AND_HEAD_TRACKERS = 0x12, @@ -805,528 +787,1091 @@ enum { HID_USAGE_PAGE_SENSORS = 0x20, // 0x21 - 0x3f is reserved HID_USAGE_PAGE_MEDICAL_INSTRUMENT = 0x40, + HID_USAGE_PAGE_BRAILLE_DISPLAY = 0x41, HID_USAGE_PAGE_LIGHTING_AND_ILLUMINATION = 0x59, HID_USAGE_PAGE_MONITOR = 0x80, // 0x80 - 0x83 HID_USAGE_PAGE_POWER = 0x84, HID_USAGE_PAGE_BATTERY = 0x85, // 0x86 - 0x87 is reserved for Power Device - HID_USAGE_PAGE_BARCODE_SCANNER = 0x8c, - HID_USAGE_PAGE_SCALE = 0x8d, - HID_USAGE_PAGE_MSR = 0x8e, + HID_USAGE_PAGE_BARCODE_SCANNER = 0x8C, + HID_USAGE_PAGE_SCALE = 0x8D, + HID_USAGE_PAGE_MSR = 0x8E, HID_USAGE_PAGE_CAMERA = 0x90, HID_USAGE_PAGE_ARCADE = 0x91, + HID_USAGE_PAGE_GAMING = 0x92, // Gaming Standards Association (GSA) HID usage page HID_USAGE_PAGE_FIDO = 0xF1D0, // FIDO alliance HID usage page HID_USAGE_PAGE_VENDOR = 0xFF00 // 0xFF00 - 0xFFFF }; /// HID Usage Table - Table 6: Generic Desktop Page enum { - HID_USAGE_DESKTOP_POINTER = 0x01, - HID_USAGE_DESKTOP_MOUSE = 0x02, - HID_USAGE_DESKTOP_JOYSTICK = 0x04, - HID_USAGE_DESKTOP_GAMEPAD = 0x05, - HID_USAGE_DESKTOP_KEYBOARD = 0x06, - HID_USAGE_DESKTOP_KEYPAD = 0x07, - HID_USAGE_DESKTOP_MULTI_AXIS_CONTROLLER = 0x08, - HID_USAGE_DESKTOP_TABLET_PC_SYSTEM = 0x09, - HID_USAGE_DESKTOP_X = 0x30, - HID_USAGE_DESKTOP_Y = 0x31, - HID_USAGE_DESKTOP_Z = 0x32, - HID_USAGE_DESKTOP_RX = 0x33, - HID_USAGE_DESKTOP_RY = 0x34, - HID_USAGE_DESKTOP_RZ = 0x35, - HID_USAGE_DESKTOP_SLIDER = 0x36, - HID_USAGE_DESKTOP_DIAL = 0x37, - HID_USAGE_DESKTOP_WHEEL = 0x38, - HID_USAGE_DESKTOP_HAT_SWITCH = 0x39, - HID_USAGE_DESKTOP_COUNTED_BUFFER = 0x3a, - HID_USAGE_DESKTOP_BYTE_COUNT = 0x3b, - HID_USAGE_DESKTOP_MOTION_WAKEUP = 0x3c, - HID_USAGE_DESKTOP_START = 0x3d, - HID_USAGE_DESKTOP_SELECT = 0x3e, - HID_USAGE_DESKTOP_VX = 0x40, - HID_USAGE_DESKTOP_VY = 0x41, - HID_USAGE_DESKTOP_VZ = 0x42, - HID_USAGE_DESKTOP_VBRX = 0x43, - HID_USAGE_DESKTOP_VBRY = 0x44, - HID_USAGE_DESKTOP_VBRZ = 0x45, - HID_USAGE_DESKTOP_VNO = 0x46, - HID_USAGE_DESKTOP_FEATURE_NOTIFICATION = 0x47, - HID_USAGE_DESKTOP_RESOLUTION_MULTIPLIER = 0x48, - HID_USAGE_DESKTOP_SYSTEM_CONTROL = 0x80, - HID_USAGE_DESKTOP_SYSTEM_POWER_DOWN = 0x81, - HID_USAGE_DESKTOP_SYSTEM_SLEEP = 0x82, - HID_USAGE_DESKTOP_SYSTEM_WAKE_UP = 0x83, - HID_USAGE_DESKTOP_SYSTEM_CONTEXT_MENU = 0x84, - HID_USAGE_DESKTOP_SYSTEM_MAIN_MENU = 0x85, - HID_USAGE_DESKTOP_SYSTEM_APP_MENU = 0x86, - HID_USAGE_DESKTOP_SYSTEM_MENU_HELP = 0x87, - HID_USAGE_DESKTOP_SYSTEM_MENU_EXIT = 0x88, - HID_USAGE_DESKTOP_SYSTEM_MENU_SELECT = 0x89, - HID_USAGE_DESKTOP_SYSTEM_MENU_RIGHT = 0x8A, - HID_USAGE_DESKTOP_SYSTEM_MENU_LEFT = 0x8B, - HID_USAGE_DESKTOP_SYSTEM_MENU_UP = 0x8C, - HID_USAGE_DESKTOP_SYSTEM_MENU_DOWN = 0x8D, - HID_USAGE_DESKTOP_SYSTEM_COLD_RESTART = 0x8E, - HID_USAGE_DESKTOP_SYSTEM_WARM_RESTART = 0x8F, - HID_USAGE_DESKTOP_DPAD_UP = 0x90, - HID_USAGE_DESKTOP_DPAD_DOWN = 0x91, - HID_USAGE_DESKTOP_DPAD_RIGHT = 0x92, - HID_USAGE_DESKTOP_DPAD_LEFT = 0x93, - HID_USAGE_DESKTOP_SYSTEM_DOCK = 0xA0, - HID_USAGE_DESKTOP_SYSTEM_UNDOCK = 0xA1, - HID_USAGE_DESKTOP_SYSTEM_SETUP = 0xA2, - HID_USAGE_DESKTOP_SYSTEM_BREAK = 0xA3, - HID_USAGE_DESKTOP_SYSTEM_DEBUGGER_BREAK = 0xA4, - HID_USAGE_DESKTOP_APPLICATION_BREAK = 0xA5, - HID_USAGE_DESKTOP_APPLICATION_DEBUGGER_BREAK = 0xA6, - HID_USAGE_DESKTOP_SYSTEM_SPEAKER_MUTE = 0xA7, - HID_USAGE_DESKTOP_SYSTEM_HIBERNATE = 0xA8, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_INVERT = 0xB0, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_INTERNAL = 0xB1, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_EXTERNAL = 0xB2, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_BOTH = 0xB3, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_DUAL = 0xB4, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_TOGGLE_INT_EXT = 0xB5, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_SWAP_PRIMARY_SECONDARY = 0xB6, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_LCD_AUTOSCALE = 0xB7 + HID_USAGE_DESKTOP_POINTER = 0x01, // CP + HID_USAGE_DESKTOP_MOUSE = 0x02, // CA + // 03 Reserved + + HID_USAGE_DESKTOP_JOYSTICK = 0x04, // CA + HID_USAGE_DESKTOP_GAMEPAD = 0x05, // CA + HID_USAGE_DESKTOP_KEYBOARD = 0x06, // CA + HID_USAGE_DESKTOP_KEYPAD = 0x07, // CA + HID_USAGE_DESKTOP_MULTI_AXIS_CONTROLLER = 0x08, // CA + HID_USAGE_DESKTOP_TABLET_PC_SYSTEM = 0x09, // CA + HID_USAGE_DESKTOP_WATER_COOLING = 0x0A, // CA + HID_USAGE_DESKTOP_COMPUTER_CHASSIS = 0x0B, // CA + HID_USAGE_DESKTOP_WIRELESS_RADIO = 0x0C, // CA + HID_USAGE_DESKTOP_PORTABLE_DEVICE = 0x0D, // CA + HID_USAGE_DESKTOP_SYSTEM_MULTI_AXIS_CONTROLLER = 0x0E, // CA + HID_USAGE_DESKTOP_SPATIAL_CONTROLLER = 0x0F, // CA + HID_USAGE_DESKTOP_ASSISTIVE = 0x10, // CA + HID_USAGE_DESKTOP_DEVICE_DOCK = 0x11, // CA + HID_USAGE_DESKTOP_DOCKABLE_DEVICE = 0x12, // CA + HID_USAGE_DESKTOP_CALL_STATE_MANAGEMENT = 0x13, // CA + // 14-2F Reserved + + HID_USAGE_DESKTOP_X = 0x30, // DV + HID_USAGE_DESKTOP_Y = 0x31, // DV + HID_USAGE_DESKTOP_Z = 0x32, // DV + HID_USAGE_DESKTOP_RX = 0x33, // DV + HID_USAGE_DESKTOP_RY = 0x34, // DV + HID_USAGE_DESKTOP_RZ = 0x35, // DV + HID_USAGE_DESKTOP_SLIDER = 0x36, // DV + HID_USAGE_DESKTOP_DIAL = 0x37, // DV + HID_USAGE_DESKTOP_WHEEL = 0x38, // DV + HID_USAGE_DESKTOP_HAT_SWITCH = 0x39, // DV + HID_USAGE_DESKTOP_COUNTED_BUFFER = 0x3A, // CL + HID_USAGE_DESKTOP_BYTE_COUNT = 0x3B, // DV + HID_USAGE_DESKTOP_MOTION_WAKEUP = 0x3C, // OSC/DF + HID_USAGE_DESKTOP_START = 0x3D, // OOC + HID_USAGE_DESKTOP_SELECT = 0x3E, // OOC + // 3F Reserved + + HID_USAGE_DESKTOP_VX = 0x40, // DV + HID_USAGE_DESKTOP_VY = 0x41, // DV + HID_USAGE_DESKTOP_VZ = 0x42, // DV + HID_USAGE_DESKTOP_VBRX = 0x43, // DV + HID_USAGE_DESKTOP_VBRY = 0x44, // DV + HID_USAGE_DESKTOP_VBRZ = 0x45, // DV + HID_USAGE_DESKTOP_VNO = 0x46, // DV + HID_USAGE_DESKTOP_FEATURE_NOTIFICATION = 0x47, // DV/DF + HID_USAGE_DESKTOP_RESOLUTION_MULTIPLIER = 0x48, // DV + HID_USAGE_DESKTOP_QX = 0x49, // DV + HID_USAGE_DESKTOP_QY = 0x4A, // DV + HID_USAGE_DESKTOP_QZ = 0x4B, // DV + HID_USAGE_DESKTOP_QW = 0x4C, // DV + // 4D-7F Reserved + + HID_USAGE_DESKTOP_SYSTEM_CONTROL = 0x80, // CA + HID_USAGE_DESKTOP_SYSTEM_POWER_DOWN = 0x81, // OSC + HID_USAGE_DESKTOP_SYSTEM_SLEEP = 0x82, // OSC + HID_USAGE_DESKTOP_SYSTEM_WAKE_UP = 0x83, // OSC + HID_USAGE_DESKTOP_SYSTEM_CONTEXT_MENU = 0x84, // OSC + HID_USAGE_DESKTOP_SYSTEM_MAIN_MENU = 0x85, // OSC + HID_USAGE_DESKTOP_SYSTEM_APP_MENU = 0x86, // OSC + HID_USAGE_DESKTOP_SYSTEM_MENU_HELP = 0x87, // OSC + HID_USAGE_DESKTOP_SYSTEM_MENU_EXIT = 0x88, // OSC + HID_USAGE_DESKTOP_SYSTEM_MENU_SELECT = 0x89, // OSC + HID_USAGE_DESKTOP_SYSTEM_MENU_RIGHT = 0x8A, // RTC + HID_USAGE_DESKTOP_SYSTEM_MENU_LEFT = 0x8B, // RTC + HID_USAGE_DESKTOP_SYSTEM_MENU_UP = 0x8C, // RTC + HID_USAGE_DESKTOP_SYSTEM_MENU_DOWN = 0x8D, // RTC + HID_USAGE_DESKTOP_SYSTEM_COLD_RESTART = 0x8E, // OSC + HID_USAGE_DESKTOP_SYSTEM_WARM_RESTART = 0x8F, // OSC + HID_USAGE_DESKTOP_DPAD_UP = 0x90, // OOC + HID_USAGE_DESKTOP_DPAD_DOWN = 0x91, // OOC + HID_USAGE_DESKTOP_DPAD_RIGHT = 0x92, // OOC + HID_USAGE_DESKTOP_DPAD_LEFT = 0x93, // OOC + HID_USAGE_DESKTOP_INDEX_TRIGGER = 0x94, // MC/DV + HID_USAGE_DESKTOP_PALM_TRIGGER = 0x95, // MC/DV + HID_USAGE_DESKTOP_THUMBSTICK = 0x96, // CP + HID_USAGE_DESKTOP_SYSTEM_FUNCTION_SHIFT = 0x97, // MC + HID_USAGE_DESKTOP_SYSTEM_FUNCTION_SHIFT_LOCK = 0x98, // OOC + HID_USAGE_DESKTOP_SYSTEM_FUNCTION_SHIFT_LOCK_INDICATOR = 0x99, // DV + HID_USAGE_DESKTOP_SYSTEM_DISMISS_NOTIFICATION = 0x9A, // OSC + HID_USAGE_DESKTOP_SYSTEM_DO_NOT_DISTURB = 0x9B, // OOC + // 9C-9F Reserved + + HID_USAGE_DESKTOP_SYSTEM_DOCK = 0xA0, // OSC + HID_USAGE_DESKTOP_SYSTEM_UNDOCK = 0xA1, // OSC + HID_USAGE_DESKTOP_SYSTEM_SETUP = 0xA2, // OSC + HID_USAGE_DESKTOP_SYSTEM_BREAK = 0xA3, // OSC + HID_USAGE_DESKTOP_SYSTEM_DEBUGGER_BREAK = 0xA4, // OSC + HID_USAGE_DESKTOP_APPLICATION_BREAK = 0xA5, // OSC + HID_USAGE_DESKTOP_APPLICATION_DEBUGGER_BREAK = 0xA6, // OSC + HID_USAGE_DESKTOP_SYSTEM_SPEAKER_MUTE = 0xA7, // OSC + HID_USAGE_DESKTOP_SYSTEM_HIBERNATE = 0xA8, // OSC + HID_USAGE_DESKTOP_SYSTEM_MICROPHONE_MUTE = 0xA9, // OOC + HID_USAGE_DESKTOP_SYSTEM_ACCESSIBILITY_BINDING = 0xAA, // OOC + // AB-AF Reserved + + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_INVERT = 0xB0, // OSC + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_INTERNAL = 0xB1, // OSC + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_EXTERNAL = 0xB2, // OSC + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_BOTH = 0xB3, // OSC + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_DUAL = 0xB4, // OSC + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_TOGGLE_INT_EXT = 0xB5, // OSC + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_SWAP_PRIMARY_SECONDARY = 0xB6, // OSC + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_LCD_AUTOSCALE = 0xB7, // OSC + // B8-BF Reserved + + HID_USAGE_DESKTOP_SENSOR_ZONE = 0xC0, // CL + HID_USAGE_DESKTOP_RPM = 0xC1, // DV + HID_USAGE_DESKTOP_COOLANT_LEVEL = 0xC2, // DV + HID_USAGE_DESKTOP_COOLANT_CRITICAL_LEVEL = 0xC3, // SV + HID_USAGE_DESKTOP_COOLANT_PUMP = 0xC4, // US + HID_USAGE_DESKTOP_CHASSIS_ENCLOSURE = 0xC5, // CL + HID_USAGE_DESKTOP_WIRELESS_RADIO_BUTTON = 0xC6, // OOC + HID_USAGE_DESKTOP_WIRELESS_RADIO_LED = 0xC7, // OOC + HID_USAGE_DESKTOP_WIRELESS_RADIO_SLIDER_SWITCH = 0xC8, // OOC + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_ROTATION_LOCK_BUTTON = 0xC9, // OOC + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_ROTATION_LOCK_SLIDER_SWITCH = 0xCA, // OOC + HID_USAGE_DESKTOP_CONTROL_ENABLE = 0xCB, // DF + // CC-CF Reserved + + HID_USAGE_DESKTOP_DOCKABLE_DEVICE_UNIQUE_ID = 0xD0, // DV + HID_USAGE_DESKTOP_DOCKABLE_DEVICE_VENDOR_ID = 0xD1, // DV + HID_USAGE_DESKTOP_DOCKABLE_DEVICE_PRIMARY_USAGE_PAGE = 0xD2, // DV + HID_USAGE_DESKTOP_DOCKABLE_DEVICE_PRIMARY_USAGE_ID = 0xD3, // DV + HID_USAGE_DESKTOP_DOCKABLE_DEVICE_DOCKING_STATE = 0xD4, // DF + HID_USAGE_DESKTOP_DOCKABLE_DEVICE_DISPLAY_OCCLUSION = 0xD5, // CL + HID_USAGE_DESKTOP_DOCKABLE_DEVICE_OBJECT_TYPE = 0xD6, // DV + // D7-DF Reserved + + HID_USAGE_DESKTOP_CALL_ACTIVE_LED = 0xE0, // OOC + HID_USAGE_DESKTOP_CALL_MUTE_TOGGLE = 0xE1, // OSC + HID_USAGE_DESKTOP_CALL_MUTE_LED = 0xE2 // OOC + // E3-FFFF Reserved +}; + +/// HID Usage Table: Simulation Controls Page (0x02) +enum { + HID_USAGE_SIMULATION_CONTROLS_FLIGHT_SIMULATION_DEVICE = 0x01, // CA + HID_USAGE_SIMULATION_CONTROLS_AUTOMOBILE_SIMULATION_DEVICE = 0x02, // CA + HID_USAGE_SIMULATION_CONTROLS_TANK_SIMULATION_DEVICE = 0x03, // CA + HID_USAGE_SIMULATION_CONTROLS_SPACESHIP_SIMULATION_DEVICE = 0x04, // CA + HID_USAGE_SIMULATION_CONTROLS_SUBMARINE_SIMULATION_DEVICE = 0x05, // CA + HID_USAGE_SIMULATION_CONTROLS_SAILING_SIMULATION_DEVICE = 0x06, // CA + HID_USAGE_SIMULATION_CONTROLS_MOTORCYCLE_SIMULATION_DEVICE = 0x07, // CA + HID_USAGE_SIMULATION_CONTROLS_SPORTS_SIMULATION_DEVICE = 0x08, // CA + HID_USAGE_SIMULATION_CONTROLS_AIRPLANE_SIMULATION_DEVICE = 0x09, // CA + HID_USAGE_SIMULATION_CONTROLS_HELICOPTER_SIMULATION_DEVICE = 0x0A, // CA + HID_USAGE_SIMULATION_CONTROLS_MAGIC_CARPET_SIMULATION_DEVICE = 0x0B, // CA + HID_USAGE_SIMULATION_CONTROLS_BICYCLE_SIMULATION_DEVICE = 0x0C, // CA + // 0D-1F Reserved + + HID_USAGE_SIMULATION_CONTROLS_FLIGHT_CONTROL_STICK = 0x20, // CA + HID_USAGE_SIMULATION_CONTROLS_FLIGHT_STICK = 0x21, // CA + HID_USAGE_SIMULATION_CONTROLS_CYCLIC_CONTROL = 0x22, // CP + HID_USAGE_SIMULATION_CONTROLS_CYCLIC_TRIM = 0x23, // CP + HID_USAGE_SIMULATION_CONTROLS_FLIGHT_YOKE = 0x24, // CA + HID_USAGE_SIMULATION_CONTROLS_TRACK_CONTROL = 0x25, // CP + // 26-AF Reserved + + HID_USAGE_SIMULATION_CONTROLS_AILERON = 0xB0, // DV + HID_USAGE_SIMULATION_CONTROLS_AILERON_TRIM = 0xB1, // DV + HID_USAGE_SIMULATION_CONTROLS_ANTI_TORQUE_CONTROL = 0xB2, // DV + HID_USAGE_SIMULATION_CONTROLS_AUTOPILOT_ENABLE = 0xB3, // OOC + HID_USAGE_SIMULATION_CONTROLS_CHAFF_RELEASE = 0xB4, // OSC + HID_USAGE_SIMULATION_CONTROLS_COLLECTIVE_CONTROL = 0xB5, // DV + HID_USAGE_SIMULATION_CONTROLS_DIVE_BRAKE = 0xB6, // DV + HID_USAGE_SIMULATION_CONTROLS_ELECTRONIC_COUNTERMEASURES = 0xB7, // OOC + HID_USAGE_SIMULATION_CONTROLS_ELEVATOR = 0xB8, // DV + HID_USAGE_SIMULATION_CONTROLS_ELEVATOR_TRIM = 0xB9, // DV + HID_USAGE_SIMULATION_CONTROLS_RUDDER = 0xBA, // DV + HID_USAGE_SIMULATION_CONTROLS_THROTTLE = 0xBB, // DV + HID_USAGE_SIMULATION_CONTROLS_FLIGHT_COMMUNICATIONS = 0xBC, // OOC + HID_USAGE_SIMULATION_CONTROLS_FLARE_RELEASE = 0xBD, // OSC + HID_USAGE_SIMULATION_CONTROLS_LANDING_GEAR = 0xBE, // OOC + HID_USAGE_SIMULATION_CONTROLS_TOE_BRAKE = 0xBF, // DV + HID_USAGE_SIMULATION_CONTROLS_TRIGGER = 0xC0, // MC + HID_USAGE_SIMULATION_CONTROLS_WEAPONS_ARM = 0xC1, // OOC + HID_USAGE_SIMULATION_CONTROLS_WEAPONS_SELECT = 0xC2, // OSC + HID_USAGE_SIMULATION_CONTROLS_WING_FLAPS = 0xC3, // DV + HID_USAGE_SIMULATION_CONTROLS_ACCELERATOR = 0xC4, // DV + HID_USAGE_SIMULATION_CONTROLS_BRAKE = 0xC5, // DV + HID_USAGE_SIMULATION_CONTROLS_CLUTCH = 0xC6, // DV + HID_USAGE_SIMULATION_CONTROLS_SHIFTER = 0xC7, // DV + HID_USAGE_SIMULATION_CONTROLS_STEERING = 0xC8, // DV + HID_USAGE_SIMULATION_CONTROLS_TURRET_DIRECTION = 0xC9, // DV + HID_USAGE_SIMULATION_CONTROLS_BARREL_ELEVATION = 0xCA, // DV + HID_USAGE_SIMULATION_CONTROLS_DIVE_PLANE = 0xCB, // DV + HID_USAGE_SIMULATION_CONTROLS_BALLAST = 0xCC, // DV + HID_USAGE_SIMULATION_CONTROLS_BICYCLE_CRANK = 0xCD, // DV + HID_USAGE_SIMULATION_CONTROLS_HANDLE_BARS = 0xCE, // DV + HID_USAGE_SIMULATION_CONTROLS_FRONT_BRAKE = 0xCF, // DV + HID_USAGE_SIMULATION_CONTROLS_REAR_BRAKE = 0xD0, // DV + // D1-FFFF Reserved +}; + +/// HID Usage Table: VR Controls Page (0x03) +enum { + HID_USAGE_VR_CONTROLS_BELT = 0x01, // CA + HID_USAGE_VR_CONTROLS_BODY_SUIT = 0x02, // CA + HID_USAGE_VR_CONTROLS_FLEXOR = 0x03, // CP + HID_USAGE_VR_CONTROLS_GLOVE = 0x04, // CA + HID_USAGE_VR_CONTROLS_HEAD_TRACKER = 0x05, // CP + HID_USAGE_VR_CONTROLS_HEAD_MOUNTED_DISPLAY = 0x06, // CA + HID_USAGE_VR_CONTROLS_HAND_TRACKER = 0x07, // CA + HID_USAGE_VR_CONTROLS_OCULOMETER = 0x08, // CA + HID_USAGE_VR_CONTROLS_VEST = 0x09, // CA + HID_USAGE_VR_CONTROLS_ANIMATRONIC_DEVICE = 0x0A, // CA + // 0B-1F Reserved + + HID_USAGE_VR_CONTROLS_STEREO_ENABLE = 0x20, // OOC + HID_USAGE_VR_CONTROLS_DISPLAY_ENABLE = 0x21 // OOC + // 22-FFFF Reserved +}; + +/// HID Usage Table: Sports Controls Page (0x04) +enum { + HID_USAGE_SPORTS_CONTROLS_BASEBALL_BAT = 0x01, // CA + HID_USAGE_SPORTS_CONTROLS_GOLF_CLUB = 0x02, // CA + HID_USAGE_SPORTS_CONTROLS_ROWING_MACHINE = 0x03, // CA + HID_USAGE_SPORTS_CONTROLS_TREADMILL = 0x04, // CA + // 05-2F Reserved + + HID_USAGE_SPORTS_CONTROLS_OAR = 0x30, // DV + HID_USAGE_SPORTS_CONTROLS_SLOPE = 0x31, // DV + HID_USAGE_SPORTS_CONTROLS_RATE = 0x32, // DV + HID_USAGE_SPORTS_CONTROLS_STICK_SPEED = 0x33, // DV + HID_USAGE_SPORTS_CONTROLS_STICK_FACE_ANGLE = 0x34, // DV + HID_USAGE_SPORTS_CONTROLS_STICK_HEEL_TOE = 0x35, // DV + HID_USAGE_SPORTS_CONTROLS_STICK_FOLLOW_THROUGH = 0x36, // DV + HID_USAGE_SPORTS_CONTROLS_STICK_TEMPO = 0x37, // DV + HID_USAGE_SPORTS_CONTROLS_STICK_TYPE = 0x38, // NAry + HID_USAGE_SPORTS_CONTROLS_STICK_HEIGHT = 0x39, // DV + // 3A-4F Reserved + + HID_USAGE_SPORTS_CONTROLS_PUTTER = 0x50, // Sel + HID_USAGE_SPORTS_CONTROLS_1_IRON = 0x51, // Sel + HID_USAGE_SPORTS_CONTROLS_2_IRON = 0x52, // Sel + HID_USAGE_SPORTS_CONTROLS_3_IRON = 0x53, // Sel + HID_USAGE_SPORTS_CONTROLS_4_IRON = 0x54, // Sel + HID_USAGE_SPORTS_CONTROLS_5_IRON = 0x55, // Sel + HID_USAGE_SPORTS_CONTROLS_6_IRON = 0x56, // Sel + HID_USAGE_SPORTS_CONTROLS_7_IRON = 0x57, // Sel + HID_USAGE_SPORTS_CONTROLS_8_IRON = 0x58, // Sel + HID_USAGE_SPORTS_CONTROLS_9_IRON = 0x59, // Sel + HID_USAGE_SPORTS_CONTROLS_10_IRON = 0x5A, // Sel + HID_USAGE_SPORTS_CONTROLS_11_IRON = 0x5B, // Sel + HID_USAGE_SPORTS_CONTROLS_SAND_WEDGE = 0x5C, // Sel + HID_USAGE_SPORTS_CONTROLS_LOFT_WEDGE = 0x5D, // Sel + HID_USAGE_SPORTS_CONTROLS_POWER_WEDGE = 0x5E, // Sel + HID_USAGE_SPORTS_CONTROLS_1_WOOD = 0x5F, // Sel + HID_USAGE_SPORTS_CONTROLS_3_WOOD = 0x60, // Sel + HID_USAGE_SPORTS_CONTROLS_5_WOOD = 0x61, // Sel + HID_USAGE_SPORTS_CONTROLS_7_WOOD = 0x62, // Sel + HID_USAGE_SPORTS_CONTROLS_9_WOOD = 0x63, // Sel + // 64-FFFF Reserved +}; + +/// HID Usage Table: Game Controls Page (0x05) +enum { + HID_USAGE_GAME_CONTROLS_3D_GAME_CONTROLLER = 0x01, // CA + HID_USAGE_GAME_CONTROLS_PINBALL_DEVICE = 0x02, // CA + HID_USAGE_GAME_CONTROLS_GUN_DEVICE = 0x03, // CA + // 04-1F Reserved + + HID_USAGE_GAME_CONTROLS_POINT_OF_VIEW = 0x20, // CP + HID_USAGE_GAME_CONTROLS_TURN_RIGHT_LEFT = 0x21, // DV + HID_USAGE_GAME_CONTROLS_PITCH_FORWARD_BACKWARD = 0x22, // DV + HID_USAGE_GAME_CONTROLS_ROLL_RIGHT_LEFT = 0x23, // DV + HID_USAGE_GAME_CONTROLS_MOVE_RIGHT_LEFT = 0x24, // DV + HID_USAGE_GAME_CONTROLS_MOVE_FORWARD_BACKWARD = 0x25, // DV + HID_USAGE_GAME_CONTROLS_MOVE_UP_DOWN = 0x26, // DV + HID_USAGE_GAME_CONTROLS_LEAN_RIGHT_LEFT = 0x27, // DV + HID_USAGE_GAME_CONTROLS_LEAN_FORWARD_BACKWARD = 0x28, // DV + HID_USAGE_GAME_CONTROLS_HEIGHT_OF_POV = 0x29, // DV + HID_USAGE_GAME_CONTROLS_FLIPPER = 0x2A, // MC + HID_USAGE_GAME_CONTROLS_SECONDARY_FLIPPER = 0x2B, // MC + HID_USAGE_GAME_CONTROLS_BUMP = 0x2C, // MC + HID_USAGE_GAME_CONTROLS_NEW_GAME = 0x2D, // OSC + HID_USAGE_GAME_CONTROLS_SHOOT_BALL = 0x2E, // OSC + HID_USAGE_GAME_CONTROLS_PLAYER = 0x2F, // OSC + HID_USAGE_GAME_CONTROLS_GUN_BOLT = 0x30, // OOC + HID_USAGE_GAME_CONTROLS_GUN_CLIP = 0x31, // OOC + HID_USAGE_GAME_CONTROLS_GUN_SELECTOR = 0x32, // NAry + HID_USAGE_GAME_CONTROLS_GUN_SINGLE_SHOT = 0x33, // Sel + HID_USAGE_GAME_CONTROLS_GUN_BURST = 0x34, // Sel + HID_USAGE_GAME_CONTROLS_GUN_AUTOMATIC = 0x35, // Sel + HID_USAGE_GAME_CONTROLS_GUN_SAFETY = 0x36, // OOC + HID_USAGE_GAME_CONTROLS_GAMEPAD_FIRE_JUMP = 0x37, // CL + // 38 Reserved + + HID_USAGE_GAME_CONTROLS_GAMEPAD_TRIGGER = 0x39, // CL + HID_USAGE_GAME_CONTROLS_FORM_FITTING_GAMEPAD = 0x3A // SF + // 3B-FFFF Reserved +}; + +/// HID Usage Table: Generic Device Controls Page (0x06) +enum { + HID_USAGE_GENERIC_DEVICE_CONTROLS_BACKGROUND_NONUSER_CONTROLS = 0x01, // CA + // 02-1F Reserved + + HID_USAGE_GENERIC_DEVICE_CONTROLS_BATTERY_STRENGTH = 0x20, // DV + HID_USAGE_GENERIC_DEVICE_CONTROLS_WIRELESS_CHANNEL = 0x21, // DV + HID_USAGE_GENERIC_DEVICE_CONTROLS_WIRELESS_ID = 0x22, // DV + HID_USAGE_GENERIC_DEVICE_CONTROLS_DISCOVER_WIRELESS_CONTROL = 0x23, // OSC + HID_USAGE_GENERIC_DEVICE_CONTROLS_SECURITY_CODE_CHARACTER_ENTERED = 0x24, // OSC + HID_USAGE_GENERIC_DEVICE_CONTROLS_SECURITY_CODE_CHARACTER_ERASED = 0x25, // OSC + HID_USAGE_GENERIC_DEVICE_CONTROLS_SECURITY_CODE_CLEARED = 0x26, // OSC + HID_USAGE_GENERIC_DEVICE_CONTROLS_SEQUENCE_ID = 0x27, // DV + HID_USAGE_GENERIC_DEVICE_CONTROLS_SEQUENCE_ID_RESET = 0x28, // DF + HID_USAGE_GENERIC_DEVICE_CONTROLS_RF_SIGNAL_STRENGTH = 0x29, // DV + HID_USAGE_GENERIC_DEVICE_CONTROLS_SOFTWARE_VERSION = 0x2A, // CL + HID_USAGE_GENERIC_DEVICE_CONTROLS_PROTOCOL_VERSION = 0x2B, // CL + HID_USAGE_GENERIC_DEVICE_CONTROLS_HARDWARE_VERSION = 0x2C, // CL + HID_USAGE_GENERIC_DEVICE_CONTROLS_MAJOR = 0x2D, // SV + HID_USAGE_GENERIC_DEVICE_CONTROLS_MINOR = 0x2E, // SV + HID_USAGE_GENERIC_DEVICE_CONTROLS_REVISION = 0x2F, // SV + HID_USAGE_GENERIC_DEVICE_CONTROLS_HANDEDNESS = 0x30, // NAry + HID_USAGE_GENERIC_DEVICE_CONTROLS_EITHER_HAND = 0x31, // Sel + HID_USAGE_GENERIC_DEVICE_CONTROLS_LEFT_HAND = 0x32, // Sel + HID_USAGE_GENERIC_DEVICE_CONTROLS_RIGHT_HAND = 0x33, // Sel + HID_USAGE_GENERIC_DEVICE_CONTROLS_BOTH_HANDS = 0x34, // Sel + // 35-3F Reserved + + HID_USAGE_GENERIC_DEVICE_CONTROLS_GRIP_POSE_OFFSET = 0x40, // CP + HID_USAGE_GENERIC_DEVICE_CONTROLS_POINTER_POSE_OFFSET = 0x41 // CP + // 42-FFFF Reserved +}; + +/// HID Usage Table: Keyboard/Keypad Page (0x07) +/// Defined above + +/// HID Usage Table: LED Page (0x08) +enum { + HID_USAGE_LED_NUM_LOCK = 0x01, // OOC + HID_USAGE_LED_CAPS_LOCK = 0x02, // OOC + HID_USAGE_LED_SCROLL_LOCK = 0x03, // OOC + HID_USAGE_LED_COMPOSE = 0x04, // OOC + HID_USAGE_LED_KANA = 0x05, // OOC + HID_USAGE_LED_POWER = 0x06, // OOC + HID_USAGE_LED_SHIFT = 0x07, // OOC + HID_USAGE_LED_DO_NOT_SHIFT = 0x08, // OOC + HID_USAGE_LED_MUTE = 0x09, // OOC + HID_USAGE_LED_TONE_ENABLE = 0x0A, // OOC + HID_USAGE_LED_HIGH_CUT_FILTER = 0x0B, // OOC + HID_USAGE_LED_LOW_CUT_FILTER = 0x0C, // OOC + HID_USAGE_LED_EQUALIZER_ENABLE = 0x0D, // OOC + HID_USAGE_LED_SOUND_FIELD_ON = 0x0E, // OOC + HID_USAGE_LED_SURROUND_ON = 0x0F, // OOC + HID_USAGE_LED_REPEAT = 0x10, // OOC + HID_USAGE_LED_STEREO = 0x11, // OOC + HID_USAGE_LED_SAMPLING_RATE_DETECT = 0x12, // OOC + HID_USAGE_LED_SPINNING = 0x13, // OOC + HID_USAGE_LED_CAV = 0x14, // OOC + HID_USAGE_LED_CLV = 0x15, // OOC + HID_USAGE_LED_RECORDING_FORMAT_DETECT = 0x16, // OOC + HID_USAGE_LED_OFF_HOOK = 0x17, // OOC + HID_USAGE_LED_RING = 0x18, // OOC + HID_USAGE_LED_MESSAGE_WAITING = 0x19, // OOC + HID_USAGE_LED_DATA_MODE = 0x1A, // OOC + HID_USAGE_LED_BATTERY_OPERATION = 0x1B, // OOC + HID_USAGE_LED_BATTERY_OK = 0x1C, // OOC + HID_USAGE_LED_BATTERY_LOW = 0x1D, // OOC + HID_USAGE_LED_SPEAKER = 0x1E, // OOC + HID_USAGE_LED_HEADSET = 0x1F, // OOC + HID_USAGE_LED_HOLD = 0x20, // OOC + HID_USAGE_LED_MICROPHONE = 0x21, // OOC + HID_USAGE_LED_COVERAGE = 0x22, // OOC + HID_USAGE_LED_NIGHT_MODE = 0x23, // OOC + HID_USAGE_LED_SEND_CALLS = 0x24, // OOC + HID_USAGE_LED_CALL_PICKUPS = 0x25, // OOC + HID_USAGE_LED_CONFERENCE = 0x26, // OOC + HID_USAGE_LED_STANDBY = 0x27, // OOC + HID_USAGE_LED_CAMERA_ON = 0x28, // OOC + HID_USAGE_LED_CAMERA_OFF = 0x29, // OOC + HID_USAGE_LED_ON_LINE = 0x2A, // OOC + HID_USAGE_LED_OFF_LINE = 0x2B, // OOC + HID_USAGE_LED_BUSY = 0x2C, // OOC + HID_USAGE_LED_READY = 0x2D, // OOC + HID_USAGE_LED_PAPER_OUT = 0x2E, // OOC + HID_USAGE_LED_PAPER_JAM = 0x2F, // OOC + HID_USAGE_LED_REMOTE = 0x30, // OOC + HID_USAGE_LED_FORWARD = 0x31, // OOC + HID_USAGE_LED_REVERSE = 0x32, // OOC + HID_USAGE_LED_STOP = 0x33, // OOC + HID_USAGE_LED_REWIND = 0x34, // OOC + HID_USAGE_LED_FAST_FORWARD = 0x35, // OOC + HID_USAGE_LED_PLAY = 0x36, // OOC + HID_USAGE_LED_PAUSE = 0x37, // OOC + HID_USAGE_LED_RECORD = 0x38, // OOC + HID_USAGE_LED_ERROR = 0x39, // OOC + HID_USAGE_LED_USAGE_SELECTED_INDICATOR = 0x3A, // US + HID_USAGE_LED_USAGE_IN_USE_INDICATOR = 0x3B, // US + HID_USAGE_LED_USAGE_MULTI_MODE_INDICATOR = 0x3C, // UM + HID_USAGE_LED_INDICATOR_ON = 0x3D, // Sel + HID_USAGE_LED_INDICATOR_FLASH = 0x3E, // Sel + HID_USAGE_LED_INDICATOR_SLOW_BLINK = 0x3F, // Sel + HID_USAGE_LED_INDICATOR_FAST_BLINK = 0x40, // Sel + HID_USAGE_LED_INDICATOR_OFF = 0x41, // Sel + HID_USAGE_LED_FLASH_ON_TIME = 0x42, // DV + HID_USAGE_LED_SLOW_BLINK_ON_TIME = 0x43, // DV + HID_USAGE_LED_SLOW_BLINK_OFF_TIME = 0x44, // DV + HID_USAGE_LED_FAST_BLINK_ON_TIME = 0x45, // DV + HID_USAGE_LED_FAST_BLINK_OFF_TIME = 0x46, // DV + HID_USAGE_LED_USAGE_INDICATOR_COLOR = 0x47, // UM + HID_USAGE_LED_INDICATOR_RED = 0x48, // Sel + HID_USAGE_LED_INDICATOR_GREEN = 0x49, // Sel + HID_USAGE_LED_INDICATOR_AMBER = 0x4A, // Sel + HID_USAGE_LED_GENERIC_INDICATOR = 0x4B, // OOC + HID_USAGE_LED_SYSTEM_SUSPEND = 0x4C, // OOC + HID_USAGE_LED_EXTERNAL_POWER_CONNECTED = 0x4D, // OOC + HID_USAGE_LED_INDICATOR_BLUE = 0x4E, // Sel + HID_USAGE_LED_INDICATOR_ORANGE = 0x4F, // Sel + HID_USAGE_LED_GOOD_STATUS = 0x50, // OOC + HID_USAGE_LED_WARNING_STATUS = 0x51, // OOC + HID_USAGE_LED_RGB_LED = 0x52, // CL + HID_USAGE_LED_RED_LED_CHANNEL = 0x53, // DV + HID_USAGE_LED_BLUE_LED_CHANNEL = 0x54, // DV + HID_USAGE_LED_GREEN_LED_CHANNEL = 0x55, // DV + HID_USAGE_LED_LED_INTENSITY = 0x56, // DV + HID_USAGE_LED_SYSTEM_MICROPHONE_MUTE = 0x57, // OOC + // 58-5F Reserved + + HID_USAGE_LED_PLAYER_INDICATOR = 0x60, // NAry + HID_USAGE_LED_PLAYER_1 = 0x61, // Sel + HID_USAGE_LED_PLAYER_2 = 0x62, // Sel + HID_USAGE_LED_PLAYER_3 = 0x63, // Sel + HID_USAGE_LED_PLAYER_4 = 0x64, // Sel + HID_USAGE_LED_PLAYER_5 = 0x65, // Sel + HID_USAGE_LED_PLAYER_6 = 0x66, // Sel + HID_USAGE_LED_PLAYER_7 = 0x67, // Sel + HID_USAGE_LED_PLAYER_8 = 0x68, // Sel + // 69-FFFF Reserved +}; + +/// HID Usage Table: Button Page (0x09) +/// Intentionally skipped + +/// HID Usage Table: Ordinal Page (0x0A) +/// Intentionally skipped + +/// HID Usage Table: Telephony Device Page (0x0B) +enum { + HID_USAGE_TELEPHONY_PHONE = 0x0001, // CA + HID_USAGE_TELEPHONY_ANSWERING_MACHINE = 0x0002, // CA + HID_USAGE_TELEPHONY_MESSAGE_CONTROLS = 0x0003, // CL + HID_USAGE_TELEPHONY_HANDSET = 0x0004, // CL + HID_USAGE_TELEPHONY_HEADSET = 0x0005, // CL/CA + HID_USAGE_TELEPHONY_TELEPHONY_KEY_PAD = 0x0006, // NAry + HID_USAGE_TELEPHONY_PROGRAMMABLE_BUTTON = 0x0007, // NAry + // 08-1F Reserved + + HID_USAGE_TELEPHONY_HOOK_SWITCH = 0x0020, // OOC + HID_USAGE_TELEPHONY_FLASH = 0x0021, // MC + HID_USAGE_TELEPHONY_FEATURE = 0x0022, // OSC + HID_USAGE_TELEPHONY_HOLD = 0x0023, // OOC + HID_USAGE_TELEPHONY_REDIAL = 0x0024, // OSC + HID_USAGE_TELEPHONY_TRANSFER = 0x0025, // OSC + HID_USAGE_TELEPHONY_DROP = 0x0026, // OSC + HID_USAGE_TELEPHONY_PARK = 0x0027, // OOC + HID_USAGE_TELEPHONY_FORWARD_CALLS = 0x0028, // OOC + HID_USAGE_TELEPHONY_ALTERNATE_FUNCTION = 0x0029, // MC + HID_USAGE_TELEPHONY_LINE = 0x002A, // OSC/NAry + HID_USAGE_TELEPHONY_SPEAKER_PHONE = 0x002B, // OOC + HID_USAGE_TELEPHONY_CONFERENCE = 0x002C, // OOC + HID_USAGE_TELEPHONY_RING_ENABLE = 0x002D, // OOC + HID_USAGE_TELEPHONY_RING_SELECT = 0x002E, // OSC + HID_USAGE_TELEPHONY_PHONE_MUTE = 0x002F, // OOC + HID_USAGE_TELEPHONY_CALLER_ID = 0x0030, // MC + HID_USAGE_TELEPHONY_SEND = 0x0031, // OOC + // 32-4F Reserved + + HID_USAGE_TELEPHONY_SPEED_DIAL = 0x0050, // OSC + HID_USAGE_TELEPHONY_STORE_NUMBER = 0x0051, // OSC + HID_USAGE_TELEPHONY_RECALL_NUMBER = 0x0052, // OSC + HID_USAGE_TELEPHONY_PHONE_DIRECTORY = 0x0053, // OOC + // 54-6F Reserved + + HID_USAGE_TELEPHONY_VOICE_MAIL = 0x0070, // OOC + HID_USAGE_TELEPHONY_SCREEN_CALLS = 0x0071, // OOC + HID_USAGE_TELEPHONY_DO_NOT_DISTURB = 0x0072, // OOC + HID_USAGE_TELEPHONY_MESSAGE = 0x0073, // OSC + HID_USAGE_TELEPHONY_ANSWER_ON_OFF = 0x0074, // OOC + // 75-8F Reserved + + HID_USAGE_TELEPHONY_INSIDE_DIAL_TONE = 0x0090, // MC + HID_USAGE_TELEPHONY_OUTSIDE_DIAL_TONE = 0x0091, // MC + HID_USAGE_TELEPHONY_INSIDE_RING_TONE = 0x0092, // MC + HID_USAGE_TELEPHONY_OUTSIDE_RING_TONE = 0x0093, // MC + HID_USAGE_TELEPHONY_PRIORITY_RING_TONE = 0x0094, // MC + HID_USAGE_TELEPHONY_INSIDE_RINGBACK = 0x0095, // MC + HID_USAGE_TELEPHONY_PRIORITY_RINGBACK = 0x0096, // MC + HID_USAGE_TELEPHONY_LINE_BUSY_TONE = 0x0097, // MC + HID_USAGE_TELEPHONY_REORDER_TONE = 0x0098, // MC + HID_USAGE_TELEPHONY_CALL_WAITING_TONE = 0x0099, // MC + HID_USAGE_TELEPHONY_CONFIRMATION_TONE_1 = 0x009A, // MC + HID_USAGE_TELEPHONY_CONFIRMATION_TONE_2 = 0x009B, // MC + HID_USAGE_TELEPHONY_TONES_OFF = 0x009C, // OOC + HID_USAGE_TELEPHONY_OUTSIDE_RINGBACK = 0x009D, // MC + HID_USAGE_TELEPHONY_RINGER = 0x009E, // OOC + // 9F-AF Reserved + + HID_USAGE_TELEPHONY_PHONE_KEY_0 = 0x00B0, // Sel + HID_USAGE_TELEPHONY_PHONE_KEY_1 = 0x00B1, // Sel + HID_USAGE_TELEPHONY_PHONE_KEY_2 = 0x00B2, // Sel + HID_USAGE_TELEPHONY_PHONE_KEY_3 = 0x00B3, // Sel + HID_USAGE_TELEPHONY_PHONE_KEY_4 = 0x00B4, // Sel + HID_USAGE_TELEPHONY_PHONE_KEY_5 = 0x00B5, // Sel + HID_USAGE_TELEPHONY_PHONE_KEY_6 = 0x00B6, // Sel + HID_USAGE_TELEPHONY_PHONE_KEY_7 = 0x00B7, // Sel + HID_USAGE_TELEPHONY_PHONE_KEY_8 = 0x00B8, // Sel + HID_USAGE_TELEPHONY_PHONE_KEY_9 = 0x00B9, // Sel + HID_USAGE_TELEPHONY_PHONE_KEY_STAR = 0x00BA, // Sel + HID_USAGE_TELEPHONY_PHONE_KEY_POUND = 0x00BB, // Sel + HID_USAGE_TELEPHONY_PHONE_KEY_A = 0x00BC, // Sel + HID_USAGE_TELEPHONY_PHONE_KEY_B = 0x00BD, // Sel + HID_USAGE_TELEPHONY_PHONE_KEY_C = 0x00BE, // Sel + HID_USAGE_TELEPHONY_PHONE_KEY_D = 0x00BF, // Sel + HID_USAGE_TELEPHONY_PHONE_CALL_HISTORY_KEY = 0x00C0, // Sel + HID_USAGE_TELEPHONY_PHONE_CALLER_ID_KEY = 0x00C1, // Sel + HID_USAGE_TELEPHONY_PHONE_SETTINGS_KEY = 0x00C2, // Sel + // C3-EF Reserved + + HID_USAGE_TELEPHONY_HOST_CONTROL = 0x00F0, // OOC + HID_USAGE_TELEPHONY_HOST_AVAILABLE = 0x00F1, // OOC + HID_USAGE_TELEPHONY_HOST_CALL_ACTIVE = 0x00F2, // OOC + HID_USAGE_TELEPHONY_ACTIVATE_HANDSET_AUDIO = 0x00F3, // OOC + HID_USAGE_TELEPHONY_RING_TYPE = 0x00F4, // NAry + HID_USAGE_TELEPHONY_REDIALABLE_PHONE_NUMBER = 0x00F5, // OOC + // F6-F7 Reserved + + HID_USAGE_TELEPHONY_STOP_RING_TONE = 0x00F8, // Sel + HID_USAGE_TELEHONY_PSTN_RING_TONE = 0x00F9, // Sel + HID_USAGE_TELEPHONY_HOST_RING_TONE = 0x00FA, // Sel + HID_USAGE_TELEPHONY_ALERT_SOUND_ERROR = 0x00FB, // Sel + HID_USAGE_TELEPHONY_ALERT_SOUND_CONFIRM = 0x00FC, // Sel + HID_USAGE_TELEPHONY_ALERT_SOUND_NOTIFICATION = 0x00FD, // Sel + HID_USAGE_TELEPHONY_SILENT_RING = 0x00FE, // Sel + // FF-107 Reserved + + HID_USAGE_TELEPHONY_EMAIL_MESSAGE_WAITING = 0x0108, // OOC + HID_USAGE_TELEPHONY_VOICEMAIL_MESSAGE_WAITING = 0x0109, // OOC + HID_USAGE_TELEPHONY_HOST_HOLD = 0x010A, // OOC + // 10B-10F Reserved + + HID_USAGE_TELEPHONY_INCOMING_CALL_HISTORY_COUNT = 0x0110, // DV + HID_USAGE_TELEPHONY_OUTGOING_CALL_HISTORY_COUNT = 0x0111, // DV + HID_USAGE_TELEPHONY_INCOMING_CALL_HISTORY = 0x0112, // CL + HID_USAGE_TELEPHONY_OUTGOING_CALL_HISTORY = 0x0113, // CL + HID_USAGE_TELEPHONY_PHONE_LOCALE = 0x0114, // DV + // 115-13F Reserved + + HID_USAGE_TELEPHONY_PHONE_TIME_SECOND = 0x0140, // DV + HID_USAGE_TELEPHONY_PHONE_TIME_MINUTE = 0x0141, // DV + HID_USAGE_TELEPHONY_PHONE_TIME_HOUR = 0x0142, // DV + HID_USAGE_TELEPHONY_PHONE_DATE_DAY = 0x0143, // DV + HID_USAGE_TELEPHONY_PHONE_DATE_MONTH = 0x0144, // DV + HID_USAGE_TELEPHONY_PHONE_DATE_YEAR = 0x0145, // DV + HID_USAGE_TELEPHONY_HANDSET_NICKNAME = 0x0146, // DV + HID_USAGE_TELEPHONY_ADDRESS_BOOK_ID = 0x0147, // DV + // 148-149 Reserved + + HID_USAGE_TELEPHONY_CALL_DURATION = 0x014A, // DV + HID_USAGE_TELEPHONY_DUAL_MODE_PHONE = 0x014B, // CA + // 14C-FFFF Reserved }; /// HID Usage Table: Consumer Page (0x0C) -/// Only contains controls that supported by Windows (whole list is too long) enum { - HID_USAGE_CONSUMER_UNASSIGNED = 0x0000, + HID_USAGE_CONSUMER_UNASSIGNED = 0x0000, // Generic Control - HID_USAGE_CONSUMER_CONTROL = 0x0001, - HID_USAGE_CONSUMER_NUMERIC_KEY_PAD = 0x0002, - HID_USAGE_CONSUMER_PROGRAMMABLE_BUTTONS = 0x0003, - HID_USAGE_CONSUMER_MICROPHONE = 0x0004, - HID_USAGE_CONSUMER_HEADPHONE = 0x0005, - HID_USAGE_CONSUMER_GRAPHIC_EQUALIZER = 0x0006, - // 07-1F Reserved + HID_USAGE_CONSUMER_CONTROL = 0x0001, // CA + HID_USAGE_CONSUMER_NUMERIC_KEY_PAD = 0x0002, // NAry + HID_USAGE_CONSUMER_PROGRAMMABLE_BUTTONS = 0x0003, // NAry + HID_USAGE_CONSUMER_MICROPHONE = 0x0004, // CA + HID_USAGE_CONSUMER_HEADPHONE = 0x0005, // CA + HID_USAGE_CONSUMER_GRAPHIC_EQUALIZER = 0x0006, // CA + HID_USAGE_CONSUMER_KEYBOARD_BACKLIGHT = 0x0007, // CA + // 08-1F Reserved - HID_USAGE_CONSUMER_PLUS_10 = 0x0020, - HID_USAGE_CONSUMER_PLUS_100 = 0x0021, - HID_USAGE_CONSUMER_AM_PM = 0x0022, + HID_USAGE_CONSUMER_PLUS_10 = 0x0020, // OSC + HID_USAGE_CONSUMER_PLUS_100 = 0x0021, // OSC + HID_USAGE_CONSUMER_AM_PM = 0x0022, // OSC // 23-3F Reserved // Power Control - HID_USAGE_CONSUMER_POWER = 0x0030, - HID_USAGE_CONSUMER_RESET = 0x0031, - HID_USAGE_CONSUMER_SLEEP = 0x0032, + HID_USAGE_CONSUMER_POWER = 0x0030, // OOC + HID_USAGE_CONSUMER_RESET = 0x0031, // OSC + HID_USAGE_CONSUMER_SLEEP = 0x0032, // OSC - HID_USAGE_CONSUMER_SLEEP_AFTER = 0x0033, - HID_USAGE_CONSUMER_SLEEP_MODE = 0x0034, - HID_USAGE_CONSUMER_ILLUMINATION = 0x0035, - HID_USAGE_CONSUMER_FUNCTION_BUTTONS = 0x0036, + HID_USAGE_CONSUMER_SLEEP_AFTER = 0x0033, // OSC + HID_USAGE_CONSUMER_SLEEP_MODE = 0x0034, // RTC + HID_USAGE_CONSUMER_ILLUMINATION = 0x0035, // OOC + HID_USAGE_CONSUMER_FUNCTION_BUTTONS = 0x0036, // NAry // 37-3F Reserved - HID_USAGE_CONSUMER_MENU = 0x0040, - HID_USAGE_CONSUMER_MENU_PICK = 0x0041, - HID_USAGE_CONSUMER_MENU_UP = 0x0042, - HID_USAGE_CONSUMER_MENU_DOWN = 0x0043, - HID_USAGE_CONSUMER_MENU_LEFT = 0x0044, - HID_USAGE_CONSUMER_MENU_RIGHT = 0x0045, - HID_USAGE_CONSUMER_MENU_ESCAPE = 0x0046, - HID_USAGE_CONSUMER_MENU_VALUE_INCREASE = 0x0047, - HID_USAGE_CONSUMER_MENU_VALUE_DECREASE = 0x0048, + HID_USAGE_CONSUMER_MENU = 0x0040, // OOC + HID_USAGE_CONSUMER_MENU_PICK = 0x0041, // OSC + HID_USAGE_CONSUMER_MENU_UP = 0x0042, // OSC + HID_USAGE_CONSUMER_MENU_DOWN = 0x0043, // OSC + HID_USAGE_CONSUMER_MENU_LEFT = 0x0044, // OSC + HID_USAGE_CONSUMER_MENU_RIGHT = 0x0045, // OSC + HID_USAGE_CONSUMER_MENU_ESCAPE = 0x0046, // OSC + HID_USAGE_CONSUMER_MENU_VALUE_INCREASE = 0x0047, // OSC + HID_USAGE_CONSUMER_MENU_VALUE_DECREASE = 0x0048, // OSC // 49-5F Reserved - HID_USAGE_CONSUMER_DATA_ON_SCREEN = 0x0060, - HID_USAGE_CONSUMER_CLOSED_CAPTION = 0x0061, - HID_USAGE_CONSUMER_CLOSED_CAPTION_SELECT = 0x0062, - HID_USAGE_CONSUMER_VCR_TV = 0x0063, - HID_USAGE_CONSUMER_BROADCAST_MODE = 0x0064, - HID_USAGE_CONSUMER_SNAPSHOT = 0x0065, - HID_USAGE_CONSUMER_STILL = 0x0066, - - // 67-7F Reserved - // Screen Brightness - HID_USAGE_CONSUMER_BRIGHTNESS_INCREMENT = 0x006F, - HID_USAGE_CONSUMER_BRIGHTNESS_DECREMENT = 0x0070, - - // These HID usages operate only on mobile systems (battery powered) and - // require Windows 8 (build 8302 or greater). - HID_USAGE_CONSUMER_WIRELESS_RADIO_CONTROLS = 0x000C, - HID_USAGE_CONSUMER_WIRELESS_RADIO_BUTTONS = 0x00C6, - HID_USAGE_CONSUMER_WIRELESS_RADIO_LED = 0x00C7, - HID_USAGE_CONSUMER_WIRELESS_RADIO_SLIDER_SWITCH = 0x00C8, - - HID_USAGE_CONSUMER_SELECTION = 0x0080, - HID_USAGE_CONSUMER_ASSIGN_SELECTION = 0x0081, - HID_USAGE_CONSUMER_MODE_STEP = 0x0082, - HID_USAGE_CONSUMER_RECALL_LAST = 0x0083, - HID_USAGE_CONSUMER_ENTER_CHANNEL = 0x0084, - HID_USAGE_CONSUMER_ORDER_MOVIE = 0x0085, - HID_USAGE_CONSUMER_CHANNEL = 0x0086, - HID_USAGE_CONSUMER_MEDIA_SELECTION = 0x0087, - HID_USAGE_CONSUMER_MEDIA_SELECT_COMPUTER = 0x0088, - HID_USAGE_CONSUMER_MEDIA_SELECT_TV = 0x0089, - HID_USAGE_CONSUMER_MEDIA_SELECT_WWW = 0x008A, - HID_USAGE_CONSUMER_MEDIA_SELECT_DVD = 0x008B, - HID_USAGE_CONSUMER_MEDIA_SELECT_TELEPHONE = 0x008C, - HID_USAGE_CONSUMER_MEDIA_SELECT_PROGRAM_GUIDE = 0x008D, - HID_USAGE_CONSUMER_MEDIA_SELECT_VIDEO_PHONE = 0x008E, - HID_USAGE_CONSUMER_MEDIA_SELECT_GAMES = 0x008F, - HID_USAGE_CONSUMER_MEDIA_SELECT_MESSAGES = 0x0090, - HID_USAGE_CONSUMER_MEDIA_SELECT_CD = 0x0091, - HID_USAGE_CONSUMER_MEDIA_SELECT_VCR = 0x0092, - HID_USAGE_CONSUMER_MEDIA_SELECT_TUNER = 0x0093, - HID_USAGE_CONSUMER_QUIT = 0x0094, - HID_USAGE_CONSUMER_HELP = 0x0095, - HID_USAGE_CONSUMER_MEDIA_SELECT_TAPE = 0x0096, - HID_USAGE_CONSUMER_MEDIA_SELECT_CABLE = 0x0097, - HID_USAGE_CONSUMER_MEDIA_SELECT_SATELLITE = 0x0098, - HID_USAGE_CONSUMER_MEDIA_SELECT_SECURITY = 0x0099, - HID_USAGE_CONSUMER_MEDIA_SELECT_HOME = 0x009A, - HID_USAGE_CONSUMER_MEDIA_SELECT_CALL = 0x009B, - HID_USAGE_CONSUMER_CHANNEL_INCREMENT = 0x009C, - HID_USAGE_CONSUMER_CHANNEL_DECREMENT = 0x009D, - HID_USAGE_CONSUMER_MEDIA_SELECT_SAP = 0x009E, + HID_USAGE_CONSUMER_DATA_ON_SCREEN = 0x0060, // OOC + HID_USAGE_CONSUMER_CLOSED_CAPTION = 0x0061, // OOC + HID_USAGE_CONSUMER_CLOSED_CAPTION_SELECT = 0x0062, // OSC + HID_USAGE_CONSUMER_VCR_TV = 0x0063, // OOC + HID_USAGE_CONSUMER_BROADCAST_MODE = 0x0064, // OSC + HID_USAGE_CONSUMER_SNAPSHOT = 0x0065, // OSC + HID_USAGE_CONSUMER_STILL = 0x0066, // OSC + HID_USAGE_CONSUMER_PICTURE_IN_PICTURE_TOGGLE = 0x0067, // OSC + HID_USAGE_CONSUMER_PICTURE_IN_PICTURE_SWAP = 0x0068, // OSC + HID_USAGE_CONSUMER_RED_MENU_BUTTON = 0x0069, // MC + HID_USAGE_CONSUMER_GREEN_MENU_BUTTON = 0x006A, // MC + HID_USAGE_CONSUMER_BLUE_MENU_BUTTON = 0x006B, // MC + HID_USAGE_CONSUMER_YELLOW_MENU_BUTTON = 0x006C, // MC + HID_USAGE_CONSUMER_ASPECT = 0x006D, // OSC + HID_USAGE_CONSUMER_3D_MODE_SELECT = 0x006E, // OSC + HID_USAGE_CONSUMER_DISPLAY_BRIGHTNESS_INCREMENT = 0x006F, // RTC + HID_USAGE_CONSUMER_DISPLAY_BRIGHTNESS_DECREMENT = 0x0070, // RTC + HID_USAGE_CONSUMER_DISPLAY_BRIGHTNESS = 0x0071, // LC + HID_USAGE_CONSUMER_DISPLAY_BACKLIGHT_TOGGLE = 0x0072, // OOC + HID_USAGE_CONSUMER_DISPLAY_SET_BRIGHTNESS_TO_MINIMUM = 0x0073, // OSC + HID_USAGE_CONSUMER_DISPLAY_SET_BRIGHTNESS_TO_MAXIMUM = 0x0074, // OSC + HID_USAGE_CONSUMER_DISPLAY_SET_AUTO_BRIGHTNESS = 0x0075, // OOC + HID_USAGE_CONSUMER_CAMERA_ACCESS_ENABLED = 0x0076, // OOC + HID_USAGE_CONSUMER_CAMERA_ACCESS_DISABLED = 0x0077, // OOC + HID_USAGE_CONSUMER_CAMERA_ACCESS_TOGGLE = 0x0078, // OOC + HID_USAGE_CONSUMER_KEYBOARD_BRIGHTNESS_INCREMENT = 0x0079, // OSC + HID_USAGE_CONSUMER_KEYBOARD_BRIGHTNESS_DECREMENT = 0x007A, // OSC + HID_USAGE_CONSUMER_KEYBOARD_BACKLIGHT_SET_LEVEL = 0x007B, // LC + HID_USAGE_CONSUMER_KEYBOARD_BACKLIGHT_OOC = 0x007C, // OOC + HID_USAGE_CONSUMER_KEYBOARD_BACKLIGHT_SET_MINIMUM = 0x007D, // OSC + HID_USAGE_CONSUMER_KEYBOARD_BACKLIGHT_SET_MAXIMUM = 0x007E, // OSC + HID_USAGE_CONSUMER_KEYBOARD_BACKLIGHT_AUTO = 0x007F, // OOC + HID_USAGE_CONSUMER_SELECTION = 0x0080, // NAry + HID_USAGE_CONSUMER_ASSIGN_SELECTION = 0x0081, // OSC + HID_USAGE_CONSUMER_MODE_STEP = 0x0082, // OSC + HID_USAGE_CONSUMER_RECALL_LAST = 0x0083, // OSC + HID_USAGE_CONSUMER_ENTER_CHANNEL = 0x0084, // OSC + HID_USAGE_CONSUMER_ORDER_MOVIE = 0x0085, // OSC + HID_USAGE_CONSUMER_CHANNEL = 0x0086, // LC + HID_USAGE_CONSUMER_MEDIA_SELECTION = 0x0087, // NAry + HID_USAGE_CONSUMER_MEDIA_SELECT_COMPUTER = 0x0088, // Sel + HID_USAGE_CONSUMER_MEDIA_SELECT_TV = 0x0089, // Sel + HID_USAGE_CONSUMER_MEDIA_SELECT_WWW = 0x008A, // Sel + HID_USAGE_CONSUMER_MEDIA_SELECT_DVD = 0x008B, // Sel + HID_USAGE_CONSUMER_MEDIA_SELECT_TELEPHONE = 0x008C, // Sel + HID_USAGE_CONSUMER_MEDIA_SELECT_PROGRAM_GUIDE = 0x008D, // Sel + HID_USAGE_CONSUMER_MEDIA_SELECT_VIDEO_PHONE = 0x008E, // Sel + HID_USAGE_CONSUMER_MEDIA_SELECT_GAMES = 0x008F, // Sel + HID_USAGE_CONSUMER_MEDIA_SELECT_MESSAGES = 0x0090, // Sel + HID_USAGE_CONSUMER_MEDIA_SELECT_CD = 0x0091, // Sel + HID_USAGE_CONSUMER_MEDIA_SELECT_VCR = 0x0092, // Sel + HID_USAGE_CONSUMER_MEDIA_SELECT_TUNER = 0x0093, // Sel + HID_USAGE_CONSUMER_QUIT = 0x0094, // OSC + HID_USAGE_CONSUMER_HELP = 0x0095, // OOC + HID_USAGE_CONSUMER_MEDIA_SELECT_TAPE = 0x0096, // Sel + HID_USAGE_CONSUMER_MEDIA_SELECT_CABLE = 0x0097, // Sel + HID_USAGE_CONSUMER_MEDIA_SELECT_SATELLITE = 0x0098, // Sel + HID_USAGE_CONSUMER_MEDIA_SELECT_SECURITY = 0x0099, // Sel + HID_USAGE_CONSUMER_MEDIA_SELECT_HOME = 0x009A, // Sel + HID_USAGE_CONSUMER_MEDIA_SELECT_CALL = 0x009B, // Sel + HID_USAGE_CONSUMER_CHANNEL_INCREMENT = 0x009C, // OSC + HID_USAGE_CONSUMER_CHANNEL_DECREMENT = 0x009D, // OSC + HID_USAGE_CONSUMER_MEDIA_SELECT_SAP = 0x009E, // Sel // 9F Reserved - HID_USAGE_CONSUMER_VCR_PLUS = 0x00A0, - HID_USAGE_CONSUMER_ONCE = 0x00A1, - HID_USAGE_CONSUMER_DAILY = 0x00A2, - HID_USAGE_CONSUMER_WEEKLY = 0x00A3, - HID_USAGE_CONSUMER_MONTHLY = 0x00A4, + HID_USAGE_CONSUMER_VCR_PLUS = 0x00A0, // OSC + HID_USAGE_CONSUMER_ONCE = 0x00A1, // OSC + HID_USAGE_CONSUMER_DAILY = 0x00A2, // OSC + HID_USAGE_CONSUMER_WEEKLY = 0x00A3, // OSC + HID_USAGE_CONSUMER_MONTHLY = 0x00A4, // OSC // A5-AF Reserved - HID_USAGE_CONSUMER_PLAY = 0x00B0, - HID_USAGE_CONSUMER_PAUSE = 0x00B1, - HID_USAGE_CONSUMER_RECORD = 0x00B2, - HID_USAGE_CONSUMER_FAST_FORWARD = 0x00B3, - HID_USAGE_CONSUMER_REWIND = 0x00B4, - HID_USAGE_CONSUMER_SCAN_NEXT_TRACK = 0x00B5, - HID_USAGE_CONSUMER_SCAN_PREVIOUS_TRACK = 0x00B6, - HID_USAGE_CONSUMER_STOP = 0x00B7, - HID_USAGE_CONSUMER_EJECT = 0x00B8, - HID_USAGE_CONSUMER_RANDOM_PLAY = 0x00B9, - HID_USAGE_CONSUMER_SELECT_DISC = 0x00BA, - HID_USAGE_CONSUMER_ENTER_DISC = 0x00BB, - HID_USAGE_CONSUMER_REPEAT = 0x00BC, - HID_USAGE_CONSUMER_TRACKING = 0x00BD, - HID_USAGE_CONSUMER_TRACK_NORMAL = 0x00BE, - HID_USAGE_CONSUMER_SLOW_TRACKING = 0x00BF, - HID_USAGE_CONSUMER_FRAME_FORWARD = 0x00C0, - HID_USAGE_CONSUMER_FRAME_BACK = 0x00C1, - HID_USAGE_CONSUMER_MARK = 0x00C2, - HID_USAGE_CONSUMER_CLEAR_MARK = 0x00C3, - HID_USAGE_CONSUMER_REPEAT_FROM_MARK = 0x00C4, - HID_USAGE_CONSUMER_RETURN_TO_MARK = 0x00C5, - HID_USAGE_CONSUMER_SEARCH_MARK_FORWARD = 0x00C6, - HID_USAGE_CONSUMER_SEARCH_MARK_BACKWARDS = 0x00C7, - HID_USAGE_CONSUMER_COUNTER_RESET = 0x00C8, - HID_USAGE_CONSUMER_SHOW_COUNTER = 0x00C9, - HID_USAGE_CONSUMER_TRACKING_INCREMENT = 0x00CA, - HID_USAGE_CONSUMER_TRACKING_DECREMENT = 0x00CB, - HID_USAGE_CONSUMER_STOP_EJECT = 0x00CC, + HID_USAGE_CONSUMER_PLAY = 0x00B0, // OOC + HID_USAGE_CONSUMER_PAUSE = 0x00B1, // OOC + HID_USAGE_CONSUMER_RECORD = 0x00B2, // OOC + HID_USAGE_CONSUMER_FAST_FORWARD = 0x00B3, // OOC + HID_USAGE_CONSUMER_REWIND = 0x00B4, // OOC + HID_USAGE_CONSUMER_SCAN_NEXT_TRACK = 0x00B5, // OSC + HID_USAGE_CONSUMER_SCAN_PREVIOUS_TRACK = 0x00B6, // OSC + HID_USAGE_CONSUMER_STOP = 0x00B7, // OSC + HID_USAGE_CONSUMER_EJECT = 0x00B8, // OSC + HID_USAGE_CONSUMER_RANDOM_PLAY = 0x00B9, // OOC + HID_USAGE_CONSUMER_SELECT_DISC = 0x00BA, // NAry + HID_USAGE_CONSUMER_ENTER_DISC = 0x00BB, // MC + HID_USAGE_CONSUMER_REPEAT = 0x00BC, // OSC + HID_USAGE_CONSUMER_TRACKING = 0x00BD, // LC + HID_USAGE_CONSUMER_TRACK_NORMAL = 0x00BE, // OSC + HID_USAGE_CONSUMER_SLOW_TRACKING = 0x00BF, // LC + HID_USAGE_CONSUMER_FRAME_FORWARD = 0x00C0, // RTC + HID_USAGE_CONSUMER_FRAME_BACK = 0x00C1, // RTC + HID_USAGE_CONSUMER_MARK = 0x00C2, // OSC + HID_USAGE_CONSUMER_CLEAR_MARK = 0x00C3, // OSC + HID_USAGE_CONSUMER_REPEAT_FROM_MARK = 0x00C4, // OOC + HID_USAGE_CONSUMER_RETURN_TO_MARK = 0x00C5, // OSC + HID_USAGE_CONSUMER_SEARCH_MARK_FORWARD = 0x00C6, // OSC + HID_USAGE_CONSUMER_SEARCH_MARK_BACKWARDS = 0x00C7, // OSC + HID_USAGE_CONSUMER_COUNTER_RESET = 0x00C8, // OSC - // Media Control - HID_USAGE_CONSUMER_PLAY_PAUSE = 0x00CD, + // These HID usages operate only on mobile systems (battery powered) and + // require Windows 8 (build 8302 or greater). + HID_USAGE_CONSUMER_WIRELESS_RADIO_CONTROLS = 0x000C, + HID_USAGE_CONSUMER_WIRELESS_RADIO_BUTTONS = 0x00C6, + HID_USAGE_CONSUMER_WIRELESS_RADIO_LED = 0x00C7, + HID_USAGE_CONSUMER_WIRELESS_RADIO_SLIDER_SWITCH = 0x00C8, - HID_USAGE_CONSUMER_PLAY_SKIP = 0x00CE, - // CF-DF Reserved - HID_USAGE_CONSUMER_VOLUME = 0x00E0, - HID_USAGE_CONSUMER_BALANCE = 0x00E1, - HID_USAGE_CONSUMER_MUTE = 0x00E2, - HID_USAGE_CONSUMER_BASS = 0x00E3, - HID_USAGE_CONSUMER_TREBLE = 0x00E4, - HID_USAGE_CONSUMER_BASS_BOOST = 0x00E5, - HID_USAGE_CONSUMER_SURROUND_MODE = 0x00E6, - HID_USAGE_CONSUMER_LOUDNESS = 0x00E7, - HID_USAGE_CONSUMER_MPX = 0x00E8, - HID_USAGE_CONSUMER_VOLUME_INCREMENT = 0x00E9, - HID_USAGE_CONSUMER_VOLUME_DECREMENT = 0x00EA, + HID_USAGE_CONSUMER_SHOW_COUNTER = 0x00C9, // OSC + HID_USAGE_CONSUMER_TRACKING_INCREMENT = 0x00CA, // RTC + HID_USAGE_CONSUMER_TRACKING_DECREMENT = 0x00CB, // RTC + HID_USAGE_CONSUMER_STOP_EJECT = 0x00CC, // OSC + HID_USAGE_CONSUMER_PLAY_PAUSE = 0x00CD, // OSC + HID_USAGE_CONSUMER_PLAY_SKIP = 0x00CE, // OSC + HID_USAGE_CONSUMER_VOICE_COMMAND = 0x00CF, // OSC + HID_USAGE_CONSUMER_INVOKE_CAPTURE_INTERFACE = 0x00D0, // Sel + HID_USAGE_CONSUMER_START_OR_STOP_GAME_RECORDING = 0x00D1, // Sel + HID_USAGE_CONSUMER_HISTORICAL_GAME_CAPTURE = 0x00D2, // Sel + HID_USAGE_CONSUMER_CAPTURE_GAME_SCREENSHOT = 0x00D3, // Sel + HID_USAGE_CONSUMER_SHOW_OR_HIDE_RECORDING_INDICATOR = 0x00D4, // Sel + HID_USAGE_CONSUMER_START_OR_STOP_MICROPHONE_CAPTURE = 0x00D5, // Sel + HID_USAGE_CONSUMER_START_OR_STOP_CAMERA_CAPTURE = 0x00D6, // Sel + HID_USAGE_CONSUMER_START_OR_STOP_GAME_BROADCAST = 0x00D7, // Sel + HID_USAGE_CONSUMER_START_OR_STOP_VOICE_DICTATION_SESSION = 0x00D8, // OOC + HID_USAGE_CONSUMER_INVOKE_DISMISS_EMOJI_PICKER = 0x00D9, // OOC + // DA-DF Reserved + HID_USAGE_CONSUMER_VOLUME = 0x00E0, // LC + HID_USAGE_CONSUMER_BALANCE = 0x00E1, // LC + HID_USAGE_CONSUMER_MUTE = 0x00E2, // OOC + HID_USAGE_CONSUMER_BASS = 0x00E3, // LC + HID_USAGE_CONSUMER_TREBLE = 0x00E4, // LC + HID_USAGE_CONSUMER_BASS_BOOST = 0x00E5, // OOC + HID_USAGE_CONSUMER_SURROUND_MODE = 0x00E6, // OSC + HID_USAGE_CONSUMER_LOUDNESS = 0x00E7, // OOC + HID_USAGE_CONSUMER_MPX = 0x00E8, // OOC + HID_USAGE_CONSUMER_VOLUME_INCREMENT = 0x00E9, // RTC + HID_USAGE_CONSUMER_VOLUME_DECREMENT = 0x00EA, // RTC // EB-EF Reserved - HID_USAGE_CONSUMER_SPEED_SELECT = 0x00F0, - HID_USAGE_CONSUMER_PLAYBACK_SPEED = 0x00F1, - HID_USAGE_CONSUMER_STANDARD_PLAY = 0x00F2, - HID_USAGE_CONSUMER_LONG_PLAY = 0x00F3, - HID_USAGE_CONSUMER_EXTENDED_PLAY = 0x00F4, - HID_USAGE_CONSUMER_SLOW = 0x00F5, + HID_USAGE_CONSUMER_SPEED_SELECT = 0x00F0, // OSC + HID_USAGE_CONSUMER_PLAYBACK_SPEED = 0x00F1, // NAry + HID_USAGE_CONSUMER_STANDARD_PLAY = 0x00F2, // Sel + HID_USAGE_CONSUMER_LONG_PLAY = 0x00F3, // Sel + HID_USAGE_CONSUMER_EXTENDED_PLAY = 0x00F4, // Sel + HID_USAGE_CONSUMER_SLOW = 0x00F5, // OSC // F6-FF Reserved - HID_USAGE_CONSUMER_FAN_ENABLE = 0x0100, - HID_USAGE_CONSUMER_FAN_SPEED = 0x0101, - HID_USAGE_CONSUMER_LIGHT_ENABLE = 0x0102, - HID_USAGE_CONSUMER_LIGHT_ILLUMINATION_LEVEL = 0x0103, - HID_USAGE_CONSUMER_CLIMATE_CONTROL_ENABLE = 0x0104, - HID_USAGE_CONSUMER_ROOM_TEMPERATURE = 0x0105, - HID_USAGE_CONSUMER_SECURITY_ENABLE = 0x0106, - HID_USAGE_CONSUMER_FIRE_ALARM = 0x0107, - HID_USAGE_CONSUMER_POLICE_ALARM = 0x0108, - HID_USAGE_CONSUMER_PROXIMITY = 0x0109, - HID_USAGE_CONSUMER_MOTION = 0x010A, - HID_USAGE_CONSUMER_DURESS_ALARM = 0x010B, - HID_USAGE_CONSUMER_HOLDUP_ALARM = 0x010C, - HID_USAGE_CONSUMER_MEDICAL_ALARM = 0x010D, + HID_USAGE_CONSUMER_FAN_ENABLE = 0x0100, // OOC + HID_USAGE_CONSUMER_FAN_SPEED = 0x0101, // LC + HID_USAGE_CONSUMER_LIGHT_ENABLE = 0x0102, // OOC + HID_USAGE_CONSUMER_LIGHT_ILLUMINATION_LEVEL = 0x0103, // LC + HID_USAGE_CONSUMER_CLIMATE_CONTROL_ENABLE = 0x0104, // OOC + HID_USAGE_CONSUMER_ROOM_TEMPERATURE = 0x0105, // LC + HID_USAGE_CONSUMER_SECURITY_ENABLE = 0x0106, // OOC + HID_USAGE_CONSUMER_FIRE_ALARM = 0x0107, // OSC + HID_USAGE_CONSUMER_POLICE_ALARM = 0x0108, // OSC + HID_USAGE_CONSUMER_PROXIMITY = 0x0109, // LC + HID_USAGE_CONSUMER_MOTION = 0x010A, // OSC + HID_USAGE_CONSUMER_DURESS_ALARM = 0x010B, // OSC + HID_USAGE_CONSUMER_HOLDUP_ALARM = 0x010C, // OSC + HID_USAGE_CONSUMER_MEDICAL_ALARM = 0x010D, // OSC // 10E-14F Reserved - HID_USAGE_CONSUMER_BALANCE_RIGHT = 0x0150, - HID_USAGE_CONSUMER_BALANCE_LEFT = 0x0151, - HID_USAGE_CONSUMER_BASS_INCREMENT = 0x0152, - HID_USAGE_CONSUMER_BASS_DECREMENT = 0x0153, - HID_USAGE_CONSUMER_TREBLE_INCREMENT = 0x0154, - HID_USAGE_CONSUMER_TREBLE_DECREMENT = 0x0155, + HID_USAGE_CONSUMER_BALANCE_RIGHT = 0x0150, // RTC + HID_USAGE_CONSUMER_BALANCE_LEFT = 0x0151, // RTC + HID_USAGE_CONSUMER_BASS_INCREMENT = 0x0152, // RTC + HID_USAGE_CONSUMER_BASS_DECREMENT = 0x0153, // RTC + HID_USAGE_CONSUMER_TREBLE_INCREMENT = 0x0154, // RTC + HID_USAGE_CONSUMER_TREBLE_DECREMENT = 0x0155, // RTC // 156-15F Reserved - HID_USAGE_CONSUMER_SPEAKER_SYSTEM = 0x0160, - HID_USAGE_CONSUMER_CHANNEL_LEFT = 0x0161, - HID_USAGE_CONSUMER_CHANNEL_RIGHT = 0x0162, - HID_USAGE_CONSUMER_CHANNEL_CENTER = 0x0163, - HID_USAGE_CONSUMER_CHANNEL_FRONT = 0x0164, - HID_USAGE_CONSUMER_CHANNEL_CENTER_FRONT = 0x0165, - HID_USAGE_CONSUMER_CHANNEL_SIDE = 0x0166, - HID_USAGE_CONSUMER_CHANNEL_SURROUND = 0x0167, - HID_USAGE_CONSUMER_CHANNEL_LOW_FREQUENCY = 0x0168, - // Enhancement - // CL 15.12.1 - HID_USAGE_CONSUMER_CHANNEL_TOP = 0x0169, - HID_USAGE_CONSUMER_CHANNEL_UNKNOWN = 0x016A, + HID_USAGE_CONSUMER_SPEAKER_SYSTEM = 0x0160, // CL + HID_USAGE_CONSUMER_CHANNEL_LEFT = 0x0161, // CL + HID_USAGE_CONSUMER_CHANNEL_RIGHT = 0x0162, // CL + HID_USAGE_CONSUMER_CHANNEL_CENTER = 0x0163, // CL + HID_USAGE_CONSUMER_CHANNEL_FRONT = 0x0164, // CL + HID_USAGE_CONSUMER_CHANNEL_CENTER_FRONT = 0x0165, // CL + HID_USAGE_CONSUMER_CHANNEL_SIDE = 0x0166, // CL + HID_USAGE_CONSUMER_CHANNEL_SURROUND = 0x0167, // CL + HID_USAGE_CONSUMER_CHANNEL_LOW_FREQUENCY = 0x0168, // CL + HID_USAGE_CONSUMER_CHANNEL_TOP = 0x0169, // CL + HID_USAGE_CONSUMER_CHANNEL_UNKNOWN = 0x016A, // CL // 16B-16F Reserved - HID_USAGE_CONSUMER_SUB_CHANNEL = 0x0170, - HID_USAGE_CONSUMER_SUB_CHANNEL_INCREMENT = 0x0171, - HID_USAGE_CONSUMER_SUB_CHANNEL_DECREMENT = 0x0172, - HID_USAGE_CONSUMER_ALTERNATE_AUDIO_INCREMENT = 0x0173, - HID_USAGE_CONSUMER_ALTERNATE_AUDIO_DECREMENT = 0x0174, + HID_USAGE_CONSUMER_SUB_CHANNEL = 0x0170, // LC + HID_USAGE_CONSUMER_SUB_CHANNEL_INCREMENT = 0x0171, // OSC + HID_USAGE_CONSUMER_SUB_CHANNEL_DECREMENT = 0x0172, // OSC + HID_USAGE_CONSUMER_ALTERNATE_AUDIO_INCREMENT = 0x0173, // OSC + HID_USAGE_CONSUMER_ALTERNATE_AUDIO_DECREMENT = 0x0174, // OSC // 175-17F Reserved - HID_USAGE_CONSUMER_APPLICATION_LAUNCH_BUTTONS = 0x0180, - HID_USAGE_CONSUMER_AL_LAUNCH_BUTTON_CONFIGURATION = 0x0181, - // Tool - // Sel 15.15 - HID_USAGE_CONSUMER_AL_PROGRAMMABLE_BUTTON = 0x0182, - // Configuration - // Sel 15.15 - HID_USAGE_CONSUMER_AL_CONSUMER_CONTROL_CONFIGURATION = 0x0183, - // Configuration - // Sel 15.15 - HID_USAGE_CONSUMER_AL_WORD_PROCESSOR = 0x0184, - HID_USAGE_CONSUMER_AL_TEXT_EDITOR = 0x0185, - HID_USAGE_CONSUMER_AL_SPREADSHEET = 0x0186, - HID_USAGE_CONSUMER_AL_GRAPHICS_EDITOR = 0x0187, - HID_USAGE_CONSUMER_AL_PRESENTATION_APP = 0x0188, - HID_USAGE_CONSUMER_AL_DATABASE_APP = 0x0189, - HID_USAGE_CONSUMER_AL_EMAIL_READER = 0x018A, - HID_USAGE_CONSUMER_AL_NEWSREADER = 0x018B, - HID_USAGE_CONSUMER_AL_VOICEMAIL = 0x018C, - HID_USAGE_CONSUMER_AL_CONTACTS_ADDRESS_BOOK = 0x018D, - HID_USAGE_CONSUMER_AL_CALENDAR_SCHEDULE = 0x018E, - HID_USAGE_CONSUMER_AL_TASK_PROJECT_MANAGER = 0x018F, - HID_USAGE_CONSUMER_AL_LOG_JOURNAL_TIMECARD = 0x0190, - HID_USAGE_CONSUMER_AL_CHECKBOOK_FINANCE = 0x0191, - HID_USAGE_CONSUMER_AL_CALCULATOR = 0x0192, - HID_USAGE_CONSUMER_AL_A_V_CAPTURE_PLAYBACK = 0x0193, - HID_USAGE_CONSUMER_AL_LOCAL_MACHINE_BROWSER = 0x0194, - HID_USAGE_CONSUMER_AL_LAN_WAN_BROWSER = 0x0195, - HID_USAGE_CONSUMER_AL_INTERNET_BROWSER = 0x0196, - HID_USAGE_CONSUMER_AL_REMOTE_NETWORKING_ISP = 0x0197, - // Connect - // Sel 15.15 - HID_USAGE_CONSUMER_AL_NETWORK_CONFERENCE = 0x0198, - HID_USAGE_CONSUMER_AL_NETWORK_CHAT = 0x0199, - HID_USAGE_CONSUMER_AL_TELEPHONY_DIALER = 0x019A, - HID_USAGE_CONSUMER_AL_LOGON = 0x019B, - HID_USAGE_CONSUMER_AL_LOGOFF = 0x019C, - HID_USAGE_CONSUMER_AL_LOGON_LOGOFF = 0x019D, - HID_USAGE_CONSUMER_AL_TERMINAL_LOCK_SCREENSAVER = 0x019E, - HID_USAGE_CONSUMER_AL_CONTROL_PANEL = 0x019F, - HID_USAGE_CONSUMER_AL_COMMAND_LINE_PROCESSOR_RUN = 0x01A0, - HID_USAGE_CONSUMER_AL_PROCESS_TASK_MANAGER = 0x01A1, - HID_USAGE_CONSUMER_AL_SELECT_TASK_APPLICATION = 0x01A2, - HID_USAGE_CONSUMER_AL_NEXT_TASK_APPLICATION = 0x01A3, - HID_USAGE_CONSUMER_AL_PREVIOUS_TASK_APPLICATION = 0x01A4, - HID_USAGE_CONSUMER_AL_PREEMPTIVE_HALT = 0x01A5, - // Task_Application - // Sel 15.15 - HID_USAGE_CONSUMER_AL_INTEGRATED_HELP_CENTER = 0x01A6, - HID_USAGE_CONSUMER_AL_DOCUMENTS = 0x01A7, - HID_USAGE_CONSUMER_AL_THESAURUS = 0x01A8, - HID_USAGE_CONSUMER_AL_DICTIONARY = 0x01A9, - HID_USAGE_CONSUMER_AL_DESKTOP = 0x01AA, - HID_USAGE_CONSUMER_AL_SPELL_CHECK = 0x01AB, - HID_USAGE_CONSUMER_AL_GRAMMAR_CHECK = 0x01AC, - HID_USAGE_CONSUMER_AL_WIRELESS_STATUS = 0x01AD, - HID_USAGE_CONSUMER_AL_KEYBOARD_LAYOUT = 0x01AE, - HID_USAGE_CONSUMER_AL_VIRUS_PROTECTION = 0x01AF, - HID_USAGE_CONSUMER_AL_ENCRYPTION = 0x01B0, - HID_USAGE_CONSUMER_AL_SCREEN_SAVER = 0x01B1, - HID_USAGE_CONSUMER_AL_ALARMS = 0x01B2, - HID_USAGE_CONSUMER_AL_CLOCK = 0x01B3, - HID_USAGE_CONSUMER_AL_FILE_BROWSER = 0x01B4, - HID_USAGE_CONSUMER_AL_POWER_STATUS = 0x01B5, - HID_USAGE_CONSUMER_AL_IMAGE_BROWSER = 0x01B6, - HID_USAGE_CONSUMER_AL_AUDIO_BROWSER = 0x01B7, - HID_USAGE_CONSUMER_AL_MOVIE_BROWSER = 0x01B8, - HID_USAGE_CONSUMER_AL_DIGITAL_RIGHTS_MANAGER = 0x01B9, - HID_USAGE_CONSUMER_AL_DIGITAL_WALLET = 0x01BA, + HID_USAGE_CONSUMER_APPLICATION_LAUNCH_BUTTONS = 0x0180, // NAry + HID_USAGE_CONSUMER_AL_LAUNCH_BUTTON_CONFIGURATION = 0x0181, // Sel + HID_USAGE_CONSUMER_AL_PROGRAMMABLE_BUTTON = 0x0182, // Sel + HID_USAGE_CONSUMER_AL_CONSUMER_CONTROL_CONFIGURATION = 0x0183, // Sel + HID_USAGE_CONSUMER_AL_WORD_PROCESSOR = 0x0184, // Sel + HID_USAGE_CONSUMER_AL_TEXT_EDITOR = 0x0185, // Sel + HID_USAGE_CONSUMER_AL_SPREADSHEET = 0x0186, // Sel + HID_USAGE_CONSUMER_AL_GRAPHICS_EDITOR = 0x0187, // Sel + HID_USAGE_CONSUMER_AL_PRESENTATION_APP = 0x0188, // Sel + HID_USAGE_CONSUMER_AL_DATABASE_APP = 0x0189, // Sel + HID_USAGE_CONSUMER_AL_EMAIL_READER = 0x018A, // Sel + HID_USAGE_CONSUMER_AL_NEWSREADER = 0x018B, // Sel + HID_USAGE_CONSUMER_AL_VOICEMAIL = 0x018C, // Sel + HID_USAGE_CONSUMER_AL_CONTACTS_ADDRESS_BOOK = 0x018D, // Sel + HID_USAGE_CONSUMER_AL_CALENDAR_SCHEDULE = 0x018E, // Sel + HID_USAGE_CONSUMER_AL_TASK_PROJECT_MANAGER = 0x018F, // Sel + HID_USAGE_CONSUMER_AL_LOG_JOURNAL_TIMECARD = 0x0190, // Sel + HID_USAGE_CONSUMER_AL_CHECKBOOK_FINANCE = 0x0191, // Sel + HID_USAGE_CONSUMER_AL_CALCULATOR = 0x0192, // Sel + HID_USAGE_CONSUMER_AL_A_V_CAPTURE_PLAYBACK = 0x0193, // Sel + HID_USAGE_CONSUMER_AL_LOCAL_MACHINE_BROWSER = 0x0194, // Sel + HID_USAGE_CONSUMER_AL_LAN_WAN_BROWSER = 0x0195, // Sel + HID_USAGE_CONSUMER_AL_INTERNET_BROWSER = 0x0196, // Sel + HID_USAGE_CONSUMER_AL_REMOTE_NETWORKING_ISP = 0x0197, // Sel + HID_USAGE_CONSUMER_AL_NETWORK_CONFERENCE = 0x0198, // Sel + HID_USAGE_CONSUMER_AL_NETWORK_CHAT = 0x0199, // Sel + HID_USAGE_CONSUMER_AL_TELEPHONY_DIALER = 0x019A, // Sel + HID_USAGE_CONSUMER_AL_LOGON = 0x019B, // Sel + HID_USAGE_CONSUMER_AL_LOGOFF = 0x019C, // Sel + HID_USAGE_CONSUMER_AL_LOGON_LOGOFF = 0x019D, // Sel + HID_USAGE_CONSUMER_AL_TERMINAL_LOCK_SCREENSAVER = 0x019E, // Sel + HID_USAGE_CONSUMER_AL_CONTROL_PANEL = 0x019F, // Sel + HID_USAGE_CONSUMER_AL_COMMAND_LINE_PROCESSOR_RUN = 0x01A0, // Sel + HID_USAGE_CONSUMER_AL_PROCESS_TASK_MANAGER = 0x01A1, // Sel + HID_USAGE_CONSUMER_AL_SELECT_TASK_APPLICATION = 0x01A2, // Sel + HID_USAGE_CONSUMER_AL_NEXT_TASK_APPLICATION = 0x01A3, // Sel + HID_USAGE_CONSUMER_AL_PREVIOUS_TASK_APPLICATION = 0x01A4, // Sel + HID_USAGE_CONSUMER_AL_PREEMPTIVE_HALT = 0x01A5, // Sel + HID_USAGE_CONSUMER_AL_INTEGRATED_HELP_CENTER = 0x01A6, // Sel + HID_USAGE_CONSUMER_AL_DOCUMENTS = 0x01A7, // Sel + HID_USAGE_CONSUMER_AL_THESAURUS = 0x01A8, // Sel + HID_USAGE_CONSUMER_AL_DICTIONARY = 0x01A9, // Sel + HID_USAGE_CONSUMER_AL_DESKTOP = 0x01AA, // Sel + HID_USAGE_CONSUMER_AL_SPELL_CHECK = 0x01AB, // Sel + HID_USAGE_CONSUMER_AL_GRAMMAR_CHECK = 0x01AC, // Sel + HID_USAGE_CONSUMER_AL_WIRELESS_STATUS = 0x01AD, // Sel + HID_USAGE_CONSUMER_AL_KEYBOARD_LAYOUT = 0x01AE, // Sel + HID_USAGE_CONSUMER_AL_VIRUS_PROTECTION = 0x01AF, // Sel + HID_USAGE_CONSUMER_AL_ENCRYPTION = 0x01B0, // Sel + HID_USAGE_CONSUMER_AL_SCREEN_SAVER = 0x01B1, // Sel + HID_USAGE_CONSUMER_AL_ALARMS = 0x01B2, // Sel + HID_USAGE_CONSUMER_AL_CLOCK = 0x01B3, // Sel + HID_USAGE_CONSUMER_AL_FILE_BROWSER = 0x01B4, // Sel + HID_USAGE_CONSUMER_AL_POWER_STATUS = 0x01B5, // Sel + HID_USAGE_CONSUMER_AL_IMAGE_BROWSER = 0x01B6, // Sel + HID_USAGE_CONSUMER_AL_AUDIO_BROWSER = 0x01B7, // Sel + HID_USAGE_CONSUMER_AL_MOVIE_BROWSER = 0x01B8, // Sel + HID_USAGE_CONSUMER_AL_DIGITAL_RIGHTS_MANAGER = 0x01B9, // Sel + HID_USAGE_CONSUMER_AL_DIGITAL_WALLET = 0x01BA, // Sel // 1BB Reserved - HID_USAGE_CONSUMER_AL_INSTANT_MESSAGING = 0x01BC, - HID_USAGE_CONSUMER_AL_OEM_FEATURES_TIPS_TUTORIAL = 0x01BD, - // Browser - // Sel 15.15 - HID_USAGE_CONSUMER_AL_OEM_HELP = 0x01BE, - HID_USAGE_CONSUMER_AL_ONLINE_COMMUNITY = 0x01BF, - HID_USAGE_CONSUMER_AL_ENTERTAINMENT_CONTENT = 0x01C0, - // Browser - // Sel 15.15 - HID_USAGE_CONSUMER_AL_ONLINE_SHOPPING_BROWSER = 0x01C1, - HID_USAGE_CONSUMER_AL_SMARTCARD_INFORMATION_HELP = 0x01C2, - HID_USAGE_CONSUMER_AL_MARKET_MONITOR_FINANCE = 0x01C3, - // Browser - // Sel 15.15 - HID_USAGE_CONSUMER_AL_CUSTOMIZED_CORPORATE_NEWS = 0x01C4, - // Browser - // Sel 15.15 - HID_USAGE_CONSUMER_AL_ONLINE_ACTIVITY_BROWSER = 0x01C5, - HID_USAGE_CONSUMER_AL_RESEARCH_SEARCH_BROWSER = 0x01C6, - HID_USAGE_CONSUMER_AL_AUDIO_PLAYER = 0x01C7, - // 1C8-1FF Reserved - HID_USAGE_CONSUMER_GENERIC_GUI_APPLICATION = 0x0200, - // ' Controls - // ' - HID_USAGE_CONSUMER_AC_NEW = 0x0201, - HID_USAGE_CONSUMER_AC_OPEN = 0x0202, - HID_USAGE_CONSUMER_AC_CLOSE = 0x0203, - HID_USAGE_CONSUMER_AC_EXIT = 0x0204, - HID_USAGE_CONSUMER_AC_MAXIMIZE = 0x0205, - HID_USAGE_CONSUMER_AC_MINIMIZE = 0x0206, - HID_USAGE_CONSUMER_AC_SAVE = 0x0207, - HID_USAGE_CONSUMER_AC_PRINT = 0x0208, - HID_USAGE_CONSUMER_AC_PROPERTIES = 0x0209, - HID_USAGE_CONSUMER_AC_UNDO = 0x021A, - HID_USAGE_CONSUMER_AC_COPY = 0x021B, - HID_USAGE_CONSUMER_AC_CUT = 0x021C, - HID_USAGE_CONSUMER_AC_PASTE = 0x021D, - HID_USAGE_CONSUMER_AC_SELECT_ALL = 0x021E, - HID_USAGE_CONSUMER_AC_FIND = 0x021F, - HID_USAGE_CONSUMER_AC_FIND_AND_REPLACE = 0x0220, - // Browser/Explorer Specific - HID_USAGE_CONSUMER_AC_SEARCH = 0x0221, - HID_USAGE_CONSUMER_AC_GO_TO = 0x0222, - HID_USAGE_CONSUMER_AC_HOME = 0x0223, - HID_USAGE_CONSUMER_AC_BACK = 0x0224, - HID_USAGE_CONSUMER_AC_FORWARD = 0x0225, - HID_USAGE_CONSUMER_AC_STOP = 0x0226, - HID_USAGE_CONSUMER_AC_REFRESH = 0x0227, - HID_USAGE_CONSUMER_AC_PREVIOUS_LINK = 0x0228, - HID_USAGE_CONSUMER_AC_NEXT_LINK = 0x0229, - HID_USAGE_CONSUMER_AC_BOOKMARKS = 0x022A, - HID_USAGE_CONSUMER_AC_HISTORY = 0x022B, - HID_USAGE_CONSUMER_AC_SUBSCRIPTIONS = 0x022C, - HID_USAGE_CONSUMER_AC_ZOOM_IN = 0x022D, - HID_USAGE_CONSUMER_AC_ZOOM_OUT = 0x022E, - HID_USAGE_CONSUMER_AC_ZOOM = 0x022F, - HID_USAGE_CONSUMER_AC_FULL_SCREEN_VIEW = 0x0230, - HID_USAGE_CONSUMER_AC_NORMAL_VIEW = 0x0231, - HID_USAGE_CONSUMER_AC_VIEW_TOGGLE = 0x0232, - HID_USAGE_CONSUMER_AC_SCROLL_UP = 0x0233, - HID_USAGE_CONSUMER_AC_SCROLL_DOWN = 0x0234, - HID_USAGE_CONSUMER_AC_SCROLL = 0x0235, - HID_USAGE_CONSUMER_AC_PAN_LEFT = 0x0236, - HID_USAGE_CONSUMER_AC_PAN_RIGHT = 0x0237, - // Mouse Horizontal scroll - HID_USAGE_CONSUMER_AC_PAN = 0x0238, - HID_USAGE_CONSUMER_AC_NEW_WINDOW = 0x0239, - HID_USAGE_CONSUMER_AC_TILE_HORIZONTALLY = 0x023A, - HID_USAGE_CONSUMER_AC_TILE_VERTICALLY = 0x023B, - HID_USAGE_CONSUMER_AC_FORMAT = 0x023C, - HID_USAGE_CONSUMER_AC_EDIT = 0x023D, - HID_USAGE_CONSUMER_AC_BOLD = 0x023E, - HID_USAGE_CONSUMER_AC_ITALICS = 0x023F, - HID_USAGE_CONSUMER_AC_UNDERLINE = 0x0240, - HID_USAGE_CONSUMER_AC_STRIKETHROUGH = 0x0241, - HID_USAGE_CONSUMER_AC_SUBSCRIPT = 0x0242, - HID_USAGE_CONSUMER_AC_SUPERSCRIPT = 0x0243, - HID_USAGE_CONSUMER_AC_ALL_CAPS = 0x0244, - HID_USAGE_CONSUMER_AC_ROTATE = 0x0245, - HID_USAGE_CONSUMER_AC_RESIZE = 0x0246, - HID_USAGE_CONSUMER_AC_FLIP_HORIZONTAL = 0x0247, - HID_USAGE_CONSUMER_AC_FLIP_VERTICAL = 0x0248, - HID_USAGE_CONSUMER_AC_MIRROR_HORIZONTAL = 0x0249, - HID_USAGE_CONSUMER_AC_MIRROR_VERTICAL = 0x024A, - HID_USAGE_CONSUMER_AC_FONT_SELECT = 0x024B, - HID_USAGE_CONSUMER_AC_FONT_COLOR = 0x024C, - HID_USAGE_CONSUMER_AC_FONT_SIZE = 0x024D, - HID_USAGE_CONSUMER_AC_JUSTIFY_LEFT = 0x024E, - HID_USAGE_CONSUMER_AC_JUSTIFY_CENTER_H = 0x024F, - HID_USAGE_CONSUMER_AC_JUSTIFY_RIGHT = 0x0250, - HID_USAGE_CONSUMER_AC_JUSTIFY_BLOCK_H = 0x0251, - HID_USAGE_CONSUMER_AC_JUSTIFY_TOP = 0x0252, - HID_USAGE_CONSUMER_AC_JUSTIFY_CENTER_V = 0x0253, - HID_USAGE_CONSUMER_AC_JUSTIFY_BOTTOM = 0x0254, - HID_USAGE_CONSUMER_AC_JUSTIFY_BLOCK_V = 0x0255, - HID_USAGE_CONSUMER_AC_INDENT_DECREASE = 0x0256, - HID_USAGE_CONSUMER_AC_INDENT_INCREASE = 0x0257, - HID_USAGE_CONSUMER_AC_NUMBERED_LIST = 0x0258, - HID_USAGE_CONSUMER_AC_RESTART_NUMBERING = 0x0259, - HID_USAGE_CONSUMER_AC_BULLETED_LIST = 0x025A, - HID_USAGE_CONSUMER_AC_PROMOTE = 0x025B, - HID_USAGE_CONSUMER_AC_DEMOTE = 0x025C, - HID_USAGE_CONSUMER_AC_YES = 0x025D, - HID_USAGE_CONSUMER_AC_NO = 0x025E, - HID_USAGE_CONSUMER_AC_CANCEL = 0x025F, - HID_USAGE_CONSUMER_AC_CATALOG = 0x0260, - HID_USAGE_CONSUMER_AC_BUY_CHECKOUT = 0x0261, - HID_USAGE_CONSUMER_AC_ADD_TO_CART = 0x0262, - HID_USAGE_CONSUMER_AC_EXPAND = 0x0263, - HID_USAGE_CONSUMER_AC_EXPAND_ALL = 0x0264, - HID_USAGE_CONSUMER_AC_COLLAPSE = 0x0265, - HID_USAGE_CONSUMER_AC_COLLAPSE_ALL = 0x0266, - HID_USAGE_CONSUMER_AC_PRINT_PREVIEW = 0x0267, - HID_USAGE_CONSUMER_AC_PASTE_SPECIAL = 0x0268, - HID_USAGE_CONSUMER_AC_INSERT_MODE = 0x0269, - HID_USAGE_CONSUMER_AC_DELETE = 0x026A, - HID_USAGE_CONSUMER_AC_LOCK = 0x026B, - HID_USAGE_CONSUMER_AC_UNLOCK = 0x026C, - HID_USAGE_CONSUMER_AC_PROTECT = 0x026D, - HID_USAGE_CONSUMER_AC_UNPROTECT = 0x026E, - HID_USAGE_CONSUMER_AC_ATTACH_COMMENT = 0x026F, - HID_USAGE_CONSUMER_AC_DELETE_COMMENT = 0x0270, - HID_USAGE_CONSUMER_AC_VIEW_COMMENT = 0x0271, - HID_USAGE_CONSUMER_AC_SELECT_WORD = 0x0272, - HID_USAGE_CONSUMER_AC_SELECT_SENTENCE = 0x0273, - HID_USAGE_CONSUMER_AC_SELECT_PARAGRAPH = 0x0274, - HID_USAGE_CONSUMER_AC_SELECT_COLUMN = 0x0275, - HID_USAGE_CONSUMER_AC_SELECT_ROW = 0x0276, - HID_USAGE_CONSUMER_AC_SELECT_TABLE = 0x0277, - HID_USAGE_CONSUMER_AC_SELECT_OBJECT = 0x0278, - HID_USAGE_CONSUMER_AC_REDO_REPEAT = 0x0279, - HID_USAGE_CONSUMER_AC_SORT = 0x027A, - HID_USAGE_CONSUMER_AC_SORT_ASCENDING = 0x027B, - HID_USAGE_CONSUMER_AC_SORT_DESCENDING = 0x027C, - HID_USAGE_CONSUMER_AC_FILTER = 0x027D, - HID_USAGE_CONSUMER_AC_SET_CLOCK = 0x027E, - HID_USAGE_CONSUMER_AC_VIEW_CLOCK = 0x027F, - HID_USAGE_CONSUMER_AC_SELECT_TIME_ZONE = 0x0280, - HID_USAGE_CONSUMER_AC_EDIT_TIME_ZONES = 0x0281, - HID_USAGE_CONSUMER_AC_SET_ALARM = 0x0282, - HID_USAGE_CONSUMER_AC_CLEAR_ALARM = 0x0283, - HID_USAGE_CONSUMER_AC_SNOOZE_ALARM = 0x0284, - HID_USAGE_CONSUMER_AC_RESET_ALARM = 0x0285, - HID_USAGE_CONSUMER_AC_SYNCHRONIZE = 0x0286, - HID_USAGE_CONSUMER_AC_SEND_RECEIVE = 0x0287, - HID_USAGE_CONSUMER_AC_SEND_TO = 0x0288, - HID_USAGE_CONSUMER_AC_REPLY = 0x0289, - HID_USAGE_CONSUMER_AC_REPLY_ALL = 0x028A, - HID_USAGE_CONSUMER_AC_FORWARD_MSG = 0x028B, - HID_USAGE_CONSUMER_AC_SEND = 0x028C, - HID_USAGE_CONSUMER_AC_ATTACH_FILE = 0x028D, - HID_USAGE_CONSUMER_AC_UPLOAD = 0x028E, - HID_USAGE_CONSUMER_AC_DOWNLOAD_SAVE_TARGET_AS = 0x028F, - HID_USAGE_CONSUMER_AC_SET_BORDERS = 0x0290, - HID_USAGE_CONSUMER_AC_INSERT_ROW = 0x0291, - HID_USAGE_CONSUMER_AC_INSERT_COLUMN = 0x0292, - HID_USAGE_CONSUMER_AC_INSERT_FILE = 0x0293, - HID_USAGE_CONSUMER_AC_INSERT_PICTURE = 0x0294, - HID_USAGE_CONSUMER_AC_INSERT_OBJECT = 0x0295, - HID_USAGE_CONSUMER_AC_INSERT_SYMBOL = 0x0296, - HID_USAGE_CONSUMER_AC_SAVE_AND_CLOSE = 0x0297, - HID_USAGE_CONSUMER_AC_RENAME = 0x0298, - HID_USAGE_CONSUMER_AC_MERGE = 0x0299, - HID_USAGE_CONSUMER_AC_SPLIT = 0x029A, - HID_USAGE_CONSUMER_AC_DISRIBUTE_HORIZONTALLY = 0x029B, - HID_USAGE_CONSUMER_AC_DISTRIBUTE_VERTICALLY = 0x029C, - // 29D-FFFF Reserved + HID_USAGE_CONSUMER_AL_INSTANT_MESSAGING = 0x01BC, // Sel + HID_USAGE_CONSUMER_AL_OEM_FEATURES_TIPS_TUTORIAL = 0x01BD, // Sel + HID_USAGE_CONSUMER_AL_OEM_HELP = 0x01BE, // Sel + HID_USAGE_CONSUMER_AL_ONLINE_COMMUNITY = 0x01BF, // Sel + HID_USAGE_CONSUMER_AL_ENTERTAINMENT_CONTENT = 0x01C0, // Sel + HID_USAGE_CONSUMER_AL_ONLINE_SHOPPING_BROWSER = 0x01C1, // Sel + HID_USAGE_CONSUMER_AL_SMARTCARD_INFORMATION_HELP = 0x01C2, // Sel + HID_USAGE_CONSUMER_AL_MARKET_MONITOR_FINANCE = 0x01C3, // Sel + HID_USAGE_CONSUMER_AL_CUSTOMIZED_CORPORATE_NEWS = 0x01C4, // Sel + HID_USAGE_CONSUMER_AL_ONLINE_ACTIVITY_BROWSER = 0x01C5, // Sel + HID_USAGE_CONSUMER_AL_RESEARCH_SEARCH_BROWSER = 0x01C6, // Sel + HID_USAGE_CONSUMER_AL_AUDIO_PLAYER = 0x01C7, // Sel + HID_USAGE_CONSUMER_AL_MESSAGE_STATUS = 0x01C8, // Sel + HID_USAGE_CONSUMER_AL_CONTACT_SYNC = 0x01C9, // Sel + HID_USAGE_CONSUMER_AL_NAVIGATION = 0x01CA, // Sel + HID_USAGE_CONSUMER_AL_CONTEXT_AWARE_DESKTOP_ASSISTANT = 0x01CB, // Sel + // 1CC-1FF Reserved + HID_USAGE_CONSUMER_GENERIC_GUI_APPLICATION = 0x0200, // NAry + HID_USAGE_CONSUMER_AC_NEW = 0x0201, // Sel + HID_USAGE_CONSUMER_AC_OPEN = 0x0202, // Sel + HID_USAGE_CONSUMER_AC_CLOSE = 0x0203, // Sel + HID_USAGE_CONSUMER_AC_EXIT = 0x0204, // Sel + HID_USAGE_CONSUMER_AC_MAXIMIZE = 0x0205, // Sel + HID_USAGE_CONSUMER_AC_MINIMIZE = 0x0206, // Sel + HID_USAGE_CONSUMER_AC_SAVE = 0x0207, // Sel + HID_USAGE_CONSUMER_AC_PRINT = 0x0208, // Sel + HID_USAGE_CONSUMER_AC_PROPERTIES = 0x0209, // Sel + // 20A-219 Reserved + HID_USAGE_CONSUMER_AC_UNDO = 0x021A, // Sel + HID_USAGE_CONSUMER_AC_COPY = 0x021B, // Sel + HID_USAGE_CONSUMER_AC_CUT = 0x021C, // Sel + HID_USAGE_CONSUMER_AC_PASTE = 0x021D, // Sel + HID_USAGE_CONSUMER_AC_SELECT_ALL = 0x021E, // Sel + HID_USAGE_CONSUMER_AC_FIND = 0x021F, // Sel + HID_USAGE_CONSUMER_AC_FIND_AND_REPLACE = 0x0220, // Sel + HID_USAGE_CONSUMER_AC_SEARCH = 0x0221, // Sel + HID_USAGE_CONSUMER_AC_GO_TO = 0x0222, // Sel + HID_USAGE_CONSUMER_AC_HOME = 0x0223, // Sel + HID_USAGE_CONSUMER_AC_BACK = 0x0224, // Sel + HID_USAGE_CONSUMER_AC_FORWARD = 0x0225, // Sel + HID_USAGE_CONSUMER_AC_STOP = 0x0226, // Sel + HID_USAGE_CONSUMER_AC_REFRESH = 0x0227, // Sel + HID_USAGE_CONSUMER_AC_PREVIOUS_LINK = 0x0228, // Sel + HID_USAGE_CONSUMER_AC_NEXT_LINK = 0x0229, // Sel + HID_USAGE_CONSUMER_AC_BOOKMARKS = 0x022A, // Sel + HID_USAGE_CONSUMER_AC_HISTORY = 0x022B, // Sel + HID_USAGE_CONSUMER_AC_SUBSCRIPTIONS = 0x022C, // Sel + HID_USAGE_CONSUMER_AC_ZOOM_IN = 0x022D, // Sel + HID_USAGE_CONSUMER_AC_ZOOM_OUT = 0x022E, // Sel + HID_USAGE_CONSUMER_AC_ZOOM = 0x022F, // LC + HID_USAGE_CONSUMER_AC_FULL_SCREEN_VIEW = 0x0230, // Sel + HID_USAGE_CONSUMER_AC_NORMAL_VIEW = 0x0231, // Sel + HID_USAGE_CONSUMER_AC_VIEW_TOGGLE = 0x0232, // Sel + HID_USAGE_CONSUMER_AC_SCROLL_UP = 0x0233, // Sel + HID_USAGE_CONSUMER_AC_SCROLL_DOWN = 0x0234, // Sel + HID_USAGE_CONSUMER_AC_SCROLL = 0x0235, // LC + HID_USAGE_CONSUMER_AC_PAN_LEFT = 0x0236, // Sel + HID_USAGE_CONSUMER_AC_PAN_RIGHT = 0x0237, // Sel + HID_USAGE_CONSUMER_AC_PAN = 0x0238, // LC + HID_USAGE_CONSUMER_AC_NEW_WINDOW = 0x0239, // Sel + HID_USAGE_CONSUMER_AC_TILE_HORIZONTALLY = 0x023A, // Sel + HID_USAGE_CONSUMER_AC_TILE_VERTICALLY = 0x023B, // Sel + HID_USAGE_CONSUMER_AC_FORMAT = 0x023C, // Sel + HID_USAGE_CONSUMER_AC_EDIT = 0x023D, // Sel + HID_USAGE_CONSUMER_AC_BOLD = 0x023E, // Sel + HID_USAGE_CONSUMER_AC_ITALICS = 0x023F, // Sel + HID_USAGE_CONSUMER_AC_UNDERLINE = 0x0240, // Sel + HID_USAGE_CONSUMER_AC_STRIKETHROUGH = 0x0241, // Sel + HID_USAGE_CONSUMER_AC_SUBSCRIPT = 0x0242, // Sel + HID_USAGE_CONSUMER_AC_SUPERSCRIPT = 0x0243, // Sel + HID_USAGE_CONSUMER_AC_ALL_CAPS = 0x0244, // Sel + HID_USAGE_CONSUMER_AC_ROTATE = 0x0245, // Sel + HID_USAGE_CONSUMER_AC_RESIZE = 0x0246, // Sel + HID_USAGE_CONSUMER_AC_FLIP_HORIZONTAL = 0x0247, // Sel + HID_USAGE_CONSUMER_AC_FLIP_VERTICAL = 0x0248, // Sel + HID_USAGE_CONSUMER_AC_MIRROR_HORIZONTAL = 0x0249, // Sel + HID_USAGE_CONSUMER_AC_MIRROR_VERTICAL = 0x024A, // Sel + HID_USAGE_CONSUMER_AC_FONT_SELECT = 0x024B, // Sel + HID_USAGE_CONSUMER_AC_FONT_COLOR = 0x024C, // Sel + HID_USAGE_CONSUMER_AC_FONT_SIZE = 0x024D, // Sel + HID_USAGE_CONSUMER_AC_JUSTIFY_LEFT = 0x024E, // Sel + HID_USAGE_CONSUMER_AC_JUSTIFY_CENTER_H = 0x024F, // Sel + HID_USAGE_CONSUMER_AC_JUSTIFY_RIGHT = 0x0250, // Sel + HID_USAGE_CONSUMER_AC_JUSTIFY_BLOCK_H = 0x0251, // Sel + HID_USAGE_CONSUMER_AC_JUSTIFY_TOP = 0x0252, // Sel + HID_USAGE_CONSUMER_AC_JUSTIFY_CENTER_V = 0x0253, // Sel + HID_USAGE_CONSUMER_AC_JUSTIFY_BOTTOM = 0x0254, // Sel + HID_USAGE_CONSUMER_AC_JUSTIFY_BLOCK_V = 0x0255, // Sel + HID_USAGE_CONSUMER_AC_INDENT_DECREASE = 0x0256, // Sel + HID_USAGE_CONSUMER_AC_INDENT_INCREASE = 0x0257, // Sel + HID_USAGE_CONSUMER_AC_NUMBERED_LIST = 0x0258, // Sel + HID_USAGE_CONSUMER_AC_RESTART_NUMBERING = 0x0259, // Sel + HID_USAGE_CONSUMER_AC_BULLETED_LIST = 0x025A, // Sel + HID_USAGE_CONSUMER_AC_PROMOTE = 0x025B, // Sel + HID_USAGE_CONSUMER_AC_DEMOTE = 0x025C, // Sel + HID_USAGE_CONSUMER_AC_YES = 0x025D, // Sel + HID_USAGE_CONSUMER_AC_NO = 0x025E, // Sel + HID_USAGE_CONSUMER_AC_CANCEL = 0x025F, // Sel + HID_USAGE_CONSUMER_AC_CATALOG = 0x0260, // Sel + HID_USAGE_CONSUMER_AC_BUY_CHECKOUT = 0x0261, // Sel + HID_USAGE_CONSUMER_AC_ADD_TO_CART = 0x0262, // Sel + HID_USAGE_CONSUMER_AC_EXPAND = 0x0263, // Sel + HID_USAGE_CONSUMER_AC_EXPAND_ALL = 0x0264, // Sel + HID_USAGE_CONSUMER_AC_COLLAPSE = 0x0265, // Sel + HID_USAGE_CONSUMER_AC_COLLAPSE_ALL = 0x0266, // Sel + HID_USAGE_CONSUMER_AC_PRINT_PREVIEW = 0x0267, // Sel + HID_USAGE_CONSUMER_AC_PASTE_SPECIAL = 0x0268, // Sel + HID_USAGE_CONSUMER_AC_INSERT_MODE = 0x0269, // Sel + HID_USAGE_CONSUMER_AC_DELETE = 0x026A, // Sel + HID_USAGE_CONSUMER_AC_LOCK = 0x026B, // Sel + HID_USAGE_CONSUMER_AC_UNLOCK = 0x026C, // Sel + HID_USAGE_CONSUMER_AC_PROTECT = 0x026D, // Sel + HID_USAGE_CONSUMER_AC_UNPROTECT = 0x026E, // Sel + HID_USAGE_CONSUMER_AC_ATTACH_COMMENT = 0x026F, // Sel + HID_USAGE_CONSUMER_AC_DELETE_COMMENT = 0x0270, // Sel + HID_USAGE_CONSUMER_AC_VIEW_COMMENT = 0x0271, // Sel + HID_USAGE_CONSUMER_AC_SELECT_WORD = 0x0272, // Sel + HID_USAGE_CONSUMER_AC_SELECT_SENTENCE = 0x0273, // Sel + HID_USAGE_CONSUMER_AC_SELECT_PARAGRAPH = 0x0274, // Sel + HID_USAGE_CONSUMER_AC_SELECT_COLUMN = 0x0275, // Sel + HID_USAGE_CONSUMER_AC_SELECT_ROW = 0x0276, // Sel + HID_USAGE_CONSUMER_AC_SELECT_TABLE = 0x0277, // Sel + HID_USAGE_CONSUMER_AC_SELECT_OBJECT = 0x0278, // Sel + HID_USAGE_CONSUMER_AC_REDO_REPEAT = 0x0279, // Sel + HID_USAGE_CONSUMER_AC_SORT = 0x027A, // Sel + HID_USAGE_CONSUMER_AC_SORT_ASCENDING = 0x027B, // Sel + HID_USAGE_CONSUMER_AC_SORT_DESCENDING = 0x027C, // Sel + HID_USAGE_CONSUMER_AC_FILTER = 0x027D, // Sel + HID_USAGE_CONSUMER_AC_SET_CLOCK = 0x027E, // Sel + HID_USAGE_CONSUMER_AC_VIEW_CLOCK = 0x027F, // Sel + HID_USAGE_CONSUMER_AC_SELECT_TIME_ZONE = 0x0280, // Sel + HID_USAGE_CONSUMER_AC_EDIT_TIME_ZONES = 0x0281, // Sel + HID_USAGE_CONSUMER_AC_SET_ALARM = 0x0282, // Sel + HID_USAGE_CONSUMER_AC_CLEAR_ALARM = 0x0283, // Sel + HID_USAGE_CONSUMER_AC_SNOOZE_ALARM = 0x0284, // Sel + HID_USAGE_CONSUMER_AC_RESET_ALARM = 0x0285, // Sel + HID_USAGE_CONSUMER_AC_SYNCHRONIZE = 0x0286, // Sel + HID_USAGE_CONSUMER_AC_SEND_RECEIVE = 0x0287, // Sel + HID_USAGE_CONSUMER_AC_SEND_TO = 0x0288, // Sel + HID_USAGE_CONSUMER_AC_REPLY = 0x0289, // Sel + HID_USAGE_CONSUMER_AC_REPLY_ALL = 0x028A, // Sel + HID_USAGE_CONSUMER_AC_FORWARD_MSG = 0x028B, // Sel + HID_USAGE_CONSUMER_AC_SEND = 0x028C, // Sel + HID_USAGE_CONSUMER_AC_ATTACH_FILE = 0x028D, // Sel + HID_USAGE_CONSUMER_AC_UPLOAD = 0x028E, // Sel + HID_USAGE_CONSUMER_AC_DOWNLOAD_SAVE_TARGET_AS = 0x028F, // Sel + HID_USAGE_CONSUMER_AC_SET_BORDERS = 0x0290, // Sel + HID_USAGE_CONSUMER_AC_INSERT_ROW = 0x0291, // Sel + HID_USAGE_CONSUMER_AC_INSERT_COLUMN = 0x0292, // Sel + HID_USAGE_CONSUMER_AC_INSERT_FILE = 0x0293, // Sel + HID_USAGE_CONSUMER_AC_INSERT_PICTURE = 0x0294, // Sel + HID_USAGE_CONSUMER_AC_INSERT_OBJECT = 0x0295, // Sel + HID_USAGE_CONSUMER_AC_INSERT_SYMBOL = 0x0296, // Sel + HID_USAGE_CONSUMER_AC_SAVE_AND_CLOSE = 0x0297, // Sel + HID_USAGE_CONSUMER_AC_RENAME = 0x0298, // Sel + HID_USAGE_CONSUMER_AC_MERGE = 0x0299, // Sel + HID_USAGE_CONSUMER_AC_SPLIT = 0x029A, // Sel + HID_USAGE_CONSUMER_AC_DISRIBUTE_HORIZONTALLY = 0x029B, // Sel + HID_USAGE_CONSUMER_AC_DISTRIBUTE_VERTICALLY = 0x029C, // Sel + HID_USAGE_CONSUMER_AC_NEXT_KEYBOARD_LAYOUT_SELECT = 0x029D, // Sel + HID_USAGE_CONSUMER_AC_NAVIGATION_GUIDANCE = 0x029E, // Sel + HID_USAGE_CONSUMER_AC_DESKTOP_SHOW_ALL_WINDOWS = 0x029F, // Sel + HID_USAGE_CONSUMER_AC_SOFT_KEY_LEFT = 0x02A0, // Sel + HID_USAGE_CONSUMER_AC_SOFT_KEY_RIGHT = 0x02A1, // Sel + HID_USAGE_CONSUMER_AC_DESKTOP_SHOW_ALL_APPLICATIONS = 0x02A2, // Sel + // 2A3-2AF Reserved + HID_USAGE_CONSUMER_AC_IDLE_KEEP_ALIVE = 0x02B0, // Sel + // 2B1-2BF Reserved + HID_USAGE_CONSUMER_EXTENDED_KEYBOARD_ATTRIBUTES_COLLECTION = 0x02C0, // CL + HID_USAGE_CONSUMER_KEYBOARD_FORM_FACTOR = 0x02C1, // SV + HID_USAGE_CONSUMER_KEYBOARD_KEY_TYPE = 0x02C2, // SV + HID_USAGE_CONSUMER_KEYBOARD_PHYSICAL_LAYOUT = 0x02C3, // SV + HID_USAGE_CONSUMER_VENDOR_SPECIFIC_KEYBOARD_PHYSICAL_LAYOUT = 0x02C4, // SV + HID_USAGE_CONSUMER_KEYBOARD_IETF_LANGUAGE_TAG_INDEX = 0x02C5, // SV + HID_USAGE_CONSUMER_IMPLEMENTED_KEYBOARD_INPUT_ASSIST_CONTROLS = 0x02C6, // SV + HID_USAGE_CONSUMER_KEYBOARD_INPUT_ASSIST_PREVIOUS = 0x02C7, // Sel + HID_USAGE_CONSUMER_KEYBOARD_INPUT_ASSIST_NEXT = 0x02C8, // Sel + HID_USAGE_CONSUMER_KEYBOARD_INPUT_ASSIST_PREVIOUS_GROUP = 0x02C9, // Sel + HID_USAGE_CONSUMER_KEYBOARD_INPUT_ASSIST_NEXT_GROUP = 0x02CA, // Sel + HID_USAGE_CONSUMER_KEYBOARD_INPUT_ASSIST_ACCEPT = 0x02CB, // Sel + HID_USAGE_CONSUMER_KEYBOARD_INPUT_ASSIST_CANCEL = 0x02CC, // Sel + // 2CD-2CF Reserved + HID_USAGE_CONSUMER_PRIVACY_SCREEN_TOGGLE = 0x02D0, // OOC + HID_USAGE_CONSUMER_PRIVACY_SCREEN_LEVEL_DECREMENT = 0x02D1, // RTC + HID_USAGE_CONSUMER_PRIVACY_SCREEN_LEVEL_INCREMENT = 0x02D2, // RTC + HID_USAGE_CONSUMER_PRIVACY_SCREEN_LEVEL_MINIMUM = 0x02D3, // OSC + HID_USAGE_CONSUMER_PRIVACY_SCREEN_LEVEL_MAXIMUM = 0x02D4, // OSC + // 2D5-4FF Reserved + HID_USAGE_CONSUMER_CONTACT_EDITED = 0x0500, // OOC + HID_USAGE_CONSUMER_CONTACT_ADDED = 0x0501, // OOC + HID_USAGE_CONSUMER_CONTACT_RECORD_ACTIVE = 0x0502, // OOC + HID_USAGE_CONSUMER_CONTACT_INDEX = 0x0503, // DV + HID_USAGE_CONSUMER_CONTACT_NICKNAME = 0x0504, // DV + HID_USAGE_CONSUMER_CONTACT_FIRST_NAME = 0x0505, // DV + HID_USAGE_CONSUMER_CONTACT_LAST_NAME = 0x0506, // DV + HID_USAGE_CONSUMER_CONTACT_FULL_NAME = 0x0507, // DV + HID_USAGE_CONSUMER_CONTACT_PHONE_NUMBER_PERSONAL = 0x0508, // DV + HID_USAGE_CONSUMER_CONTACT_PHONE_NUMBER_BUSINESS = 0x0509, // DV + HID_USAGE_CONSUMER_CONTACT_PHONE_NUMBER_MOBILE = 0x050A, // DV + HID_USAGE_CONSUMER_CONTACT_PHONE_NUMBER_PAGER = 0x050B, // DV + HID_USAGE_CONSUMER_CONTACT_PHONE_NUMBER_FAX = 0x050C, // DV + HID_USAGE_CONSUMER_CONTACT_PHONE_NUMBER_OTHER = 0x050D, // DV + HID_USAGE_CONSUMER_CONTACT_EMAIL_PERSONAL = 0x050E, // DV + HID_USAGE_CONSUMER_CONTACT_EMAIL_BUSINESS = 0x050F, // DV + HID_USAGE_CONSUMER_CONTACT_EMAIL_OTHER = 0x0510, // DV + HID_USAGE_CONSUMER_CONTACT_EMAIL_MAIN = 0x0511, // DV + HID_USAGE_CONSUMER_CONTACT_SPEED_DIAL_NUMBER = 0x0512, // DV + HID_USAGE_CONSUMER_CONTACT_STATUS_FLAG = 0x0513, // DV + HID_USAGE_CONSUMER_CONTACT_MISC = 0x0514, // DV + HID_USAGE_CONSUMER_KEYBOARD_BRIGHTNESS_NEXT = 0x0515, // OSC + HID_USAGE_CONSUMER_KEYBOARD_BRIGHTNESS_PREVIOUS = 0x0516, // OSC + HID_USAGE_CONSUMER_KEYBOARD_BACKLIGHT_LEVEL_SUGGESTION = 0x0517, // SV + // 518-FFFF Reserved + // For Backwards compatibility to prevent current builds from breaking + HID_USAGE_CONSUMER_BRIGHTNESS_INCREMENT = HID_USAGE_CONSUMER_DISPLAY_BRIGHTNESS_INCREMENT, // RTC + HID_USAGE_CONSUMER_BRIGHTNESS_DECREMENT = HID_USAGE_CONSUMER_DISPLAY_BRIGHTNESS_DECREMENT, // RTC }; /// HID Usage Table: Digitizer Page (0x0D) @@ -1390,6 +1935,7 @@ enum { HID_USAGE_DIGITIZER_SURFACE_SWITCH = 0x57, // DF HID_USAGE_DIGITIZER_BUTTON_SWITCH = 0x58, // DF HID_USAGE_DIGITIZER_PAD_TYPE = 0x59, // SF + HID_USAGE_DIGITIZER_SECONDARY_BARREL_SWITCH = 0x5A, // MC HID_USAGE_DIGITIZER_TRANSDUCER_SERIAL_NUMBER = 0x5B, // SV HID_USAGE_DIGITIZER_PREFERRED_COLOR = 0x5C, // DV HID_USAGE_DIGITIZER_PREFERRED_COLOR_LOCKED = 0x5D, // MC @@ -1450,151 +1996,500 @@ enum { // Reserved (0xB1 - 0xFFFF) }; +/// HID Usage Table: Haptics Page (0x0E) +enum{ + HID_USAGE_HAPTICS_SIMPLE_HAPTIC_CONTROLLER = 0x0001, // CA/CL + // Reserved (0x0002 - 0x000F) + HID_USAGE_HAPTICS_WAVEFORM_LIST = 0x0010, // NAry + HID_USAGE_HAPTICS_DURATION_LIST = 0x0011, // NAry + // Reserved (0x0012 - 0x001F) + HID_USAGE_HAPTICS_AUTO_TRIGGER = 0x0020, // DV + HID_USAGE_HAPTICS_MANUAL_TRIGGER = 0x0021, // DV + HID_USAGE_HAPTICS_AUTO_TRIGGER_ASSOCIATED_CONTROL = 0x0022, // SV + HID_USAGE_HAPTICS_INTENSITY = 0x0023, // DV + HID_USAGE_HAPTICS_REPEAT_COUNT = 0x0024, // DV + HID_USAGE_HAPTICS_RETRIGGER_PERIOD = 0x0025, // DV + HID_USAGE_HAPTICS_WAVEFORM_VENDOR_PAGE = 0x0026, // SV + HID_USAGE_HAPTICS_WAVEFORM_VENDOR_ID = 0x0027, // SV + HID_USAGE_HAPTICS_WAVEFORM_CUTOFF_TIME = 0x0028, // SV + // Reserved (0x0029 - 0x1000) + HID_USAGE_HAPTICS_WAVEFORM_NONE = 0x1001, // SV + HID_USAGE_HAPTICS_WAVEFORM_STOP = 0x1002, // SV + HID_USAGE_HAPTICS_WAVEFORM_CLICK = 0x1003, // SV + HID_USAGE_HAPTICS_WAVEFORM_BUZZ_CONTINUOUS = 0x1004, // SV + HID_USAGE_HAPTICS_WAVEFORM_RUMBLE_CONTINUOUS = 0x1005, // SV + HID_USAGE_HAPTICS_WAVEFORM_PRESS = 0x1006, // SV + HID_USAGE_HAPTICS_WAVEFORM_RELEASE = 0x1007, // SV + HID_USAGE_HAPTICS_WAVEFORM_HOVER = 0x1008, // SV + HID_USAGE_HAPTICS_WAVEFORM_SUCCESS = 0x1009, // SV + HID_USAGE_HAPTICS_WAVEFORM_ERROR = 0x100A, // SV + HID_USAGE_HAPTICS_WAVEFORM_INK_CONTINUOUS = 0x100B, // SV + HID_USAGE_HAPTICS_WAVEFORM_PENCIL_CONTINUOUS = 0x100C, // SV + HID_USAGE_HAPTICS_WAVEFORM_MARKER_CONTINUOUS = 0x100D, // SV + HID_USAGE_HAPTICS_WAVEFORM_CHISEL_MARKER_CONTINUOUS = 0x100E, // SV + HID_USAGE_HAPTICS_WAVEFORM_BRUSH_CONTINUOUS = 0x100F, // SV + HID_USAGE_HAPTICS_WAVEFORM_ERASER_CONTINUOUS = 0x1010, // SV + HID_USAGE_HAPTICS_WAVEFORM_SPARKLE_CONTINUOUS = 0x1011, // SV + // Reserved (0x1012 - 0xFFFF) +}; + /// HID Usage Table: Physical Input Device Page (0x0F) enum { HID_USAGE_PID_UNDEFINED = 0x00, - HID_USAGE_PID_PHYSICAL_INPUT_DEVICE = 0x01, - HID_USAGE_PID_NORMAL = 0x20, - HID_USAGE_PID_SET_EFFECT_REPORT = 0x21, - HID_USAGE_PID_EFFECT_PARAMETER_BLOCK_INDEX = 0x22, - HID_USAGE_PID_PARAMETER_BLOCK_OFFSET = 0x23, - HID_USAGE_PID_ROM_FLAG = 0x24, - HID_USAGE_PID_EFFECT_TYPE = 0x25, - HID_USAGE_PID_ET_CONSTANTFORCE = 0x26, - HID_USAGE_PID_ET_RAMP = 0x27, - HID_USAGE_PID_ET_CUSTOMFORCE = 0x28, - HID_USAGE_PID_ET_SQUARE = 0x30, - HID_USAGE_PID_ET_SINE = 0x31, - HID_USAGE_PID_ET_TRIANGLE = 0x32, - HID_USAGE_PID_ET_SAWTOOTH_UP = 0x33, - HID_USAGE_PID_ET_SAWTOOTH_DOWN = 0x34, - HID_USAGE_PID_ET_SPRING = 0x40, - HID_USAGE_PID_ET_DAMPER = 0x41, - HID_USAGE_PID_ET_INERTIA = 0x42, - HID_USAGE_PID_ET_FRICTION = 0x43, - HID_USAGE_PID_DURATION = 0x50, - HID_USAGE_PID_SAMPLE_PERIOD = 0x51, - HID_USAGE_PID_GAIN = 0x52, - HID_USAGE_PID_TRIGGER_BUTTON = 0x53, - HID_USAGE_PID_TRIGGER_REPEAT_INTERVAL = 0x54, - HID_USAGE_PID_AXES_ENABLE = 0x55, - HID_USAGE_PID_DIRECTION_ENABLE = 0x56, - HID_USAGE_PID_DIRECTION = 0x57, - HID_USAGE_PID_TYPE_SPECIFIC_BLOCK_OFFSET = 0x58, - HID_USAGE_PID_BLOCK_TYPE = 0x59, - HID_USAGE_PID_SET_ENVELOPE_REPORT = 0x5a, - HID_USAGE_PID_ATTACK_LEVEL = 0x5b, - HID_USAGE_PID_ATTACK_TIME = 0x5c, - HID_USAGE_PID_FADE_LEVEL = 0x5d, - HID_USAGE_PID_FADE_TIME = 0x5e, - HID_USAGE_PID_SET_CONDITION_REPORT = 0x5f, - HID_USAGE_PID_CENTERPOINT_OFFSET = 0x60, - HID_USAGE_PID_POSITIVE_COEFFICIENT = 0x61, - HID_USAGE_PID_NEGATIVE_COEFFICIENT = 0x62, - HID_USAGE_PID_POSITIVE_SATURATION = 0x63, - HID_USAGE_PID_NEGATIVE_SATURATION = 0x64, - HID_USAGE_PID_DEAD_BAND = 0x65, - HID_USAGE_PID_DOWNLOAD_FORCE_SAMPLE = 0x66, - HID_USAGE_PID_ISOCH_CUSTOMFORCE_ENABLE = 0x67, - HID_USAGE_PID_CUSTOMFORCE_DATA_REPORT = 0x68, - HID_USAGE_PID_CUSTOMFORCE_DATA = 0x69, - HID_USAGE_PID_CUSTOMFORCE_VENDOR_DEFINED_DATA = 0x6a, - HID_USAGE_PID_SET_CUSTOMFORCE_REPORT = 0x6b, - HID_USAGE_PID_CUSTOMFORCE_DATA_OFFSET = 0x6c, - HID_USAGE_PID_SAMPLE_COUNT = 0x6d, - HID_USAGE_PID_SET_PERIODIC_REPORT = 0x6e, - HID_USAGE_PID_OFFSET = 0x6f, - HID_USAGE_PID_MAGNITUDE = 0x70, - HID_USAGE_PID_PHASE = 0x71, - HID_USAGE_PID_PERIOD = 0x72, - HID_USAGE_PID_SET_CONSTANTFORCE_REPORT = 0x73, - HID_USAGE_PID_SET_RAMPFORCE_REPORT = 0x74, - HID_USAGE_PID_RAMP_START = 0x75, - HID_USAGE_PID_RAMP_END = 0x76, - HID_USAGE_PID_EFFECT_OPERATION_REPORT = 0x77, - HID_USAGE_PID_EFFECT_OPERATION = 0x78, - HID_USAGE_PID_OP_EFFECT_START = 0x79, - HID_USAGE_PID_OP_EFFECT_START_SOLO = 0x7a, - HID_USAGE_PID_OP_EFFECT_STOP = 0x7b, - HID_USAGE_PID_LOOP_COUNT = 0x7c, - HID_USAGE_PID_DEVICE_GAIN_REPORT = 0x7d, - HID_USAGE_PID_DEVICE_GAIN = 0x7e, - HID_USAGE_PID_PARAMETER_BLOCK_POOLS_REPORT = 0x7f, - HID_USAGE_PID_RAM_POOL_SIZE = 0x80, - HID_USAGE_PID_ROM_POOL_SIZE = 0x81, - HID_USAGE_PID_ROM_EFFECT_BLOCK_COUNT = 0x82, - HID_USAGE_PID_SIMULTANEOUS_EFFECTS_MAX = 0x83, - HID_USAGE_PID_POOL_ALIGNMENT = 0x84, - HID_USAGE_PID_PARAMETER_BLOCK_MOVE_REPORT = 0x85, - HID_USAGE_PID_MOVE_SOURCE = 0x86, - HID_USAGE_PID_MOVE_DESTINATION = 0x87, - HID_USAGE_PID_MOVE_LENGTH = 0x88, - HID_USAGE_PID_EFFECT_PARAMETER_BLOCK_LOAD_REPORT = 0x89, - HID_USAGE_PID_EFFECT_PARAMETER_BLOCK_LOAD_STATUS = 0x8b, - HID_USAGE_PID_BLOCK_LOAD_SUCCESS = 0x8c, - HID_USAGE_PID_BLOCK_LOAD_FULL = 0x8d, - HID_USAGE_PID_BLOCK_LOAD_ERROR = 0x8e, - HID_USAGE_PID_BLOCK_HANDLE = 0x8f, - HID_USAGE_PID_EFFECT_PARAMETER_BLOCK_FREE_REPORT = 0x90, - HID_USAGE_PID_TYPE_SPECIFIC_BLOCK_HANDLE = 0x91, - HID_USAGE_PID_PID_STATE_REPORT = 0x92, - HID_USAGE_PID_EFFECT_PLAYING = 0x94, - HID_USAGE_PID_PID_DEVICE_CONTROL_REPORT = 0x95, - HID_USAGE_PID_PID_DEVICE_CONTROL = 0x96, - HID_USAGE_PID_DC_ENABLE_ACTUATORS = 0x97, - HID_USAGE_PID_DC_DISABLE_ACTUATORS = 0x98, - HID_USAGE_PID_DC_STOP_ALL_EFFECTS = 0x99, - HID_USAGE_PID_DC_RESET = 0x9a, - HID_USAGE_PID_DC_PAUSE = 0x9b, - HID_USAGE_PID_DC_CONTINUE = 0x9c, - HID_USAGE_PID_DEVICE_PAUSED = 0x9f, - HID_USAGE_PID_ACTUATORS_ENABLED = 0xa0, - HID_USAGE_PID_SAFETY_SWITCH = 0xa4, - HID_USAGE_PID_ACTUATOR_OVERRIDE_SWITCH = 0xa5, - HID_USAGE_PID_ACTUATOR_POWER = 0xa6, - HID_USAGE_PID_START_DELAY = 0xa7, - HID_USAGE_PID_PARAMETER_BLOCK_SIZE = 0xa8, - HID_USAGE_PID_DEVICEMANAGED_POOL = 0xa9, - HID_USAGE_PID_SHARED_PARAMETER_BLOCKS = 0xaa, - HID_USAGE_PID_CREATE_NEW_EFFECT_PARAMETER_BLOCK_REPORT = 0xab, - HID_USAGE_PID_RAM_POOL_AVAILABLE = 0xac, + HID_USAGE_PID_PHYSICAL_INPUT_DEVICE = 0x01, // CA + // Reserved (0x02 - 0x1F) + HID_USAGE_PID_NORMAL = 0x20, // DV + HID_USAGE_PID_SET_EFFECT_REPORT = 0x21, // CL + HID_USAGE_PID_EFFECT_PARAMETER_BLOCK_INDEX = 0x22, // DV + HID_USAGE_PID_PARAMETER_BLOCK_OFFSET = 0x23, // DV + HID_USAGE_PID_ROM_FLAG = 0x24, // DF + HID_USAGE_PID_EFFECT_TYPE = 0x25, // NAry + HID_USAGE_PID_ET_CONSTANTFORCE = 0x26, // Sel + HID_USAGE_PID_ET_RAMP = 0x27, // Sel + HID_USAGE_PID_ET_CUSTOMFORCE = 0x28, // Sel + // Reserved (0x29 - 0x2F) + HID_USAGE_PID_ET_SQUARE = 0x30, // Sel + HID_USAGE_PID_ET_SINE = 0x31, // Sel + HID_USAGE_PID_ET_TRIANGLE = 0x32, // Sel + HID_USAGE_PID_ET_SAWTOOTH_UP = 0x33, // Sel + HID_USAGE_PID_ET_SAWTOOTH_DOWN = 0x34, // Sel + // Reserved (0x35 - 0x3F) + HID_USAGE_PID_ET_SPRING = 0x40, // Sel + HID_USAGE_PID_ET_DAMPER = 0x41, // Sel + HID_USAGE_PID_ET_INERTIA = 0x42, // Sel + HID_USAGE_PID_ET_FRICTION = 0x43, // Sel + // Reserved (0x44 - 0x4F) + HID_USAGE_PID_DURATION = 0x50, // DV + HID_USAGE_PID_SAMPLE_PERIOD = 0x51, // DV + HID_USAGE_PID_GAIN = 0x52, // DV + HID_USAGE_PID_TRIGGER_BUTTON = 0x53, // DV + HID_USAGE_PID_TRIGGER_REPEAT_INTERVAL = 0x54, // DV + HID_USAGE_PID_AXES_ENABLE = 0x55, // US + HID_USAGE_PID_DIRECTION_ENABLE = 0x56, // DF + HID_USAGE_PID_DIRECTION = 0x57, // CL + HID_USAGE_PID_TYPE_SPECIFIC_BLOCK_OFFSET = 0x58, // CL + HID_USAGE_PID_BLOCK_TYPE = 0x59, // NAry + HID_USAGE_PID_SET_ENVELOPE_REPORT = 0x5A, // CL/SV + HID_USAGE_PID_ATTACK_LEVEL = 0x5B, // DV + HID_USAGE_PID_ATTACK_TIME = 0x5C, // DV + HID_USAGE_PID_FADE_LEVEL = 0x5D, // DV + HID_USAGE_PID_FADE_TIME = 0x5E, // DV + HID_USAGE_PID_SET_CONDITION_REPORT = 0x5F, // CL/SV + HID_USAGE_PID_CENTERPOINT_OFFSET = 0x60, // DV + HID_USAGE_PID_POSITIVE_COEFFICIENT = 0x61, // DV + HID_USAGE_PID_NEGATIVE_COEFFICIENT = 0x62, // DV + HID_USAGE_PID_POSITIVE_SATURATION = 0x63, // DV + HID_USAGE_PID_NEGATIVE_SATURATION = 0x64, // DV + HID_USAGE_PID_DEAD_BAND = 0x65, // DV + HID_USAGE_PID_DOWNLOAD_FORCE_SAMPLE = 0x66, // CL + HID_USAGE_PID_ISOCH_CUSTOMFORCE_ENABLE = 0x67, // DF + HID_USAGE_PID_CUSTOMFORCE_DATA_REPORT = 0x68, // CL + HID_USAGE_PID_CUSTOMFORCE_DATA = 0x69, // DV + HID_USAGE_PID_CUSTOMFORCE_VENDOR_DEFINED_DATA = 0x6A, // DV + HID_USAGE_PID_SET_CUSTOMFORCE_REPORT = 0x6B, // CL/SV + HID_USAGE_PID_CUSTOMFORCE_DATA_OFFSET = 0x6C, // DV + HID_USAGE_PID_SAMPLE_COUNT = 0x6D, // DV + HID_USAGE_PID_SET_PERIODIC_REPORT = 0x6E, // CL/SV + HID_USAGE_PID_OFFSET = 0x6F, // DV + HID_USAGE_PID_MAGNITUDE = 0x70, // DV + HID_USAGE_PID_PHASE = 0x71, // DV + HID_USAGE_PID_PERIOD = 0x72, // DV + HID_USAGE_PID_SET_CONSTANTFORCE_REPORT = 0x73, // CL/SV + HID_USAGE_PID_SET_RAMPFORCE_REPORT = 0x74, // CL/SV + HID_USAGE_PID_RAMP_START = 0x75, // DV + HID_USAGE_PID_RAMP_END = 0x76, // DV + HID_USAGE_PID_EFFECT_OPERATION_REPORT = 0x77, // CL + HID_USAGE_PID_EFFECT_OPERATION = 0x78, // NAry + HID_USAGE_PID_OP_EFFECT_START = 0x79, // Sel + HID_USAGE_PID_OP_EFFECT_START_SOLO = 0x7A, // Sel + HID_USAGE_PID_OP_EFFECT_STOP = 0x7B, // Sel + HID_USAGE_PID_LOOP_COUNT = 0x7C, // DV + HID_USAGE_PID_DEVICE_GAIN_REPORT = 0x7D, // CL + HID_USAGE_PID_DEVICE_GAIN = 0x7E, // DV + HID_USAGE_PID_PARAMETER_BLOCK_POOLS_REPORT = 0x7F, // CL + HID_USAGE_PID_RAM_POOL_SIZE = 0x80, // DV + HID_USAGE_PID_ROM_POOL_SIZE = 0x81, // SV + HID_USAGE_PID_ROM_EFFECT_BLOCK_COUNT = 0x82, // SV + HID_USAGE_PID_SIMULTANEOUS_EFFECTS_MAX = 0x83, // SV + HID_USAGE_PID_POOL_ALIGNMENT = 0x84, // SV + HID_USAGE_PID_PARAMETER_BLOCK_MOVE_REPORT = 0x85, // CL + HID_USAGE_PID_MOVE_SOURCE = 0x86, // DV + HID_USAGE_PID_MOVE_DESTINATION = 0x87, // DV + HID_USAGE_PID_MOVE_LENGTH = 0x88, // DV + HID_USAGE_PID_EFFECT_PARAMETER_BLOCK_LOAD_REPORT = 0x89, // CL + // Reserved (0x8A) + HID_USAGE_PID_EFFECT_PARAMETER_BLOCK_LOAD_STATUS = 0x8B, // NAry + HID_USAGE_PID_BLOCK_LOAD_SUCCESS = 0x8C, // Sel + HID_USAGE_PID_BLOCK_LOAD_FULL = 0x8D, // Sel + HID_USAGE_PID_BLOCK_LOAD_ERROR = 0x8E, // Sel + HID_USAGE_PID_BLOCK_HANDLE = 0x8F, // DV + HID_USAGE_PID_EFFECT_PARAMETER_BLOCK_FREE_REPORT = 0x90, // CL + HID_USAGE_PID_TYPE_SPECIFIC_BLOCK_HANDLE = 0x91, // CL + HID_USAGE_PID_PID_STATE_REPORT = 0x92, // CL + // Reserved (0x93) + HID_USAGE_PID_EFFECT_PLAYING = 0x94, // DF + HID_USAGE_PID_PID_DEVICE_CONTROL_REPORT = 0x95, // CL + HID_USAGE_PID_PID_DEVICE_CONTROL = 0x96, // NAry + HID_USAGE_PID_DC_ENABLE_ACTUATORS = 0x97, // Sel + HID_USAGE_PID_DC_DISABLE_ACTUATORS = 0x98, // Sel + HID_USAGE_PID_DC_STOP_ALL_EFFECTS = 0x99, // Sel + HID_USAGE_PID_DC_RESET = 0x9A, // Sel + HID_USAGE_PID_DC_PAUSE = 0x9B, // Sel + HID_USAGE_PID_DC_CONTINUE = 0x9C, // Sel + // Reserved (0x9D - 0x9E) + HID_USAGE_PID_DEVICE_PAUSED = 0x9F, // DF + HID_USAGE_PID_ACTUATORS_ENABLED = 0xA0, // DF + // Reserved (0xA1 - 0xA3) + HID_USAGE_PID_SAFETY_SWITCH = 0xA4, // DF + HID_USAGE_PID_ACTUATOR_OVERRIDE_SWITCH = 0xA5, // DF + HID_USAGE_PID_ACTUATOR_POWER = 0xA6, // OOC + HID_USAGE_PID_START_DELAY = 0xA7, // DV + HID_USAGE_PID_PARAMETER_BLOCK_SIZE = 0xA8, // CL + HID_USAGE_PID_DEVICEMANAGED_POOL = 0xA9, // SF + HID_USAGE_PID_SHARED_PARAMETER_BLOCKS = 0xAA, // SF + HID_USAGE_PID_CREATE_NEW_EFFECT_PARAMETER_BLOCK_REPORT = 0xAB, // CL + HID_USAGE_PID_RAM_POOL_AVAILABLE = 0xAC, // DV + // Reserved (0xAD - 0xFFFF) +}; + +/// HID Usage Table: Unicode Page (0x10) +/// Intentionally skipped + +/// HID Usage Table: SoC Page (0x11) +enum { + HID_USAGE_SOC_SOC_CONTROL = 0x01, // CA + HID_USAGE_SOC_FIRMWARE_TRANSFER = 0x02, // CL + HID_USAGE_SOC_FIRMWARE_FILE_ID = 0x03, // DV + HID_USAGE_SOC_FILE_OFFSET_IN_BYTES = 0x04, // DV + HID_USAGE_SOC_FILE_TRANSFER_SIZE_MAX_IN_BYTES = 0x05, // DV + HID_USAGE_SOC_FILE_PAYLOAD = 0x06, // DV + HID_USAGE_SOC_FILE_PAYLOAD_SIZE_IN_BYTES = 0x07, // DV + HID_USAGE_SOC_FILE_PAYLOAD_CONTAINS_LAST_BYTES = 0x08, // DF + HID_USAGE_SOC_FILE_TRANSFER_STOP = 0x09, // DF + HID_USAGE_SOC_FILE_TRANSFER_TILL_END = 0x0A // DF + // Reserved (0x0B - 0xFFFF) +}; + +/// HID Usage Table: Eye and Head Trackers Page (0x12) +enum { + HID_USAGE_EYE_AND_HEAD_TRACKER_EYE_TRACKER = 0x0001, // CA + HID_USAGE_EYE_AND_HEAD_TRACKER_HEAD_TRACKER = 0x0002, // CA + // Reserved (0x0003 - 0x000F) + HID_USAGE_EYE_AND_HEAD_TRACKER_TRACKING_DATA = 0x0010, // CP + HID_USAGE_EYE_AND_HEAD_TRACKER_CAPABILITIES = 0x0011, // CL + HID_USAGE_EYE_AND_HEAD_TRACKER_CONFIGURATION = 0x0012, // CL + HID_USAGE_EYE_AND_HEAD_TRACKER_STATUS = 0x0013, // CL + HID_USAGE_EYE_AND_HEAD_TRACKER_CONTROL = 0x0014, // CL + // Reserved (0x0015 - 0x001F) + HID_USAGE_EYE_AND_HEAD_TRACKER_SENSOR_TIMESTAMP = 0x0020, // DV + HID_USAGE_EYE_AND_HEAD_TRACKER_POSITION_X = 0x0021, // DV + HID_USAGE_EYE_AND_HEAD_TRACKER_POSITION_Y = 0x0022, // DV + HID_USAGE_EYE_AND_HEAD_TRACKER_POSITION_Z = 0x0023, // DV + HID_USAGE_EYE_AND_HEAD_TRACKER_GAZE_POINT = 0x0024, // CP + HID_USAGE_EYE_AND_HEAD_TRACKER_LEFT_EYE_POSITION = 0x0025, // CP + HID_USAGE_EYE_AND_HEAD_TRACKER_RIGHT_EYE_POSITION = 0x0026, // CP + HID_USAGE_EYE_AND_HEAD_TRACKER_HEAD_POSITION = 0x0027, // CP + HID_USAGE_EYE_AND_HEAD_TRACKER_HEAD_DIRECTION_POINT = 0x0028, // CP + HID_USAGE_EYE_AND_HEAD_TRACKER_ROTATION_ABOUT_X_AXIS = 0x0029, // DV + HID_USAGE_EYE_AND_HEAD_TRACKER_ROTATION_ABOUT_Y_AXIS = 0x002A, // DV + HID_USAGE_EYE_AND_HEAD_TRACKER_ROTATION_ABOUT_Z_AXIS = 0x002B, // DV + // Reserved (0x002C - 0x00FF) + HID_USAGE_EYE_AND_HEAD_TRACKER_TRACKER_QUALITY = 0x0100, // SV + HID_USAGE_EYE_AND_HEAD_TRACKER_MINIMUM_TRACKING_DISTANCE = 0x0101, // SV + HID_USAGE_EYE_AND_HEAD_TRACKER_OPTIMUM_TRACKING_DISTANCE = 0x0102, // SV + HID_USAGE_EYE_AND_HEAD_TRACKER_MAXIMUM_TRACKING_DISTANCE = 0x0103, // SV + HID_USAGE_EYE_AND_HEAD_TRACKER_MAXIMUM_SCREEN_PLANE_WIDTH = 0x0104, // SV + HID_USAGE_EYE_AND_HEAD_TRACKER_MAXIMUM_SCREEN_PLANE_HEIGHT = 0x0105, // SV + // Reserved (0x0106 - 0x01FF) + HID_USAGE_EYE_AND_HEAD_TRACKER_DISPLAY_MANUFACTURER_ID = 0x0200, // SV + HID_USAGE_EYE_AND_HEAD_TRACKER_DISPLAY_PRODUCT_ID = 0x0201, // SV + HID_USAGE_EYE_AND_HEAD_TRACKER_DISPLAY_SERIAL_NUMBER = 0x0202, // SV + HID_USAGE_EYE_AND_HEAD_TRACKER_DISPLAY_MANUFACTURER_DATE = 0x0203, // SV + HID_USAGE_EYE_AND_HEAD_TRACKER_CALIBRATED_SCREEN_WIDTH = 0x0204, // SV + HID_USAGE_EYE_AND_HEAD_TRACKER_CALIBRATED_SCREEN_HEIGHT = 0x0205, // SV + // Reserved (0x0206 - 0x02FF) + HID_USAGE_EYE_AND_HEAD_TRACKER_SAMPLING_FREQUENCY = 0x0300, // DV + HID_USAGE_EYE_AND_HEAD_TRACKER_CONFIGURATION_STATUS = 0x0301, // DV + // Reserved (0x0302 - 0x03FF) + HID_USAGE_EYE_AND_HEAD_TRACKER_DEVICE_MODE_REQUEST = 0x0400, // DV + // Reserved (0x0401 - 0xFFFF) +}; + +/// HID Usage Table - Auxiliary Display Page (0x14) +enum { + HID_USAGE_AUX_DISPLAY_ALPHANUMERIC_DISPLAY = 0x01, // CA + HID_USAGE_AUX_DISPLAY_AUXILIARY_DISPLAY = 0x02, // CA + // Reserved (0x03 - 0x1F) + HID_USAGE_AUX_DISPLAY_DISPLAY_ATTRIBUTES_REPORT = 0x20, // CL + HID_USAGE_AUX_DISPLAY_ASCII_CHARACTER_SET = 0x21, // SF + HID_USAGE_AUX_DISPLAY_DATA_READ_BACK = 0x22, // SF + HID_USAGE_AUX_DISPLAY_FONT_READ_BACK = 0x23, // SF + HID_USAGE_AUX_DISPLAY_DISPLAY_CONTROL_REPORT = 0x24, // CL + HID_USAGE_AUX_DISPLAY_CLEAR_DISPLAY = 0x25, // DF + HID_USAGE_AUX_DISPLAY_DISPLAY_ENABLE = 0x26, // DF + HID_USAGE_AUX_DISPLAY_SCREEN_SAVER_DELAY = 0x27, // SV/DV + HID_USAGE_AUX_DISPLAY_SCREEN_SAVER_ENABLE = 0x28, // DF + HID_USAGE_AUX_DISPLAY_VERTICAL_SCROLL = 0x29, // SF/DF + HID_USAGE_AUX_DISPLAY_HORIZONTAL_SCROLL = 0x2A, // SF/DF + HID_USAGE_AUX_DISPLAY_CHARACTER_REPORT = 0x2B, // CL + HID_USAGE_AUX_DISPLAY_DISPLAY_DATA = 0x2C, // DV + HID_USAGE_AUX_DISPLAY_DISPLAY_STATUS = 0x2D, // CL + HID_USAGE_AUX_DISPLAY_STAT_NOT_READY = 0x2E, // Sel + HID_USAGE_AUX_DISPLAY_STAT_READY = 0x2F, // Sel + HID_USAGE_AUX_DISPLAY_ERR_NOT_A_LOADABLE_CHARACTER = 0x30, // Sel + HID_USAGE_AUX_DISPLAY_ERR_FONT_DATA_CANNOT_BE_READ = 0x31, // Sel + HID_USAGE_AUX_DISPLAY_CURSOR_POSITION_REPORT = 0x32, // Sel + HID_USAGE_AUX_DISPLAY_ROW = 0x33, // DV + HID_USAGE_AUX_DISPLAY_COLUMN = 0x34, // DV + HID_USAGE_AUX_DISPLAY_ROWS = 0x35, // SV + HID_USAGE_AUX_DISPLAY_COLUMNS = 0x36, // SV + HID_USAGE_AUX_DISPLAY_CURSOR_PIXEL_POSITIONING = 0x37, // SF + HID_USAGE_AUX_DISPLAY_CURSOR_MODE = 0x38, // DF + HID_USAGE_AUX_DISPLAY_CURSOR_ENABLE = 0x39, // DF + HID_USAGE_AUX_DISPLAY_CURSOR_BLINK = 0x3A, // DF + HID_USAGE_AUX_DISPLAY_FONT_REPORT = 0x3B, // CL + HID_USAGE_AUX_DISPLAY_FONT_DATA = 0x3C, // Buffered Bytes + HID_USAGE_AUX_DISPLAY_CHARACTER_WIDTH = 0x3D, // SV + HID_USAGE_AUX_DISPLAY_CHARACTER_HEIGHT = 0x3E, // SV + HID_USAGE_AUX_DISPLAY_CHARACTER_SPACING_HORIZONTAL = 0x3F, // SV + HID_USAGE_AUX_DISPLAY_CHARACTER_SPACING_VERTICAL = 0x40, // SV + HID_USAGE_AUX_DISPLAY_UNICODE_CHARACTER_SET = 0x41, // SF + HID_USAGE_AUX_DISPLAY_FONT_7_SEGMENT = 0x42, // SF + HID_USAGE_AUX_DISPLAY_7_SEGMENT_DIRECT_MAP = 0x43, // SF + HID_USAGE_AUX_DISPLAY_FONT_14_SEGMENT = 0x44, // SF + HID_USAGE_AUX_DISPLAY_14_SEGMENT_DIRECT_MAP = 0x45, // SF + HID_USAGE_AUX_DISPLAY_DISPLAY_BRIGHTNESS = 0x46, // DV + HID_USAGE_AUX_DISPLAY_DISPLAY_CONTRAST = 0x47, // DV + HID_USAGE_AUX_DISPLAY_CHARACTER_ATTRIBUTE = 0x48, // CL + HID_USAGE_AUX_DISPLAY_ATTRIBUTE_READBACK = 0x49, // SF + HID_USAGE_AUX_DISPLAY_ATTRIBUTE_DATA = 0x4A, // DV + HID_USAGE_AUX_DISPLAY_CHAR_ATTR_ENHANCE = 0x4B, // OOC + HID_USAGE_AUX_DISPLAY_CHAR_ATTR_UNDERLINE = 0x4C, // OOC + HID_USAGE_AUX_DISPLAY_CHAR_ATTR_BLINK = 0x4D, // OOC + // Reserved (0x4E - 0x7F) + HID_USAGE_AUX_DISPLAY_BITMAP_SIZE_X = 0x80, // SV + HID_USAGE_AUX_DISPLAY_BITMAP_SIZE_Y = 0x81, // SV + HID_USAGE_AUX_DISPLAY_MAX_BLIT_SIZE = 0x82, // SV + HID_USAGE_AUX_DISPLAY_BIT_DEPTH_FORMAT = 0x83, // SV + HID_USAGE_AUX_DISPLAY_DISPLAY_ORIENTATION = 0x84, // DV + HID_USAGE_AUX_DISPLAY_PALETTE_REPORT = 0x85, // CL + HID_USAGE_AUX_DISPLAY_PALETTE_DATA_SIZE = 0x86, // SV + HID_USAGE_AUX_DISPLAY_PALETTE_DATA_OFFSET = 0x87, // SV + HID_USAGE_AUX_DISPLAY_PALETTE_DATA = 0x88, // Buffered Bytes + // Reserved (0x89) + HID_USAGE_AUX_DISPLAY_BLIT_REPORT = 0x8A, // CL + HID_USAGE_AUX_DISPLAY_BLIT_RECTANGLE_X1 = 0x8B, // SV + HID_USAGE_AUX_DISPLAY_BLIT_RECTANGLE_Y1 = 0x8C, // SV + HID_USAGE_AUX_DISPLAY_BLIT_RECTANGLE_X2 = 0x8D, // SV + HID_USAGE_AUX_DISPLAY_BLIT_RECTANGLE_Y2 = 0x8E, // SV + HID_USAGE_AUX_DISPLAY_BLIT_DATA = 0x8F, // Buffered Bytes + HID_USAGE_AUX_DISPLAY_SOFT_BUTTON = 0x90, // CL + HID_USAGE_AUX_DISPLAY_SOFT_BUTTON_ID = 0x91, // SV + HID_USAGE_AUX_DISPLAY_SOFT_BUTTON_SIDE = 0x92, // SV + HID_USAGE_AUX_DISPLAY_SOFT_BUTTON_OFFSET_1 = 0x93, // SV + HID_USAGE_AUX_DISPLAY_SOFT_BUTTON_OFFSET_2 = 0x94, // SV + HID_USAGE_AUX_DISPLAY_SOFT_BUTTON_REPORT = 0x95, // SV + // Reserved (0x96 - 0xC1) + HID_USAGE_AUX_DISPLAY_SOFT_KEYS = 0xC2, // SV + // Reserved (0xC3 - 0xCB) + HID_USAGE_AUX_DISPLAY_DATA_EXTENSIONS = 0xCC, // SF + // Reserved (0xCD - 0xCE) + HID_USAGE_AUX_DISPLAY_CHARACTER_MAPPING = 0xCF, // SV + // Reserved (0xD0 - 0xDC) + HID_USAGE_AUX_DISPLAY_UNICODE_EQUIVALENT = 0xDD, // SV + // Reserved (0xDE) + HID_USAGE_AUX_DISPLAY_CHARACTER_PAGE_MAPPING = 0xDF, // SV + // Reserved (0xE0 - 0xFE) + HID_USAGE_AUX_DISPLAY_REQUEST_REPORT = 0xFF // DV + // Reserved (0x100 - 0xFFFF) +}; + +/// HID Usage Table - Medical Instrument Page (0x40) +enum { + HID_USAGE_MEDICAL_INSTRUMENT_MEDICAL_ULTRASOUND = 0x01, // CA + // Reserved (0x02 - 0x1F) + HID_USAGE_MEDICAL_INSTRUMENT_VCR_ACQUISITION = 0x20, // OOC + HID_USAGE_MEDICAL_INSTRUMENT_FREEZE_THAW = 0x21, // OOC + HID_USAGE_MEDICAL_INSTRUMENT_CLIP_STORE = 0x22, // OSC + HID_USAGE_MEDICAL_INSTRUMENT_UPDATE = 0x23, // OSC + HID_USAGE_MEDICAL_INSTRUMENT_NEXT = 0x24, // OSC + HID_USAGE_MEDICAL_INSTRUMENT_SAVE = 0x25, // OSC + HID_USAGE_MEDICAL_INSTRUMENT_PRINT = 0x26, // OSC + HID_USAGE_MEDICAL_INSTRUMENT_MICROPHONE_ENABLE = 0x27, // OSC + // Reserved (0x28 - 0x3F) + HID_USAGE_MEDICAL_INSTRUMENT_CINE = 0x40, // LC + HID_USAGE_MEDICAL_INSTRUMENT_TRANSMIT_POWER = 0x41, // LC + HID_USAGE_MEDICAL_INSTRUMENT_VOLUME = 0x42, // LC + HID_USAGE_MEDICAL_INSTRUMENT_FOCUS = 0x43, // LC + HID_USAGE_MEDICAL_INSTRUMENT_DEPTH = 0x44, // LC + // Reserved (0x45 - 0x5F) + HID_USAGE_MEDICAL_INSTRUMENT_SOFT_STEP_PRIMARY = 0x60, // LC + HID_USAGE_MEDICAL_INSTRUMENT_SOFT_STEP_SECONDARY = 0x61, // LC + // Reserved (0x62 - 0x6F) + HID_USAGE_MEDICAL_INSTRUMENT_DEPTH_GAIN_COMPENSATION = 0x70, // LC + // Reserved (0x71 - 0x7F) + HID_USAGE_MEDICAL_INSTRUMENT_ZOOM_SELECT = 0x80, // OSC + HID_USAGE_MEDICAL_INSTRUMENT_ZOOM_ADJUST = 0x81, // LC + HID_USAGE_MEDICAL_INSTRUMENT_SPECTRAL_DOPPLER_MODE_SELECT = 0x82, // OSC + HID_USAGE_MEDICAL_INSTRUMENT_SPECTRAL_DOPPLER_ADJUST = 0x83, // LC + HID_USAGE_MEDICAL_INSTRUMENT_COLOR_DOPPLER_MODE_SELECT = 0x84, // OSC + HID_USAGE_MEDICAL_INSTRUMENT_COLOR_DOPPLER_ADJUST = 0x85, // LC + HID_USAGE_MEDICAL_INSTRUMENT_MOTION_MODE_SELECT = 0x86, // OSC + HID_USAGE_MEDICAL_INSTRUMENT_MOTION_MODE_ADJUST = 0x87, // LC + HID_USAGE_MEDICAL_INSTRUMENT_2D_MODE_SELECT = 0x88, // OSC + HID_USAGE_MEDICAL_INSTRUMENT_2D_MODE_ADJUST = 0x89, // LC + // Reserved (0x8A - 0x9F) + HID_USAGE_MEDICAL_INSTRUMENT_SOFT_CONTROL_SELECT = 0xA0, // OSC + HID_USAGE_MEDICAL_INSTRUMENT_SOFT_CONTROL_ADJUST = 0xA1, // LC + // Reserved (0xA2 - 0xFFFF) }; /// HID Usage Table - Lighting And Illumination Page (0x59) enum { - HID_USAGE_LIGHTING_LAMP_ARRAY = 0x01, - HID_USAGE_LIGHTING_LAMP_ARRAY_ATTRIBUTES_REPORT = 0x02, - HID_USAGE_LIGHTING_LAMP_COUNT = 0x03, - HID_USAGE_LIGHTING_BOUNDING_BOX_WIDTH_IN_MICROMETERS = 0x04, - HID_USAGE_LIGHTING_BOUNDING_BOX_HEIGHT_IN_MICROMETERS = 0x05, - HID_USAGE_LIGHTING_BOUNDING_BOX_DEPTH_IN_MICROMETERS = 0x06, - HID_USAGE_LIGHTING_LAMP_ARRAY_KIND = 0x07, - HID_USAGE_LIGHTING_MIN_UPDATE_INTERVAL_IN_MICROSECONDS = 0x08, - HID_USAGE_LIGHTING_LAMP_ATTRIBUTES_REQUEST_REPORT = 0x20, - HID_USAGE_LIGHTING_LAMP_ID = 0x21, - HID_USAGE_LIGHTING_LAMP_ATTRIBUTES_RESPONSE_REPORT = 0x22, - HID_USAGE_LIGHTING_POSITION_X_IN_MICROMETERS = 0x23, - HID_USAGE_LIGHTING_POSITION_Y_IN_MICROMETERS = 0x24, - HID_USAGE_LIGHTING_POSITION_Z_IN_MICROMETERS = 0x25, - HID_USAGE_LIGHTING_LAMP_PURPOSES = 0x26, - HID_USAGE_LIGHTING_UPDATE_LATENCY_IN_MICROSECONDS = 0x27, - HID_USAGE_LIGHTING_RED_LEVEL_COUNT = 0x28, - HID_USAGE_LIGHTING_GREEN_LEVEL_COUNT = 0x29, - HID_USAGE_LIGHTING_BLUE_LEVEL_COUNT = 0x2A, - HID_USAGE_LIGHTING_INTENSITY_LEVEL_COUNT = 0x2B, - HID_USAGE_LIGHTING_IS_PROGRAMMABLE = 0x2C, - HID_USAGE_LIGHTING_INPUT_BINDING = 0x2D, - HID_USAGE_LIGHTING_LAMP_MULTI_UPDATE_REPORT = 0x50, - HID_USAGE_LIGHTING_RED_UPDATE_CHANNEL = 0x51, - HID_USAGE_LIGHTING_GREEN_UPDATE_CHANNEL = 0x52, - HID_USAGE_LIGHTING_BLUE_UPDATE_CHANNEL = 0x53, - HID_USAGE_LIGHTING_INTENSITY_UPDATE_CHANNEL = 0x54, - HID_USAGE_LIGHTING_LAMP_UPDATE_FLAGS = 0x55, - HID_USAGE_LIGHTING_LAMP_RANGE_UPDATE_REPORT = 0x60, - HID_USAGE_LIGHTING_LAMP_ID_START = 0x61, - HID_USAGE_LIGHTING_LAMP_ID_END = 0x62, - HID_USAGE_LIGHTING_LAMP_ARRAY_CONTROL_REPORT = 0x70, - HID_USAGE_LIGHTING_AUTONOMOUS_MODE = 0x71, + HID_USAGE_LIGHTING_LAMP_ARRAY = 0x01, // CA + HID_USAGE_LIGHTING_LAMP_ARRAY_ATTRIBUTES_REPORT = 0x02, // CL + HID_USAGE_LIGHTING_LAMP_COUNT = 0x03, // SV/DV + HID_USAGE_LIGHTING_BOUNDING_BOX_WIDTH_IN_MICROMETERS = 0x04, // SV + HID_USAGE_LIGHTING_BOUNDING_BOX_HEIGHT_IN_MICROMETERS = 0x05, // SV + HID_USAGE_LIGHTING_BOUNDING_BOX_DEPTH_IN_MICROMETERS = 0x06, // SV + HID_USAGE_LIGHTING_LAMP_ARRAY_KIND = 0x07, // SV + HID_USAGE_LIGHTING_MIN_UPDATE_INTERVAL_IN_MICROSECONDS = 0x08, // SV + // Reserved (0x09 - 0x1F) + HID_USAGE_LIGHTING_LAMP_ATTRIBUTES_REQUEST_REPORT = 0x20, // CL + HID_USAGE_LIGHTING_LAMP_ID = 0x21, // SV/DV + HID_USAGE_LIGHTING_LAMP_ATTRIBUTES_RESPONSE_REPORT = 0x22, // CL + HID_USAGE_LIGHTING_POSITION_X_IN_MICROMETERS = 0x23, // DV + HID_USAGE_LIGHTING_POSITION_Y_IN_MICROMETERS = 0x24, // DV + HID_USAGE_LIGHTING_POSITION_Z_IN_MICROMETERS = 0x25, // DV + HID_USAGE_LIGHTING_LAMP_PURPOSES = 0x26, // DV + HID_USAGE_LIGHTING_UPDATE_LATENCY_IN_MICROSECONDS = 0x27, // DV + HID_USAGE_LIGHTING_RED_LEVEL_COUNT = 0x28, // DV + HID_USAGE_LIGHTING_GREEN_LEVEL_COUNT = 0x29, // DV + HID_USAGE_LIGHTING_BLUE_LEVEL_COUNT = 0x2A, // DV + HID_USAGE_LIGHTING_INTENSITY_LEVEL_COUNT = 0x2B, // DV + HID_USAGE_LIGHTING_IS_PROGRAMMABLE = 0x2C, // DV + HID_USAGE_LIGHTING_INPUT_BINDING = 0x2D, // DV + // Reserved (0x2E - 0x4F) + HID_USAGE_LIGHTING_LAMP_MULTI_UPDATE_REPORT = 0x50, // CL + HID_USAGE_LIGHTING_RED_UPDATE_CHANNEL = 0x51, // DV + HID_USAGE_LIGHTING_GREEN_UPDATE_CHANNEL = 0x52, // DV + HID_USAGE_LIGHTING_BLUE_UPDATE_CHANNEL = 0x53, // DV + HID_USAGE_LIGHTING_INTENSITY_UPDATE_CHANNEL = 0x54, // DV + HID_USAGE_LIGHTING_LAMP_UPDATE_FLAGS = 0x55, // DV + // Reserved (0x56 - 0x5F) + HID_USAGE_LIGHTING_LAMP_RANGE_UPDATE_REPORT = 0x60, // CL + HID_USAGE_LIGHTING_LAMP_ID_START = 0x61, // DV + HID_USAGE_LIGHTING_LAMP_ID_END = 0x62, // DV + // Reserved (0x63 - 0x6F) + HID_USAGE_LIGHTING_LAMP_ARRAY_CONTROL_REPORT = 0x70, // CL + HID_USAGE_LIGHTING_AUTONOMOUS_MODE = 0x71, // DV + // Reserved (0x72 - 0xFFFF) +}; + +/// HID Usage Table: Monitor Page (0x80) +enum { + HID_USAGE_MONITOR_MONITOR_CONTROL = 0x01, // CA + HID_USAGE_MONITOR_EDID_INFORMATION = 0x02, // SV + HID_USAGE_MONITOR_VDIF_INFORMATION = 0x03, // SV + HID_USAGE_MONITOR_VESA_VERSION = 0x04 // SV + // Reserved (0x05 - 0xFFFF) +}; + +/// HID Usage Table: Monitor Enumerated Page (0x81) +/// Intentionally skipped + +/// HID Usage Table: VESA Virtual Controls Page (0x82) +enum { + HID_USAGE_VESA_VIRTUAL_CONTROLS_DEGAUSS = 0x01, // DV + // Reserved (0x02 - 0x0F) + HID_USAGE_VESA_VIRTUAL_CONTROLS_BRIGHTNESS = 0x10, // DV + // Reserved (0x11) + HID_USAGE_VESA_VIRTUAL_CONTROLS_CONTRAST = 0x12, // DV + // Reserved (0x13 - 0x15) + HID_USAGE_VESA_VIRTUAL_CONTROLS_RED_VIDEO_GAIN = 0x16, // DV + // Reserved (0x17) + HID_USAGE_VESA_VIRTUAL_CONTROLS_GREEN_VIDEO_GAIN = 0x18, // DV + // Reserved (0x19) + HID_USAGE_VESA_VIRTUAL_CONTROLS_BLUE_VIDEO_GAIN = 0x1A, // DV + // Reserved (0x1B) + HID_USAGE_VESA_VIRTUAL_CONTROLS_FOCUS = 0x1C, // DV + // Reserved (0x1D - 0x1F) + HID_USAGE_VESA_VIRTUAL_CONTROLS_HORIZONTAL_POSITION = 0x20, // DV + // Reserved (0x21) + HID_USAGE_VESA_VIRTUAL_CONTROLS_HORIZONTAL_SIZE = 0x22, // DV + // Reserved (0x23) + HID_USAGE_VESA_VIRTUAL_CONTROLS_HORIZONTAL_PINCUSHION = 0x24, // DV + // Reserved (0x25) + HID_USAGE_VESA_VIRTUAL_CONTROLS_HORIZONTAL_PINCUSHION_BALANCE = 0x26, // DV + // Reserved (0x27) + HID_USAGE_VESA_VIRTUAL_CONTROLS_HORIZONTAL_MISCONVERGENCE = 0x28, // DV + // Reserved (0x29) + HID_USAGE_VESA_VIRTUAL_CONTROLS_HORIZONTAL_LINEARITY = 0x2A, // DV + // Reserved (0x2B) + HID_USAGE_VESA_VIRTUAL_CONTROLS_HORIZONTAL_LINEARITY_BALANCE = 0x2C, // DV + // Reserved (0x2D - 0x2F) + HID_USAGE_VESA_VIRTUAL_CONTROLS_VERTICAL_POSITION = 0x30, // DV + // Reserved (0x31) + HID_USAGE_VESA_VIRTUAL_CONTROLS_VERTICAL_SIZE = 0x32, // DV + // Reserved (0x33) + HID_USAGE_VESA_VIRTUAL_CONTROLS_VERTICAL_PINCUSHION = 0x34, // DV + // Reserved (0x35) + HID_USAGE_VESA_VIRTUAL_CONTROLS_VERTICAL_PINCUSHION_BALANCE = 0x36, // DV + // Reserved (0x37) + HID_USAGE_VESA_VIRTUAL_CONTROLS_VERTICAL_MISCONVERGENCE = 0x38, // DV + // Reserved (0x39) + HID_USAGE_VESA_VIRTUAL_CONTROLS_VERTICAL_LINEARITY = 0x3A, // DV + // Reserved (0x3B) + HID_USAGE_VESA_VIRTUAL_CONTROLS_VERTICAL_LINEARITY_BALANCE = 0x3C, // DV + // Reserved (0x3D - 0x3F) + HID_USAGE_VESA_VIRTUAL_CONTROLS_PARALLELOGRAM_DISTORTION = 0x40, // DV + // Reserved (0x41) + HID_USAGE_VESA_VIRTUAL_CONTROLS_TRAPEZOIDAL_DISTORTION = 0x42, // DV + // Reserved (0x43) + HID_USAGE_VESA_VIRTUAL_CONTROLS_TILT = 0x44, // DV + // Reserved (0x45) + HID_USAGE_VESA_VIRTUAL_CONTROLS_TOP_CORNER_DISTORTION_CONTROL = 0x46, // DV + // Reserved (0x47) + HID_USAGE_VESA_VIRTUAL_CONTROLS_TOP_CORNER_DISTORTION_BALANCE = 0x48, // DV + // Reserved (0x49) + HID_USAGE_VESA_VIRTUAL_CONTROLS_BOTTOM_CORNER_DISTORTION_CONTROL = 0x4A, // DV + // Reserved (0x4B) + HID_USAGE_VESA_VIRTUAL_CONTROLS_BOTTOM_CORNER_DISTORTION_BALANCE = 0x4C, // DV + // Reserved (0x4D - 0x55) + HID_USAGE_VESA_VIRTUAL_CONTROLS_HORIZONTAL_MOIRE = 0x56, // DV + // Reserved (0x57) + HID_USAGE_VESA_VIRTUAL_CONTROLS_VERTICAL_MOIRE = 0x58, // DV + // Reserved (0x59 - 0x5D) + HID_USAGE_VESA_VIRTUAL_CONTROLS_INPUT_LEVEL_SELECT = 0x5E, // NAry + // Reserved (0x5F) + HID_USAGE_VESA_VIRTUAL_CONTROLS_INPUT_SOURCE_SELECT = 0x60, // NAry + // Reserved (0x61 - 0x6B) + HID_USAGE_VESA_VIRTUAL_CONTROLS_RED_VIDEO_BLACK_LEVEL = 0x6C, // DV + // Reserved (0x6D) + HID_USAGE_VESA_VIRTUAL_CONTROLS_GREEN_VIDEO_BLACK_LEVEL = 0x6E, // DV + // Reserved (0x6F) + HID_USAGE_VESA_VIRTUAL_CONTROLS_BLUE_VIDEO_BLACK_LEVEL = 0x70, // DV + // Reserved (0x71 - 0xA1) + HID_USAGE_VESA_VIRTUAL_CONTROLS_AUTO_SIZE_CENTER = 0xA2, // NAry + // Reserved (0xA3) + HID_USAGE_VESA_VIRTUAL_CONTROLS_POLARITY_HORIZONTAL_SYNC = 0xA4, // NAry + // Reserved (0xA5) + HID_USAGE_VESA_VIRTUAL_CONTROLS_POLARITY_VERTICAL_SYNC = 0xA6, // NAry + // Reserved (0xA7) + HID_USAGE_VESA_VIRTUAL_CONTROLS_SYNC_TYPE = 0xA8, // NAry + // Reserved (0xA9) + HID_USAGE_VESA_VIRTUAL_CONTROLS_SCREEN_ORIENTATION = 0xAA, // NAry + // Reserved (0xAB) + HID_USAGE_VESA_VIRTUAL_CONTROLS_HORIZONTAL_FREQUENCY = 0xAC, // DV + // Reserved (0xAD) + HID_USAGE_VESA_VIRTUAL_CONTROLS_VERTICAL_FREQUENCY = 0xAE, // DV + // Reserved (0xAF) + HID_USAGE_VESA_VIRTUAL_CONTROLS_SETTINGS = 0xB0, // NAry + // Reserved (0xB1 - 0xC9) + HID_USAGE_VESA_VIRTUAL_CONTROLS_ON_SCREEN_DISPLAY = 0xCA, // NAry + // Reserved (0xCB - 0xD3) + HID_USAGE_VESA_VIRTUAL_CONTROLS_STEREO_MODE = 0xD4, // NAry + // Reserved (0xD5 - 0xFFFF) }; /// HID Usage Table: Power Device Page (0x84) @@ -1684,6 +2579,7 @@ enum { HID_USAGE_POWER_I_MANUFACTURER = 0xFD, HID_USAGE_POWER_I_PRODUCT = 0xFE, HID_USAGE_POWER_I_SERIAL_NUMBER = 0xFF + // Reserved (0x100 - 0xFFFF) }; /// HID Usage Table: Battery System Page (0x85) @@ -1791,6 +2687,48 @@ enum { // F4-FF Reserved }; +/// HID Usage Table: Camera Control Page (0x90) +enum { + // Reserved (0x01 - 0x1F) + HID_USAGE_CAMERA_CONTROL_CAMERA_AUTO_FOCUS = 0x20, // OSC + HID_USAGE_CAMERA_CONTROL_CAMERA_SHUTTER = 0x21 // OSC + // Reserved (0x22 - 0xFFFF) +}; + +/// HID Usage Table: Arcade Page (0x91) +enum { + HID_USAGE_ARCADE_GENERAL_PURPOSE_IO_CARD = 0x01, // CA + HID_USAGE_ARCADE_COIN_DOOR = 0x02, // CA + HID_USAGE_ARCADE_WATCHDOG_TIMER = 0x03, // CA + // Reserved (0x04 - 0x2F) + HID_USAGE_ARCADE_GENERAL_PURPOSE_ANALOG_INPUT_STATE = 0x30, // DV + HID_USAGE_ARCADE_GENERAL_PURPOSE_DIGITAL_INPUT_STATE = 0x31, // DV + HID_USAGE_ARCADE_GENERAL_PURPOSE_OPTICAL_INPUT_STATE = 0x32, // DV + HID_USAGE_ARCADE_GENERAL_PURPOSE_DIGITAL_OUTPUT_STATE = 0x33, // DV + HID_USAGE_ARCADE_NUMBER_OF_COIN_DOORS = 0x34, // DV + HID_USAGE_ARCADE_COIN_DRAWER_DROP_COUNT = 0x35, // DV + HID_USAGE_ARCADE_COIN_DRAWER_START = 0x36, // OOC + HID_USAGE_ARCADE_COIN_DRAWER_SERVICE = 0x37, // OOC + HID_USAGE_ARCADE_COIN_DRAWER_TILT = 0x38, // OOC + HID_USAGE_ARCADE_COIN_DOOR_TEST = 0x39, // OOC + // Reserved (0x3A - 0x3F) + HID_USAGE_ARCADE_COIN_DOOR_LOCKOUT = 0x40, // OOC + HID_USAGE_ARCADE_WATCHDOG_TIMEOUT = 0x41, // DV + HID_USAGE_ARCADE_WATCHDOG_ACTION = 0x42, // NAry + HID_USAGE_ARCADE_WATCHDOG_REBOOT = 0x43, // Sel + HID_USAGE_ARCADE_WATCHDOG_RESTART = 0x44, // Sel + HID_USAGE_ARCADE_ALARM_INPUT = 0x45, // DV + HID_USAGE_ARCADE_COIN_DOOR_COUNTER = 0x46, // OOC + HID_USAGE_ARCADE_IO_DIRECTION_MAPPING = 0x47, // DV + HID_USAGE_ARCADE_SET_IO_DIRECTION_MAPPING = 0x48, // DV + HID_USAGE_ARCADE_EXTENDED_OPTICAL_INPUT_STATE = 0x49, // DV + HID_USAGE_ARCADE_PIN_PAD_INPUT_STATE = 0x4A, // DV + HID_USAGE_ARCADE_PIN_PAD_STATUS = 0x4B, // DV + HID_USAGE_ARCADE_PIN_PAD_OUTPUT = 0x4C, // OOC + HID_USAGE_ARCADE_PIN_PAD_COMMAND = 0x4D, // DV + // Reserved (0x4E - 0xFFFF) +}; + /// HID Usage Table: FIDO Alliance Page (0xF1D0) enum { HID_USAGE_FIDO_U2FHID = 0x01, // U2FHID usage for top-level collection diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c index 6ee4cd9c1..b7126e82c 100644 --- a/src/class/hid/hid_device.c +++ b/src/class/hid/hid_device.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/hid/hid_device.h b/src/class/hid/hid_device.h index 32b572973..ba2258d92 100644 --- a/src/class/hid/hid_device.h +++ b/src/class/hid/hid_device.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index 29bcae99f..ca3654acb 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/hid/hid_host.h b/src/class/hid/hid_host.h index 95ba859ad..492bc60e9 100644 --- a/src/class/hid/hid_host.h +++ b/src/class/hid/hid_host.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/midi/midi.h b/src/class/midi/midi.h index 8121ec016..c966719f1 100644 --- a/src/class/midi/midi.h +++ b/src/class/midi/midi.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/midi/midi2_device.c b/src/class/midi/midi2_device.c index b14f439f8..b0a9e2503 100644 --- a/src/class/midi/midi2_device.c +++ b/src/class/midi/midi2_device.c @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2026 Saulo Verissimo - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2026 Saulo Verissimo + * SPDX-FileCopyrightText: Copyright (c) 2026 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -42,18 +24,21 @@ TU_ATTR_WEAK void tud_midi2_set_itf_cb(uint8_t itf, uint8_t alt) { (void) itf; ( TU_ATTR_WEAK bool tud_midi2_get_req_itf_cb(uint8_t rhport, const tusb_control_request_t* request) { (void) rhport; (void) request; return false; } -TU_ATTR_WEAK uint8_t tud_midi2_num_groups_cb(uint8_t itf) { - (void) itf; return CFG_TUD_MIDI2_NUM_GROUPS; -} -TU_ATTR_WEAK uint8_t tud_midi2_num_function_blocks_cb(uint8_t itf) { - (void) itf; return CFG_TUD_MIDI2_NUM_FUNCTION_BLOCKS; -} TU_ATTR_WEAK const char* tud_midi2_ep_name_cb(uint8_t itf) { (void) itf; return CFG_TUD_MIDI2_EP_NAME; } TU_ATTR_WEAK const char* tud_midi2_product_id_cb(uint8_t itf) { (void) itf; return CFG_TUD_MIDI2_PRODUCT_ID; } +TU_ATTR_WEAK const char* tud_midi2_fb_name_cb(uint8_t itf, uint8_t fb_idx) { + (void) itf; (void) fb_idx; return NULL; +} +TU_ATTR_WEAK tud_midi2_stream_result_t tud_midi2_stream_msg_cb(uint8_t itf, const uint32_t* ump_words) { + (void) itf; (void) ump_words; return MIDI2_STREAM_PASS; +} +TU_ATTR_WEAK bool tud_midi2_device_identity_cb(uint8_t itf, tud_midi2_device_identity_t* identity) { + (void) itf; (void) identity; return false; +} //--------------------------------------------------------------------+ // Byte order note @@ -77,12 +62,14 @@ enum { enum { STREAM_ENDPOINT_DISCOVERY = 0x000, STREAM_ENDPOINT_INFO = 0x001, + STREAM_DEVICE_IDENTITY = 0x002, STREAM_EP_NAME = 0x003, STREAM_PROD_INSTANCE_ID = 0x004, STREAM_CONFIG_REQUEST = 0x005, STREAM_CONFIG_NOTIFY = 0x006, STREAM_FB_DISCOVERY = 0x010, STREAM_FB_INFO = 0x011, + STREAM_FB_NAME = 0x012, }; enum { @@ -90,11 +77,14 @@ enum { UMP_VER_MINOR = 1, }; -// Group Terminal Block descriptor types (USB-MIDI 2.0) +// Function Block Info Notification low byte: UI hint (bits 5:4) + direction +// (bits 1:0). See USB-MIDI 2.0 / UMP Function Block Info Notification. enum { - MIDI2_CS_GRP_TRM_BLOCK = 0x26, - MIDI2_GRP_TRM_BLOCK_HEADER = 0x01, - MIDI2_GRP_TRM_BLOCK_ENTRY = 0x02, + FB_DIR_INPUT = 0x1, + FB_DIR_OUTPUT = 0x2, + FB_DIR_BIDIR = 0x3, + FB_UI_RECEIVER = (1u << 4), + FB_UI_SENDER = (1u << 5), }; //--------------------------------------------------------------------+ @@ -117,6 +107,16 @@ typedef struct { uint8_t protocol; bool negotiated; + // Discovery reply bits waiting for TX FIFO room, drained on TX complete + uint8_t nego_pending_ep_filter; + uint8_t nego_pending_fb_filter; + uint8_t nego_pending_fb_num; // block requested by the pending discovery, 0xFF = all + uint8_t nego_pending_fb_next; // next block index to reply for + bool nego_pending_fb_restart; // restart after the active FB name when requests merge + uint16_t nego_text_status; // text reply owning nego_text_offset, 0 = none + uint16_t nego_text_offset; // progress into the text reply being sent + uint8_t nego_text_index; // Function Block index for an active FB name + /*------------- From this point, data is not cleared by bus reset -------------*/ struct { midi2d_tx_t tx; @@ -139,8 +139,6 @@ CFG_TUD_MEM_SECTION static midi2d_epbuf_t _midi2d_epbuf[CFG_TUD_MIDI2]; TU_VERIFY_STATIC(CFG_TUD_MIDI2_NUM_GROUPS >= 1 && CFG_TUD_MIDI2_NUM_GROUPS <= 16, "CFG_TUD_MIDI2_NUM_GROUPS must be 1..16"); -TU_VERIFY_STATIC(CFG_TUD_MIDI2_NUM_FUNCTION_BLOCKS >= 1 && CFG_TUD_MIDI2_NUM_FUNCTION_BLOCKS <= 32, - "CFG_TUD_MIDI2_NUM_FUNCTION_BLOCKS must be 1..32"); #define ITF_MEM_RESET_SIZE offsetof(midi2d_interface_t, ep_stream) @@ -168,6 +166,48 @@ static const uint8_t _default_gtb_desc[] = { 0, 0 // wMaxOutputBandwidth: unknown }; +// Map GTB bGrpTrmBlkType to the FB Info Notification low byte (UI hint + dir). +static inline uint8_t _fb_dir_byte(uint8_t gtb_type) { + switch (gtb_type) { + case MIDI2_GTB_INPUT_ONLY: return FB_UI_RECEIVER | FB_DIR_INPUT; + case MIDI2_GTB_OUTPUT_ONLY: return FB_UI_SENDER | FB_DIR_OUTPUT; + default: return FB_UI_RECEIVER | FB_UI_SENDER | FB_DIR_BIDIR; + } +} + +// Walk the GTB descriptor. Returns the number of block entries. When block +// `idx` exists, fills its type / first group / group count. +static uint8_t _gtb_blocks(const uint8_t* desc, uint16_t len, uint8_t idx, + uint8_t* type, uint8_t* first_group, uint8_t* num_groups) { + uint8_t count = 0; + uint16_t off = MIDI2_GTB_HEADER_LEN; // skip the list header + while (off + MIDI2_GTB_ENTRY_LEN <= len && desc[off] >= MIDI2_GTB_ENTRY_LEN) { + if (desc[off + 2] == MIDI2_GRP_TRM_BLOCK_ENTRY) { + if (count == idx) { + if (type) *type = desc[off + 4]; // bGrpTrmBlkType + if (first_group) *first_group = desc[off + 5]; // nGroupTrm + if (num_groups) *num_groups = desc[off + 6]; // nNumGroupTrm + } + count++; + } + off = (uint16_t)(off + desc[off]); + } + return count; +} + +static bool _gtb_desc_valid(const uint8_t* desc, uint16_t len) { + return desc != NULL && len >= TUD_MIDI2_GTB_DESC_LEN(1); +} + +// GTB descriptor source: the single source of truth for block topology. +// Override to expose multiple Group Terminal Blocks with independent +// directions and group spans. +TU_ATTR_WEAK const uint8_t* tud_midi2_gtb_desc_cb(uint8_t itf, uint16_t* len) { + (void) itf; + *len = (uint16_t) sizeof(_default_gtb_desc); + return _default_gtb_desc; +} + //--------------------------------------------------------------------+ // Common utility functions //--------------------------------------------------------------------+ @@ -176,6 +216,13 @@ static inline uint8_t _itf_idx(const midi2d_interface_t* p_midi) { return (uint8_t)(p_midi - _midi2d_itf); } +static uint8_t _gtb_block_count(midi2d_interface_t* p_midi) { + uint16_t len = 0; + const uint8_t* gtb = tud_midi2_gtb_desc_cb(_itf_idx(p_midi), &len); + TU_ASSERT(_gtb_desc_valid(gtb, len), 0); + return _gtb_blocks(gtb, len, 0xFF, NULL, NULL, NULL); +} + static inline bool _tx_opened(const midi2d_interface_t* p_midi) { return p_midi->ep_stream.tx.ep_addr != 0; } @@ -283,23 +330,35 @@ static void _nego_send_endpoint_info(midi2d_interface_t* p_midi) { | ((uint32_t) UMP_VER_MAJOR << 8) | (uint32_t) UMP_VER_MINOR; msg[1] = (UINT32_C(1) << 31) // Static Function Blocks flag - | ((uint32_t)(tud_midi2_num_function_blocks_cb(_itf_idx(p_midi)) & 0x7F) << 24) + | ((uint32_t)(_gtb_block_count(p_midi) & 0x7F) << 24) | (UINT32_C(1) << 9) // MIDI 2.0 Protocol capability | (UINT32_C(1) << 8); // MIDI 1.0 Protocol capability _nego_send_ump(p_midi, msg, 4); } -static void _nego_send_stream_text(midi2d_interface_t* p_midi, uint16_t status, const char* str) { - if (!str || str[0] == '\0') return; +// Send a UMP Stream text notification, multi-packet (Complete/Start/Continue/ +// End in the Format field). When has_index is set, word0 bits 15:8 carry an +// index byte (the Function Block number for FB Name) and 13 chars fit per +// packet; otherwise the text starts there and 14 chars fit (Endpoint Name, +// Product Instance Id). +// Sends a stream text from `offset` and returns how far it got. Resuming keeps +// the End packet, which dropping the tail would lose. +static uint16_t _nego_send_stream_text(midi2d_interface_t* p_midi, uint16_t status, + bool has_index, uint8_t index, const char* str, + uint16_t offset) { + if (!str || str[0] == '\0') return 0; - uint16_t total_len = (uint16_t) strlen(str); - uint16_t offset = 0; + const uint16_t total_len = (uint16_t) strlen(str); + const uint8_t per_pkt = has_index ? 13 : 14; + const uint8_t head_chars = has_index ? 1 : 2; // chars carried in word0 + if (offset >= total_len) return total_len; while (offset < total_len) { + if (tu_fifo_remaining(&p_midi->ep_stream.tx.ff) < 16) break; uint16_t remaining = total_len - offset; - uint8_t n = (uint8_t)((remaining > 14) ? 14 : remaining); + uint8_t n = (uint8_t)((remaining > per_pkt) ? per_pkt : remaining); bool is_first = (offset == 0); - bool is_last = (remaining <= 14); + bool is_last = (remaining <= per_pkt); uint8_t form; if (is_first && is_last) form = 0; @@ -313,17 +372,23 @@ static void _nego_send_stream_text(midi2d_interface_t* p_midi, uint16_t status, | ((uint32_t) status << 16); const char* p = str + offset; - if (n > 0) msg[0] |= ((uint32_t)(uint8_t) p[0] << 8); - if (n > 1) msg[0] |= (uint32_t)(uint8_t) p[1]; - for (uint8_t i = 2; i < n; i++) { - uint8_t word_idx = (uint8_t)(1 + (i - 2) / 4); - uint8_t shift = (uint8_t)(24 - ((i - 2) % 4) * 8); + if (has_index) { + msg[0] |= ((uint32_t) index << 8); // bits 15:8 = index + if (n > 0) msg[0] |= (uint32_t)(uint8_t) p[0]; // bits 7:0 = char 0 + } else { + if (n > 0) msg[0] |= ((uint32_t)(uint8_t) p[0] << 8); // bits 15:8 = char 0 + if (n > 1) msg[0] |= (uint32_t)(uint8_t) p[1]; // bits 7:0 = char 1 + } + for (uint8_t i = head_chars; i < n; i++) { + uint8_t word_idx = (uint8_t)(1 + (i - head_chars) / 4); + uint8_t shift = (uint8_t)(24 - ((i - head_chars) % 4) * 8); msg[word_idx] |= ((uint32_t)(uint8_t) p[i] << shift); } _nego_send_ump(p_midi, msg, 4); offset += n; } + return offset; } static void _nego_send_config_notify(midi2d_interface_t* p_midi, uint8_t protocol) { @@ -334,26 +399,189 @@ static void _nego_send_config_notify(midi2d_interface_t* p_midi, uint8_t protoco _nego_send_ump(p_midi, msg, 4); } +static void _nego_send_device_identity(midi2d_interface_t* p_midi) { + tud_midi2_device_identity_t id; + tu_memclr(&id, sizeof(id)); + if (!tud_midi2_device_identity_cb(_itf_idx(p_midi), &id)) return; + + // Every field is a run of bytes, each carrying 7 bits, laid out in the same + // order as the MIDI 1.0 Device Inquiry reply this message mirrors. A 1-byte + // manufacturer ID occupies the first of the three bytes, the other two stay + // zero, so the caller passes it as 0x7D0000 and not 0x00007D. + uint32_t msg[4] = {0}; + msg[0] = ((uint32_t) MT_STREAM << 28) + | ((uint32_t) STREAM_DEVICE_IDENTITY << 16); + msg[1] = id.manufacturer & UINT32_C(0x7F7F7F); + // Family and model are 14-bit numbers sent least significant byte first, + // as in the Device Inquiry reply. Manufacturer above is a byte sequence + // rather than a number, so it keeps its own order. + msg[2] = ((uint32_t) (id.family & 0x7F) << 24) + | ((uint32_t) ((id.family >> 7) & 0x7F) << 16) + | ((uint32_t) (id.model & 0x7F) << 8) + | ((uint32_t) ((id.model >> 7) & 0x7F)); + msg[3] = ((uint32_t) ((id.sw_revision >> 24) & 0x7F) << 24) + | ((uint32_t) ((id.sw_revision >> 16) & 0x7F) << 16) + | ((uint32_t) ((id.sw_revision >> 8) & 0x7F) << 8) + | ((uint32_t) (id.sw_revision & 0x7F)); + _nego_send_ump(p_midi, msg, 4); +} + static void _nego_send_fb_info(midi2d_interface_t* p_midi, uint8_t fb_idx) { + // Derive direction and group span for this block from the GTB descriptor. + uint16_t gtb_len = 0; + const uint8_t* gtb = tud_midi2_gtb_desc_cb(_itf_idx(p_midi), >b_len); + TU_ASSERT(_gtb_desc_valid(gtb, gtb_len),); + uint8_t type = 0x00, first_group = 0, num_groups = (uint8_t) CFG_TUD_MIDI2_NUM_GROUPS; + _gtb_blocks(gtb, gtb_len, fb_idx, &type, &first_group, &num_groups); + uint32_t msg[4] = {0}; msg[0] = ((uint32_t) MT_STREAM << 28) | ((uint32_t) STREAM_FB_INFO << 16) | (UINT32_C(1) << 15) | ((uint32_t) fb_idx << 8) - | 0x02; // bDirection: bidirectional - msg[1] = ((uint32_t) 0 << 24) // bFirstGroup - | ((uint32_t) tud_midi2_num_groups_cb(_itf_idx(p_midi)) << 16); + | _fb_dir_byte(type); // UI hint + bDirection from the GTB block type + msg[1] = ((uint32_t) first_group << 24) + | ((uint32_t) num_groups << 16) + | ((uint32_t) (CFG_TUD_MIDI2_FB_CI_VERSION & 0xFF) << 8) + | ((uint32_t) (CFG_TUD_MIDI2_FB_SYSEX8_STREAMS & 0xFF)); _nego_send_ump(p_midi, msg, 4); } +static void _nego_clear_pending(midi2d_interface_t* p_midi) { + p_midi->nego_pending_ep_filter = 0; + p_midi->nego_pending_fb_filter = 0; + p_midi->nego_pending_fb_num = 0; + p_midi->nego_pending_fb_next = 0; + p_midi->nego_pending_fb_restart = false; + p_midi->nego_text_status = 0; + p_midi->nego_text_offset = 0; + p_midi->nego_text_index = 0; +} + +static const char* _nego_text_cb(midi2d_interface_t* p_midi, uint16_t status, uint8_t index) { + const uint8_t itf = _itf_idx(p_midi); + switch (status) { + case STREAM_EP_NAME: return tud_midi2_ep_name_cb(itf); + case STREAM_PROD_INSTANCE_ID: return tud_midi2_product_id_cb(itf); + case STREAM_FB_NAME: return tud_midi2_fb_name_cb(itf, index); + default: return NULL; + } +} + +// Send or resume one text reply. While it is incomplete, its status and index +// identify the sole owner of nego_text_offset so another discovery request +// cannot resume a different string from the same offset. +static bool _nego_send_text(midi2d_interface_t* p_midi, uint16_t status, uint8_t index) { + const char* text = _nego_text_cb(p_midi, status, index); + const uint16_t len = text ? (uint16_t) strlen(text) : 0; + + p_midi->nego_text_status = status; + p_midi->nego_text_index = index; + p_midi->nego_text_offset = _nego_send_stream_text(p_midi, status, status == STREAM_FB_NAME, + index, text, p_midi->nego_text_offset); + if (p_midi->nego_text_offset < len) return false; + + p_midi->nego_text_status = 0; + p_midi->nego_text_offset = 0; + p_midi->nego_text_index = 0; + return true; +} + +// Send pending discovery replies, one whole reply at a time and only when the +// TX FIFO can take it. A full-filter Endpoint Discovery asks for more bytes +// than the default FIFO holds; replies that do not fit stay pending and are +// retried from the TX complete path, paced by the transfer flow. +static void _nego_send_pending(midi2d_interface_t* p_midi) { + tu_fifo_t* tx_ff = &p_midi->ep_stream.tx.ff; + + // An incomplete text sequence must finish before any newly arrived request + // is serviced; otherwise its Continue/End packets could be attached to a + // different Endpoint or Function Block string. + if (p_midi->nego_text_status) { + const uint16_t status = p_midi->nego_text_status; + const uint8_t index = p_midi->nego_text_index; + if (!_nego_send_text(p_midi, status, index)) return; + + if (status == STREAM_FB_NAME) { + if (p_midi->nego_pending_fb_restart) { + p_midi->nego_pending_fb_next = 0; + p_midi->nego_pending_fb_restart = false; + } else { + p_midi->nego_pending_fb_next++; + } + } else { + const uint8_t bit = (status == STREAM_EP_NAME) ? 0x04 : 0x08; + p_midi->nego_pending_ep_filter &= (uint8_t) ~bit; + } + } + + while (p_midi->nego_pending_ep_filter) { + const uint8_t bit = (uint8_t)(p_midi->nego_pending_ep_filter & (uint8_t)(-p_midi->nego_pending_ep_filter)); + uint16_t status = 0; + switch (bit) { + case 0x04: status = STREAM_EP_NAME; break; + case 0x08: status = STREAM_PROD_INSTANCE_ID; break; + default: break; + } + + if (status != 0) { + if (!_nego_send_text(p_midi, status, 0)) return; + } else { + if (tu_fifo_remaining(tx_ff) < 16) return; + switch (bit) { + case 0x01: _nego_send_endpoint_info(p_midi); break; + case 0x02: _nego_send_device_identity(p_midi); break; + case 0x10: _nego_send_config_notify(p_midi, p_midi->protocol); break; + default: break; + } + } + p_midi->nego_pending_ep_filter &= (uint8_t) ~bit; + } + + const uint8_t fb_count = _gtb_block_count(p_midi); + while (p_midi->nego_pending_fb_filter && p_midi->nego_pending_fb_next < fb_count) { + const uint8_t f = p_midi->nego_pending_fb_next; + if (p_midi->nego_pending_fb_num != 0xFF && p_midi->nego_pending_fb_num != f) { + p_midi->nego_pending_fb_next++; + continue; + } + if ((p_midi->nego_pending_fb_filter & 0x01) && p_midi->nego_text_offset == 0) { + if (tu_fifo_remaining(tx_ff) < 16) return; + _nego_send_fb_info(p_midi, f); + } + if (p_midi->nego_pending_fb_filter & 0x02) { + if (!_nego_send_text(p_midi, STREAM_FB_NAME, f)) return; + } + p_midi->nego_pending_fb_next++; + } + if (p_midi->nego_pending_fb_next >= fb_count) p_midi->nego_pending_fb_filter = 0; +} + static void _nego_handle_stream_msg(midi2d_interface_t* p_midi, const uint32_t* words) { + // Let the application override this message before the built-in responder. + switch (tud_midi2_stream_msg_cb(_itf_idx(p_midi), words)) { + case MIDI2_STREAM_HANDLED: + return; + case MIDI2_STREAM_NEGOTIATED_MIDI1: + p_midi->protocol = MIDI_PROTOCOL_MIDI1; + p_midi->negotiated = true; + return; + case MIDI2_STREAM_NEGOTIATED_MIDI2: + p_midi->protocol = MIDI_PROTOCOL_MIDI2; + p_midi->negotiated = true; + return; + case MIDI2_STREAM_PASS: + default: + break; + } + uint16_t status = (words[0] >> 16) & 0x3FF; switch (status) { case STREAM_ENDPOINT_DISCOVERY: - _nego_send_endpoint_info(p_midi); - _nego_send_stream_text(p_midi, STREAM_EP_NAME, tud_midi2_ep_name_cb(_itf_idx(p_midi))); - _nego_send_stream_text(p_midi, STREAM_PROD_INSTANCE_ID, tud_midi2_product_id_cb(_itf_idx(p_midi))); + // Filter bitmap: each bit set asks for one individual reply. + p_midi->nego_pending_ep_filter |= (uint8_t)(words[1] & 0x1F); + _nego_send_pending(p_midi); break; case STREAM_CONFIG_REQUEST: { @@ -367,15 +595,23 @@ static void _nego_handle_stream_msg(midi2d_interface_t* p_midi, const uint32_t* } case STREAM_FB_DISCOVERY: { - uint8_t fb_idx = (words[0] >> 8) & 0xFF; - uint8_t fb_count = tud_midi2_num_function_blocks_cb(_itf_idx(p_midi)); - if (fb_idx == 0xFF) { - for (uint8_t f = 0; f < fb_count; f++) { - _nego_send_fb_info(p_midi, f); + const uint8_t req_num = (uint8_t)((words[0] >> 8) & 0xFF); + const uint8_t req_filter = (uint8_t)(words[0] & 0x03); + // Merge with a pending request: repeating a Function Block Info is allowed + // at any time, losing a requested one is not. + if (req_filter && p_midi->nego_pending_fb_filter) { + if (p_midi->nego_pending_fb_num != req_num) p_midi->nego_pending_fb_num = 0xFF; + if (p_midi->nego_text_status == STREAM_FB_NAME) { + p_midi->nego_pending_fb_restart = true; + } else { + p_midi->nego_pending_fb_next = 0; } - } else if (fb_idx < fb_count) { - _nego_send_fb_info(p_midi, fb_idx); + } else if (!p_midi->nego_pending_fb_filter) { + p_midi->nego_pending_fb_num = req_num; + p_midi->nego_pending_fb_next = 0; } + p_midi->nego_pending_fb_filter |= req_filter; // bit 0: FB Info, bit 1: FB Name + _nego_send_pending(p_midi); break; } @@ -685,6 +921,7 @@ bool midi2d_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control_re tu_edpt_stream_clear(&p_midi->ep_stream.rx); tu_fifo_clear(&p_midi->ep_stream.tx.ff); + _nego_clear_pending(p_midi); if (alt == 1) { p_midi->negotiated = false; @@ -718,11 +955,15 @@ bool midi2d_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control_re if (tud_midi2_get_req_itf_cb(rhport, request)) return true; + uint16_t gtb_len = 0; + const uint8_t* gtb = tud_midi2_gtb_desc_cb(idx, >b_len); + TU_ASSERT(_gtb_desc_valid(gtb, gtb_len), false); + uint16_t len = request->wLength; - if (len > sizeof(_default_gtb_desc)) { - len = sizeof(_default_gtb_desc); + if (len > gtb_len) { + len = gtb_len; } - tud_control_xfer(rhport, request, (void*)(uintptr_t) _default_gtb_desc, len); + tud_control_xfer(rhport, request, (void*)(uintptr_t) gtb, len); return true; } @@ -751,6 +992,10 @@ bool midi2d_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 } tu_edpt_stream_read_xfer(ep_rx); } else if (ep_addr == ep_tx->ep_addr && result == XFER_RESULT_SUCCESS) { + // Completed transfer freed FIFO room: flush discovery replies still pending. + if (p_midi->alt_setting == 1) { + _nego_send_pending(p_midi); + } uint16_t queued = _tx_start_xfer(p_midi); // Send ZLP if no more data is queued but the last transfer was exactly mps if (queued == 0 && tu_fifo_count(&ep_tx->ff) == 0 && xferred_bytes > 0 && diff --git a/src/class/midi/midi2_device.h b/src/class/midi/midi2_device.h index e53535693..e3eb084d9 100644 --- a/src/class/midi/midi2_device.h +++ b/src/class/midi/midi2_device.h @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2026 Saulo Verissimo - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2026 Saulo Verissimo + * SPDX-FileCopyrightText: Copyright (c) 2026 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -37,7 +19,7 @@ // Config defaults are in tusb_option.h: // CFG_TUD_MIDI2_RX_EPSIZE, CFG_TUD_MIDI2_TX_EPSIZE, // CFG_TUD_MIDI2_RX_BUFSIZE, CFG_TUD_MIDI2_TX_BUFSIZE, -// CFG_TUD_MIDI2_NUM_GROUPS, CFG_TUD_MIDI2_NUM_FUNCTION_BLOCKS, +// CFG_TUD_MIDI2_NUM_GROUPS, // CFG_TUD_MIDI2_EP_NAME, CFG_TUD_MIDI2_PRODUCT_ID #ifdef __cplusplus @@ -68,10 +50,6 @@ extern "C" { #define CFG_TUD_MIDI2_NUM_GROUPS 1 #endif -#ifndef CFG_TUD_MIDI2_NUM_FUNCTION_BLOCKS - #define CFG_TUD_MIDI2_NUM_FUNCTION_BLOCKS 1 -#endif - #ifndef CFG_TUD_MIDI2_EP_NAME #define CFG_TUD_MIDI2_EP_NAME "TinyUSB MIDI 2.0" #endif @@ -80,6 +58,17 @@ extern "C" { #define CFG_TUD_MIDI2_PRODUCT_ID "TinyUSB-MIDI2" #endif +// Function Block capabilities reported in Function Block Info Notification. +// The GTB descriptor carries direction and group span, but not these: they +// depend on what the application implements, so they default to "none". +#ifndef CFG_TUD_MIDI2_FB_CI_VERSION + #define CFG_TUD_MIDI2_FB_CI_VERSION 0 // 0: none or unknown, 1 or higher: MIDI-CI version +#endif + +#ifndef CFG_TUD_MIDI2_FB_SYSEX8_STREAMS + #define CFG_TUD_MIDI2_FB_SYSEX8_STREAMS 0 // 0: unsupported, 1: single, 2-255: simultaneous streams +#endif + // String descriptor index for the Group Terminal Block (iBlockItem, Table 5-6). // 0 = no string descriptor (default, spec-allowed). #ifndef CFG_TUD_MIDI2_BLOCK_STRIDX @@ -87,6 +76,39 @@ extern "C" { #endif //--------------------------------------------------------------------+ +// Group Terminal Block descriptor builders (USB-MIDI 2.0 Table 5-5/5-6) +//--------------------------------------------------------------------+ +// Group Terminal Block descriptor type and subtypes. +enum { + MIDI2_CS_GRP_TRM_BLOCK = 0x26, // bDescriptorType + MIDI2_GRP_TRM_BLOCK_HEADER = 0x01, // bDescriptorSubtype: list header + MIDI2_GRP_TRM_BLOCK_ENTRY = 0x02, // bDescriptorSubtype: block entry +}; + +// Block direction (bGrpTrmBlkType). +enum { + MIDI2_GTB_BIDIRECTIONAL = 0x00, + MIDI2_GTB_INPUT_ONLY = 0x01, + MIDI2_GTB_OUTPUT_ONLY = 0x02, +}; + +// GTB descriptor sizes (bytes). +enum { + MIDI2_GTB_HEADER_LEN = 5, // list header + MIDI2_GTB_ENTRY_LEN = 13, // one block entry +}; + +// Build a multi-block GTB descriptor for tud_midi2_gtb_desc_cb. Function Block +// Info is derived from these blocks (direction + group span). +#define TUD_MIDI2_GTB_DESC_LEN(_nblocks) (MIDI2_GTB_HEADER_LEN + MIDI2_GTB_ENTRY_LEN * (_nblocks)) +#define TUD_MIDI2_GTB_HEADER(_nblocks) \ + MIDI2_GTB_HEADER_LEN, MIDI2_CS_GRP_TRM_BLOCK, MIDI2_GRP_TRM_BLOCK_HEADER, \ + U16_TO_U8S_LE(TUD_MIDI2_GTB_DESC_LEN(_nblocks)) +#define TUD_MIDI2_GTB_BLOCK(_id, _type, _first_group, _num_groups, _stridx) \ + MIDI2_GTB_ENTRY_LEN, MIDI2_CS_GRP_TRM_BLOCK, MIDI2_GRP_TRM_BLOCK_ENTRY, \ + (_id), (_type), (_first_group), (_num_groups), (_stridx), 0x00, 0, 0, 0, 0 + +//--------------------------------------------------------------------+ // MIDI Protocol Values (returned by tud_midi2_n_protocol) //--------------------------------------------------------------------+ @@ -96,6 +118,28 @@ enum { MIDI_PROTOCOL_MIDI2 = 0x02, }; +// Result of the optional UMP Stream message callback (tud_midi2_stream_msg_cb). +// PASS lets the built-in responder handle the message; the others mean the +// application answered it. NEGOTIATED_* also record the protocol so +// tud_midi2_n_protocol / tud_midi2_n_negotiated stay accurate. +typedef enum { + MIDI2_STREAM_PASS = 0, + MIDI2_STREAM_HANDLED, + MIDI2_STREAM_NEGOTIATED_MIDI1, + MIDI2_STREAM_NEGOTIATED_MIDI2, +} tud_midi2_stream_result_t; + +// Device identity fields, as defined for the MIDI 1.0 Device Inquiry reply and +// reused by the Device Identity Notification. Every byte carries 7 bits. +// A 1-byte System Exclusive ID goes in the first of the three manufacturer +// bytes, so 0x7D is passed as 0x7D0000. +typedef struct { + uint32_t manufacturer; // 3 bytes, first byte is most significant + uint16_t family; // 2 bytes + uint16_t model; // 2 bytes + uint32_t sw_revision; // 4 bytes +} tud_midi2_device_identity_t; + //--------------------------------------------------------------------+ // Application Callback API (weak, optional) //--------------------------------------------------------------------+ @@ -104,11 +148,30 @@ void tud_midi2_set_itf_cb(uint8_t itf, uint8_t alt); bool tud_midi2_get_req_itf_cb(uint8_t rhport, const tusb_control_request_t* request); // Per-interface UMP Stream config (override for per-itf values). -uint8_t tud_midi2_num_groups_cb(uint8_t itf); -uint8_t tud_midi2_num_function_blocks_cb(uint8_t itf); const char* tud_midi2_ep_name_cb(uint8_t itf); const char* tud_midi2_product_id_cb(uint8_t itf); +// Group Terminal Block descriptor source: the single source of truth for block +// topology. Override to expose multiple blocks with independent directions and +// group spans. Function Block Info is derived from this descriptor. +const uint8_t* tud_midi2_gtb_desc_cb(uint8_t itf, uint16_t* len); + +// Optional per-block name, sent as a Function Block Name Notification during +// discovery. Return NULL or "" for no name. +const char* tud_midi2_fb_name_cb(uint8_t itf, uint8_t fb_idx); + +// Optional device identity, sent as a Device Identity Notification when the +// host sets the 'd' bit in the Endpoint Discovery filter. Same four fields as +// the MIDI 1.0 Device Inquiry reply. Return false to skip the notification, +// which is the default. All values are 7-bit per byte. +bool tud_midi2_device_identity_cb(uint8_t itf, tud_midi2_device_identity_t* identity); + +// Optional: intercept an incoming UMP Stream message (MT 0xF). Return PASS to +// let the built-in responder handle it, or HANDLED / NEGOTIATED_* if the app +// answered it (e.g. via tud_midi2_n_ump_write). Lets an app override a single +// response without reimplementing the whole negotiation. +tud_midi2_stream_result_t tud_midi2_stream_msg_cb(uint8_t itf, const uint32_t* ump_words); + //--------------------------------------------------------------------+ // Application API (Multiple Interfaces) //--------------------------------------------------------------------+ diff --git a/src/class/midi/midi2_host.c b/src/class/midi/midi2_host.c index 6d8861f4b..1e347159f 100644 --- a/src/class/midi/midi2_host.c +++ b/src/class/midi/midi2_host.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2026 Saulo Verissimo - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2026 Saulo Verissimo + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/midi/midi2_host.h b/src/class/midi/midi2_host.h index 47039eb85..95d68ffc2 100644 --- a/src/class/midi/midi2_host.h +++ b/src/class/midi/midi2_host.h @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2026 Saulo Verissimo - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2026 Saulo Verissimo + * SPDX-FileCopyrightText: Copyright (c) 2026 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c index de4ff5dd8..8a122215d 100644 --- a/src/class/midi/midi_device.c +++ b/src/class/midi/midi_device.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/midi/midi_device.h b/src/class/midi/midi_device.h index 57eabec1f..733bc7f75 100644 --- a/src/class/midi/midi_device.h +++ b/src/class/midi/midi_device.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index a53546404..67c9ec7ad 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/midi/midi_host.h b/src/class/midi/midi_host.h index 8fdfd8966..57084cb15 100644 --- a/src/class/midi/midi_host.h +++ b/src/class/midi/midi_host.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/msc/msc.h b/src/class/msc/msc.h index 3b5d4a855..9e9a3a692 100644 --- a/src/class/msc/msc.h +++ b/src/class/msc/msc.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c index 39dc3a074..8485105e4 100644 --- a/src/class/msc/msc_device.c +++ b/src/class/msc/msc_device.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/msc/msc_device.h b/src/class/msc/msc_device.h index 21e24971b..09d7cc426 100644 --- a/src/class/msc/msc_device.h +++ b/src/class/msc/msc_device.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c index 6a36c2820..8afd70705 100644 --- a/src/class/msc/msc_host.c +++ b/src/class/msc/msc_host.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/msc/msc_host.h b/src/class/msc/msc_host.h index 5dc7c0b94..e1396f85c 100644 --- a/src/class/msc/msc_host.h +++ b/src/class/msc/msc_host.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/mtp/mtp.h b/src/class/mtp/mtp.h index 7b22837cd..75af8baf8 100644 --- a/src/class/mtp/mtp.h +++ b/src/class/mtp/mtp.h @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2025 Ennebi Elettronica (https://ennebielettronica.com) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2025 Ennebi Elettronica (https://ennebielettronica.com) + * SPDX-FileCopyrightText: Copyright (c) 2025 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/mtp/mtp_device.c b/src/class/mtp/mtp_device.c index 1f76dfcc7..275c9f858 100644 --- a/src/class/mtp/mtp_device.c +++ b/src/class/mtp/mtp_device.c @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2025 Ennebi Elettronica (https://ennebielettronica.com) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2025 Ennebi Elettronica (https://ennebielettronica.com) + * SPDX-FileCopyrightText: Copyright (c) 2025 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -455,8 +437,11 @@ bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t TU_LOG_DRV(" MTP Data %s CB: xferred_bytes=%lu, xferred_len/total_len=%lu/%lu, is_complete=%d\r\n", is_data_in ? "IN" : "OUT", xferred_bytes, p_mtp->xferred_len, p_mtp->total_len, is_complete ? 1 : 0); - // Send/queue ZLP if packet is full-sized but transfer is complete - if (is_complete && xferred_bytes > 0 && !(xferred_bytes & (threshold - 1))) { + // Send/queue ZLP if packet is full-sized but transfer is complete. + // OUT must deliver this final payload to the application before receiving + // its terminating ZLP below. + const bool need_zlp = is_complete && xferred_bytes > 0 && !(xferred_bytes & (threshold - 1)); + if (is_data_in && need_zlp) { TU_LOG_DRV(" queue ZLP\r\n"); TU_VERIFY(usbd_edpt_claim(p_mtp->rhport, ep_addr)); TU_ASSERT(usbd_edpt_xfer(p_mtp->rhport, ep_addr, NULL, 0, false)); @@ -484,9 +469,16 @@ bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t cb_data.io_container = headerless_packet; cb_data.io_container.payload_bytes = xferred_bytes; } - tud_mtp_data_xfer_cb(&cb_data); + if (xferred_bytes > 0) { + tud_mtp_data_xfer_cb(&cb_data); + } - if (is_complete) { + if (need_zlp) { + TU_LOG_DRV(" queue ZLP\r\n"); + TU_VERIFY(usbd_edpt_claim(p_mtp->rhport, ep_addr)); + TU_ASSERT(usbd_edpt_xfer(p_mtp->rhport, ep_addr, NULL, 0, false)); + return true; + } else if (is_complete) { // back to header + payload for response cb_data.io_container = headered_packet; cb_data.io_container.header->len = sizeof(mtp_container_header_t); diff --git a/src/class/mtp/mtp_device.h b/src/class/mtp/mtp_device.h index f2c5cef7f..b2c4f1e04 100644 --- a/src/class/mtp/mtp_device.h +++ b/src/class/mtp/mtp_device.h @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2025 Ennebi Elettronica (https://ennebielettronica.com) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2025 Ennebi Elettronica (https://ennebielettronica.com) + * SPDX-FileCopyrightText: Copyright (c) 2025 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/net/ecm_rndis_device.c b/src/class/net/ecm_rndis_device.c index 643bcfbcd..b1ac2e8fd 100644 --- a/src/class/net/ecm_rndis_device.c +++ b/src/class/net/ecm_rndis_device.c @@ -1,26 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2020 Peter Lawrence - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2020 Peter Lawrence + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -343,8 +324,11 @@ static void handle_incoming_packet(uint32_t len) { rndis_data_packet_t* r = (rndis_data_packet_t*)((void*)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 = &_netd_epbuf.rx[r->DataOffset + offsetof(rndis_data_packet_t, DataOffset)]; + // DataOffset and DataLength are host-controlled; validate the payload window fits + // within the received data without overflowing the uint32 addition (len >= header) + const uint32_t hdr = offsetof(rndis_data_packet_t, DataOffset); + if ((r->DataOffset <= len - hdr) && (r->DataLength <= len - hdr - r->DataOffset)) { + pnt = &_netd_epbuf.rx[hdr + r->DataOffset]; size = r->DataLength; } } diff --git a/src/class/net/ncm.h b/src/class/net/ncm.h index 27ff89b72..073e86157 100644 --- a/src/class/net/ncm.h +++ b/src/class/net/ncm.h @@ -1,26 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021, Ha Thach (tinyusb.org) - * Copyright (c) 2024, Hardy Griech - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021, Ha Thach (tinyusb.org) + * SPDX-FileCopyrightText: Copyright (c) 2024, Hardy Griech + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/net/ncm_device.c b/src/class/net/ncm_device.c index e5f441300..72b592787 100644 --- a/src/class/net/ncm_device.c +++ b/src/class/net/ncm_device.c @@ -1,28 +1,9 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * Copyright (c) 2024 Hardy Griech - * Copyright (c) 2020 Jacob Berg Potter - * Copyright (c) 2020 Peter Lawrence - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-FileCopyrightText: Copyright (c) 2024 Hardy Griech + * SPDX-FileCopyrightText: Copyright (c) 2020 Jacob Berg Potter + * SPDX-FileCopyrightText: Copyright (c) 2020 Peter Lawrence + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -621,7 +602,7 @@ static bool recv_validate_datagram(const recv_ntb_t *ntb, uint32_t len) { TU_LOG_DRV("(EE) ill block length2: %d > %d\n", nth16->wBlockLength, CFG_TUD_NCM_OUT_NTB_MAX_SIZE); return false; } - if (nth16->wNdpIndex < sizeof(nth16) || nth16->wNdpIndex > len - (sizeof(ndp16_t) + 2 * sizeof(ndp16_datagram_t))) { + if (nth16->wNdpIndex < sizeof(nth16_t) || nth16->wNdpIndex > len - (sizeof(ndp16_t) + 2 * sizeof(ndp16_datagram_t))) { TU_LOG_DRV("(EE) ill position of first ndp: %d (%lu)\n", nth16->wNdpIndex, len); return false; } @@ -633,6 +614,12 @@ static bool recv_validate_datagram(const recv_ntb_t *ntb, uint32_t len) { TU_LOG_DRV("(EE) ill ndp16 length: %d\n", ndp16->wLength); return false; } + // the NDP block (wLength bytes from wNdpIndex) must fit within the received NTB, otherwise the + // datagram pointer array walked below (max_ndx is derived from wLength) runs past ntb->data + if ((uint32_t) nth16->wNdpIndex + ndp16->wLength > len) { + TU_LOG_DRV("(EE) ill ndp16 length: %d (%lu)\n", ndp16->wLength, len); + return false; + } if (ndp16->dwSignature != NDP16_SIGNATURE_NCM0 && ndp16->dwSignature != NDP16_SIGNATURE_NCM1) { TU_LOG_DRV("(EE) ill signature: 0x%08x\n", (unsigned) ndp16->dwSignature); return false; @@ -813,31 +800,56 @@ static void tud_network_recv_renew_r(uint8_t rhport) { } // tud_network_recv_renew /** - * Set the link state and send notification to host + * usbd-task trampoline for tud_network_link_state(), packing rhport and is_up + * into a single pointer-sized argument. + * + * Runs entirely in the usbd task context, so it cannot race the notify + * xfer-completion callback over the notification state machine. Re-arming + * notification_xmit_state and kicking notification_xmit() (rather than + * sending NETWORK_CONNECTION directly) means a state change that collides + * with an in-flight notification is picked up by the existing completion + * callback instead of being silently dropped - which would otherwise leave + * the host stuck at NO-CARRIER after a link-state change. */ -void tud_network_link_state(uint8_t rhport, bool is_up) { - TU_LOG_DRV("tud_network_link_state(%d, %d)\n", rhport, is_up); +static void ncm_link_state_task(void *param) { + uintptr_t const arg = (uintptr_t) param; + uint8_t const rhport = (uint8_t) (arg >> 1); + bool const is_up = (arg & 1u) != 0; if (ncm_interface.link_is_up == is_up) { - // No change in link state - return; + return; // no change in link state } ncm_interface.link_is_up = is_up; - // Only send notification if we have an active data interface if (ncm_interface.itf_data_alt != 1) { - TU_LOG_DRV(" link state notification skipped (interface not active)\n"); - return; + TU_LOG_DRV(" link state notification deferred (interface not active)\n"); + return; // data interface not active yet; SET_INTERFACE(alt=1) will notify } - // Reset notification state to send speed change notification first, then link state notification + // A link toggle does not change the link speed, so strictly only the + // NETWORK_CONNECTION notification would need (re)sending. Re-running the + // speed-then-connection sequence keeps this on the same state machine the + // completion callback already drives, at the cost of a redundant speed + // notification on every toggle. ncm_interface.notification_xmit_state = NOTIFICATION_SPEED; - - // Trigger notification transmission notification_xmit(rhport, false); } +/** + * Set the link state and notify the host. + * + * Defers onto the usbd task so a caller running in a different task than + * tud_task() cannot race the notification state machine against the notify + * xfer-completion callback. + */ +void tud_network_link_state(uint8_t rhport, bool is_up) { + TU_LOG_DRV("tud_network_link_state(%d, %d)\n", rhport, is_up); + + uintptr_t const arg = ((uintptr_t) rhport << 1) | (is_up ? 1u : 0u); + usbd_defer_func(ncm_link_state_task, (void *) arg, false); +} + //----------------------------------------------------------------------------- // // all the netd_*() stuff (interface TinyUSB -> driver) diff --git a/src/class/net/net_device.h b/src/class/net/net_device.h index 1ad069d92..47f88352f 100644 --- a/src/class/net/net_device.h +++ b/src/class/net/net_device.h @@ -1,26 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2020 Peter Lawrence - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2020 Peter Lawrence + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/printer/printer.h b/src/class/printer/printer.h index 09d1a8956..25e0fc700 100644 --- a/src/class/printer/printer.h +++ b/src/class/printer/printer.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2026 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2026 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/printer/printer_device.c b/src/class/printer/printer_device.c index 158455fc9..bcb6d1d53 100644 --- a/src/class/printer/printer_device.c +++ b/src/class/printer/printer_device.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2026 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2026 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/printer/printer_device.h b/src/class/printer/printer_device.h index afde1f022..eef21102f 100644 --- a/src/class/printer/printer_device.h +++ b/src/class/printer/printer_device.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2026 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2026 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/usbtmc/usbtmc.h b/src/class/usbtmc/usbtmc.h index 3bf5e1a17..bb150cd50 100644 --- a/src/class/usbtmc/usbtmc.h +++ b/src/class/usbtmc/usbtmc.h @@ -1,26 +1,7 @@ - /* - * The MIT License (MIT) - * - * Copyright (c) 2019 N Conrad - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Nathan Conrad + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/usbtmc/usbtmc_device.c b/src/class/usbtmc/usbtmc_device.c index 4b0bb01ec..0e9978a81 100644 --- a/src/class/usbtmc/usbtmc_device.c +++ b/src/class/usbtmc/usbtmc_device.c @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Nathan Conrad - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Nathan Conrad + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -270,9 +252,12 @@ bool tud_usbtmc_transmit_notification_data(const void *data, size_t len) { TU_ASSERT(len > 0); TU_ASSERT(usbtmc_state.ep_int_in != 0); #endif - TU_VERIFY(usbd_edpt_busy(usbtmc_state.rhport, usbtmc_state.ep_int_in)); + TU_VERIFY(usbd_edpt_claim(usbtmc_state.rhport, usbtmc_state.ep_int_in)); - TU_VERIFY(tu_memcpy_s(usbtmc_epbuf.epnotif, CFG_TUD_USBTMC_INT_EP_SIZE, data, len) == 0); + if (tu_memcpy_s(usbtmc_epbuf.epnotif, CFG_TUD_USBTMC_INT_EP_SIZE, data, len) != 0) { + usbd_edpt_release(usbtmc_state.rhport, usbtmc_state.ep_int_in); + return false; + } TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_int_in, usbtmc_epbuf.epnotif, (uint16_t) len, false)); return true; } @@ -512,9 +497,24 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint #if (CFG_TUD_USBTMC_ENABLE_488) case USBTMC_MSGID_USB488_TRIGGER: - // Spec says we halt the EP if we didn't declare we support it. - TU_VERIFY(usbtmc_state.capabilities->bmIntfcCapabilities488.supportsTrigger); - TU_VERIFY(tud_usbtmc_msg_trigger_cb(msg)); + // Unlike the messages above, TRIGGER is complete on arrival and has no response, so nothing else + // will move us out of STATE_IDLE. Do it here, otherwise the tud_usbtmc_start_bus_read() below (and + // any call the application makes from its callback) is a no-op and the bulk-OUT endpoint is left + // un-armed, silently timing out every subsequent host transfer. + TU_VERIFY(atomicChangeState(STATE_IDLE, STATE_NAK)); + + // Spec says we halt the EP if we didn't declare we support it; do the same when the application + // rejects the trigger. The callback result must not be wrapped in TU_VERIFY() here: returning + // early would skip both the stall and the re-arm below. + if (!usbtmc_state.capabilities->bmIntfcCapabilities488.supportsTrigger || + !tud_usbtmc_msg_trigger_cb(msg)) { + usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); + return false; + } + // Result deliberately ignored: false here means the endpoint is already armed - either the + // application re-armed it from its callback, or a transfer is still queued - not that arming + // failed. Stalling on it would halt a healthy endpoint. + tud_usbtmc_start_bus_read(); break; #endif @@ -841,7 +841,7 @@ bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request }, .StatusByte = tud_usbtmc_get_stb_cb(&(rsp.USBTMC_status))}; // Must be queued before control request response sent (USB488v1.0 4.3.1.2) - usbd_edpt_xfer(rhport, usbtmc_state.ep_int_in, (void *) &intMsg, sizeof(intMsg), false); + (void) tud_usbtmc_transmit_notification_data(&intMsg, sizeof(intMsg)); } } else { rsp.statusByte = tud_usbtmc_get_stb_cb(&(rsp.USBTMC_status)); diff --git a/src/class/usbtmc/usbtmc_device.h b/src/class/usbtmc/usbtmc_device.h index 235f1276e..efda84f16 100644 --- a/src/class/usbtmc/usbtmc_device.h +++ b/src/class/usbtmc/usbtmc_device.h @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 N Conrad - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Nathan Conrad + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -43,7 +25,6 @@ // * tud_usbtmc_open_cb // * tud_usbtmc_msg_data_cb // * tud_usbtmc_msgBulkIn_complete_cb -// * tud_usbtmc_msg_trigger_cb // * (successful) tud_usbtmc_check_abort_bulk_out_cb // * (successful) tud_usbtmc_check_abort_bulk_in_cb // * (successful) tud_usmtmc_bulkOut_clearFeature_cb diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c index e1017ba48..c4a550ef0 100644 --- a/src/class/vendor/vendor_device.c +++ b/src/class/vendor/vendor_device.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -40,6 +21,28 @@ typedef struct { uint8_t rhport; uint8_t itf_num; + #if CFG_TUD_VENDOR_EP_INT_OUT + uint8_t ep_int_out; + uint16_t int_rx_xfer_len; + #endif + #if CFG_TUD_VENDOR_EP_INT_IN + uint8_t ep_int_in; + #endif + #if CFG_TUD_VENDOR_EP_ISO_OUT + uint8_t ep_iso_out; + uint16_t iso_rx_xfer_len; + const tusb_desc_endpoint_t* iso_out_desc; // for deactivation on altsetting de-selection + #endif + #if CFG_TUD_VENDOR_EP_ISO_IN + uint8_t ep_iso_in; + const tusb_desc_endpoint_t* iso_in_desc; // for deactivation on altsetting de-selection + #endif + #if CFG_TUD_VENDOR_ALT_SETTINGS // implies non-buffered: fields cleared by bus reset + uint8_t cur_alt; + const uint8_t* p_itf_desc; // whole interface block incl. all altsettings (static app descriptor) + uint16_t itf_desc_len; + #endif + #if CFG_TUD_VENDOR_TXRX_BUFFERED /*------------- From this point, data is not cleared by bus reset -------------*/ tu_edpt_stream_t tx_stream; @@ -54,7 +57,10 @@ typedef struct { } vendord_interface_t; #if CFG_TUD_VENDOR_TXRX_BUFFERED - #define ITF_MEM_RESET_SIZE (offsetof(vendord_interface_t, itf_num) + TU_FIELD_SIZE(vendord_interface_t, itf_num)) + // The reset region is everything before the streams; tx_stream is the first preserved field + // (see the struct comment), so its offset is exactly that boundary regardless of which endpoint + // gates are enabled. + #define ITF_MEM_RESET_SIZE offsetof(vendord_interface_t, tx_stream) #else #define ITF_MEM_RESET_SIZE sizeof(vendord_interface_t) #endif @@ -71,6 +77,32 @@ typedef struct { CFG_TUD_MEM_SECTION static vendord_epbuf_t _vendord_epbuf[CFG_TUD_VENDOR]; #endif +#if CFG_TUD_VENDOR_EP_INT_OUT || CFG_TUD_VENDOR_EP_INT_IN +typedef struct { + #if CFG_TUD_VENDOR_EP_INT_OUT + TUD_EPBUF_DEF(int_out, CFG_TUD_VENDOR_EP_INT_OUT_BUFSIZE); + #endif + #if CFG_TUD_VENDOR_EP_INT_IN + TUD_EPBUF_DEF(int_in, CFG_TUD_VENDOR_EP_INT_IN_BUFSIZE); + #endif +} vendord_int_epbuf_t; + +CFG_TUD_MEM_SECTION static vendord_int_epbuf_t _vendord_int_epbuf[CFG_TUD_VENDOR]; +#endif + +#if CFG_TUD_VENDOR_EP_ISO_OUT || CFG_TUD_VENDOR_EP_ISO_IN +typedef struct { + #if CFG_TUD_VENDOR_EP_ISO_OUT + TUD_EPBUF_DEF(iso_out, CFG_TUD_VENDOR_EP_ISO_OUT_BUFSIZE); + #endif + #if CFG_TUD_VENDOR_EP_ISO_IN + TUD_EPBUF_DEF(iso_in, CFG_TUD_VENDOR_EP_ISO_IN_BUFSIZE); + #endif +} vendord_iso_epbuf_t; + +CFG_TUD_MEM_SECTION static vendord_iso_epbuf_t _vendord_iso_epbuf[CFG_TUD_VENDOR]; +#endif + //--------------------------------------------------------------------+ // Weak stubs: invoked if no strong implementation is available //--------------------------------------------------------------------+ @@ -85,15 +117,61 @@ TU_ATTR_WEAK void tud_vendor_tx_cb(uint8_t idx, uint32_t sent_bytes) { (void) sent_bytes; } +#if CFG_TUD_VENDOR_EP_INT_OUT +TU_ATTR_WEAK void tud_vendor_int_rx_cb(uint8_t idx, const uint8_t *buffer, uint32_t bufsize) { + (void)idx; + (void)buffer; + (void)bufsize; +} +#endif + +#if CFG_TUD_VENDOR_EP_INT_IN +TU_ATTR_WEAK void tud_vendor_int_tx_cb(uint8_t idx, uint32_t sent_bytes) { + (void)idx; + (void)sent_bytes; +} +#endif + +#if CFG_TUD_VENDOR_EP_ISO_OUT +TU_ATTR_WEAK void tud_vendor_iso_rx_cb(uint8_t idx, const uint8_t *buffer, uint32_t bufsize) { + (void)idx; + (void)buffer; + (void)bufsize; +} +#endif + +#if CFG_TUD_VENDOR_EP_ISO_IN +TU_ATTR_WEAK void tud_vendor_iso_tx_cb(uint8_t idx, uint32_t sent_bytes) { + (void)idx; + (void)sent_bytes; +} +#endif + bool tud_vendor_n_mounted(uint8_t idx) { TU_VERIFY(idx < CFG_TUD_VENDOR); vendord_interface_t *p_itf = &_vendord_itf[idx]; + // bulk may be absent (interrupt-only vendor interface): count the interrupt endpoints too #if CFG_TUD_VENDOR_TXRX_BUFFERED - return (p_itf->rx_stream.ep_addr != 0) || (p_itf->tx_stream.ep_addr != 0); + bool mounted = (p_itf->rx_stream.ep_addr != 0) || (p_itf->tx_stream.ep_addr != 0); #else - return (p_itf->ep_out != 0) || (p_itf->ep_in != 0); + bool mounted = (p_itf->ep_out != 0) || (p_itf->ep_in != 0); + #endif + #if CFG_TUD_VENDOR_EP_INT_OUT + mounted = mounted || (p_itf->ep_int_out != 0); + #endif + #if CFG_TUD_VENDOR_EP_INT_IN + mounted = mounted || (p_itf->ep_int_in != 0); #endif + // an altsetting may expose only isochronous endpoints; count them so apps that gate an iso + // pump on tud_vendor_mounted() still arm it + #if CFG_TUD_VENDOR_EP_ISO_OUT + mounted = mounted || (p_itf->ep_iso_out != 0); + #endif + #if CFG_TUD_VENDOR_EP_ISO_IN + mounted = mounted || (p_itf->ep_iso_in != 0); + #endif + return mounted; } //--------------------------------------------------------------------+ @@ -126,6 +204,30 @@ void tud_vendor_n_read_flush(uint8_t idx) { } #endif +// Shared non-buffered transfer helpers for the bulk / interrupt / isochronous endpoints, which are +// identical apart from the endpoint, its epbuf and its buffer size. TU_ATTR_UNUSED: in buffered +// mode with the int/iso gates off none is referenced, and clang/IAR error on an unused static. +TU_ATTR_UNUSED static inline uint32_t vendord_ep_write(vendord_interface_t *p_itf, uint8_t ep, uint8_t *epbuf, + uint32_t bufsize, const void *buffer, uint32_t len) { + TU_VERIFY(ep > 0, 0); // must be opened + TU_VERIFY(usbd_edpt_claim(p_itf->rhport, ep), 0); + const uint32_t xact_len = tu_min32(len, bufsize); + memcpy(epbuf, buffer, xact_len); + TU_ASSERT(usbd_edpt_xfer(p_itf->rhport, ep, epbuf, (uint16_t) xact_len, false), 0); + return xact_len; +} + +TU_ATTR_UNUSED static inline uint32_t vendord_ep_write_available(vendord_interface_t *p_itf, uint8_t ep, uint32_t bufsize) { + TU_VERIFY(ep > 0, 0); // must be opened + return usbd_edpt_busy(p_itf->rhport, ep) ? 0 : bufsize; +} + +TU_ATTR_UNUSED static inline bool vendord_ep_read_xfer(vendord_interface_t *p_itf, uint8_t ep, uint8_t *epbuf, uint16_t xfer_len) { + TU_VERIFY(ep > 0); // must be opened + TU_VERIFY(usbd_edpt_claim(p_itf->rhport, ep)); + return usbd_edpt_xfer(p_itf->rhport, ep, epbuf, xfer_len, false); +} + #if CFG_TUD_VENDOR_RX_MANUAL_XFER bool tud_vendor_n_read_xfer(uint8_t idx) { TU_VERIFY(idx < CFG_TUD_VENDOR); @@ -135,9 +237,8 @@ bool tud_vendor_n_read_xfer(uint8_t idx) { return tu_edpt_stream_read_xfer(&p_itf->rx_stream); #else - // Non-FIFO mode - TU_VERIFY(usbd_edpt_claim(p_itf->rhport, p_itf->ep_out)); - return usbd_edpt_xfer(p_itf->rhport, p_itf->ep_out, _vendord_epbuf[idx].epout, p_itf->rx_xfer_len, false); + // Non-FIFO mode (0 while an altsetting without a bulk OUT ep is active) + return vendord_ep_read_xfer(p_itf, p_itf->ep_out, _vendord_epbuf[idx].epout, p_itf->rx_xfer_len); #endif } #endif @@ -154,12 +255,8 @@ uint32_t tud_vendor_n_write(uint8_t idx, const void *buffer, uint32_t bufsize) { return tu_edpt_stream_write(&p_itf->tx_stream, buffer, (uint16_t)bufsize); #else - // non-fifo mode: direct transfer - TU_VERIFY(usbd_edpt_claim(p_itf->rhport, p_itf->ep_in), 0); - const uint32_t xact_len = tu_min32(bufsize, CFG_TUD_VENDOR_TX_EPSIZE); - memcpy(_vendord_epbuf[idx].epin, buffer, xact_len); - TU_ASSERT(usbd_edpt_xfer(p_itf->rhport, p_itf->ep_in, _vendord_epbuf[idx].epin, (uint16_t)xact_len, false), 0); - return xact_len; + // non-fifo mode: direct transfer (ep_in is 0 while an altsetting without a bulk IN ep is active) + return vendord_ep_write(p_itf, p_itf->ep_in, _vendord_epbuf[idx].epin, CFG_TUD_VENDOR_TX_EPSIZE, buffer, bufsize); #endif } @@ -171,9 +268,7 @@ uint32_t tud_vendor_n_write_available(uint8_t idx) { return tu_edpt_stream_write_available(&p_itf->tx_stream); #else - // Non-FIFO mode - TU_VERIFY(p_itf->ep_in > 0, 0); // must be opened - return usbd_edpt_busy(p_itf->rhport, p_itf->ep_in) ? 0 : CFG_TUD_VENDOR_TX_EPSIZE; + return vendord_ep_write_available(p_itf, p_itf->ep_in, CFG_TUD_VENDOR_TX_EPSIZE); #endif } @@ -193,6 +288,63 @@ bool tud_vendor_n_write_clear(uint8_t idx) { #endif //--------------------------------------------------------------------+ +// Interrupt endpoint API +//--------------------------------------------------------------------+ +#if CFG_TUD_VENDOR_EP_INT_OUT +bool tud_vendor_n_int_read_xfer(uint8_t idx) { + TU_VERIFY(idx < CFG_TUD_VENDOR); + vendord_interface_t *p_itf = &_vendord_itf[idx]; + return vendord_ep_read_xfer(p_itf, p_itf->ep_int_out, _vendord_int_epbuf[idx].int_out, p_itf->int_rx_xfer_len); +} +#endif + +#if CFG_TUD_VENDOR_EP_INT_IN +uint32_t tud_vendor_n_int_write(uint8_t idx, const void *buffer, uint32_t bufsize) { + TU_VERIFY(idx < CFG_TUD_VENDOR, 0); + vendord_interface_t *p_itf = &_vendord_itf[idx]; + return vendord_ep_write(p_itf, p_itf->ep_int_in, _vendord_int_epbuf[idx].int_in, CFG_TUD_VENDOR_EP_INT_IN_BUFSIZE, buffer, bufsize); +} + +uint32_t tud_vendor_n_int_write_available(uint8_t idx) { + TU_VERIFY(idx < CFG_TUD_VENDOR, 0); + vendord_interface_t *p_itf = &_vendord_itf[idx]; + return vendord_ep_write_available(p_itf, p_itf->ep_int_in, CFG_TUD_VENDOR_EP_INT_IN_BUFSIZE); +} +#endif + +//--------------------------------------------------------------------+ +// Isochronous endpoint API +//--------------------------------------------------------------------+ +#if CFG_TUD_VENDOR_EP_ISO_OUT +bool tud_vendor_n_iso_read_xfer(uint8_t idx) { + TU_VERIFY(idx < CFG_TUD_VENDOR); + vendord_interface_t *p_itf = &_vendord_itf[idx]; + return vendord_ep_read_xfer(p_itf, p_itf->ep_iso_out, _vendord_iso_epbuf[idx].iso_out, p_itf->iso_rx_xfer_len); +} +#endif + +#if CFG_TUD_VENDOR_EP_ISO_IN +uint32_t tud_vendor_n_iso_write(uint8_t idx, const void *buffer, uint32_t bufsize) { + TU_VERIFY(idx < CFG_TUD_VENDOR, 0); + vendord_interface_t *p_itf = &_vendord_itf[idx]; + return vendord_ep_write(p_itf, p_itf->ep_iso_in, _vendord_iso_epbuf[idx].iso_in, CFG_TUD_VENDOR_EP_ISO_IN_BUFSIZE, buffer, bufsize); +} + +uint32_t tud_vendor_n_iso_write_available(uint8_t idx) { + TU_VERIFY(idx < CFG_TUD_VENDOR, 0); + vendord_interface_t *p_itf = &_vendord_itf[idx]; + return vendord_ep_write_available(p_itf, p_itf->ep_iso_in, CFG_TUD_VENDOR_EP_ISO_IN_BUFSIZE); +} +#endif + +#if CFG_TUD_VENDOR_ALT_SETTINGS +uint8_t tud_vendor_n_alt(uint8_t idx) { + TU_VERIFY(idx < CFG_TUD_VENDOR, 0); + return _vendord_itf[idx].cur_alt; +} +#endif + +//--------------------------------------------------------------------+ // USBD Driver API //--------------------------------------------------------------------+ void vendord_init(void) { @@ -251,17 +403,61 @@ static uint8_t find_vendor_itf(uint8_t ep_addr) { for (uint8_t idx = 0; idx < CFG_TUD_VENDOR; idx++) { const vendord_interface_t *p_vendor = &_vendord_itf[idx]; if (ep_addr == 0) { - // find unused: require both ep == 0 - #if CFG_TUD_VENDOR_TXRX_BUFFERED - if (p_vendor->rx_stream.ep_addr == 0 && p_vendor->tx_stream.ep_addr == 0) { + // find unused interface slot + #if CFG_TUD_VENDOR_ALT_SETTINGS + // an opened interface parked in an altsetting without endpoints (the mandatory empty alt 0) + // has all ep fields 0, so the endpoint fields cannot distinguish free from open: use p_itf_desc + if (p_vendor->p_itf_desc == NULL) { + return idx; + } + #elif CFG_TUD_VENDOR_TXRX_BUFFERED + // A slot is free only if none of its endpoints are assigned; bulk may be absent + // (an interrupt-only vendor interface), so check the interrupt endpoints too. + if (p_vendor->rx_stream.ep_addr == 0 && p_vendor->tx_stream.ep_addr == 0 + #if CFG_TUD_VENDOR_EP_INT_OUT + && p_vendor->ep_int_out == 0 + #endif + #if CFG_TUD_VENDOR_EP_INT_IN + && p_vendor->ep_int_in == 0 + #endif + ) { return idx; } #else - if (p_vendor->ep_out == 0 && p_vendor->ep_in == 0) { + // A slot is free only if none of its endpoints are assigned. Bulk may be absent (an + // interrupt-only vendor interface), so the interrupt endpoints must be checked too. + if (p_vendor->ep_out == 0 && p_vendor->ep_in == 0 + #if CFG_TUD_VENDOR_EP_INT_OUT + && p_vendor->ep_int_out == 0 + #endif + #if CFG_TUD_VENDOR_EP_INT_IN + && p_vendor->ep_int_in == 0 + #endif + ) { return idx; } #endif } else { + #if CFG_TUD_VENDOR_EP_INT_OUT + if (ep_addr == p_vendor->ep_int_out) { + return idx; + } + #endif + #if CFG_TUD_VENDOR_EP_INT_IN + if (ep_addr == p_vendor->ep_int_in) { + return idx; + } + #endif + #if CFG_TUD_VENDOR_EP_ISO_OUT + if (ep_addr == p_vendor->ep_iso_out) { + return idx; + } + #endif + #if CFG_TUD_VENDOR_EP_ISO_IN + if (ep_addr == p_vendor->ep_iso_in) { + return idx; + } + #endif #if CFG_TUD_VENDOR_TXRX_BUFFERED if (ep_addr == p_vendor->rx_stream.ep_addr || ep_addr == p_vendor->tx_stream.ep_addr) { return idx; @@ -276,6 +472,287 @@ static uint8_t find_vendor_itf(uint8_t ep_addr) { return 0xff; } +#if CFG_TUD_VENDOR_ALT_SETTINGS + +// Reserve an isochronous endpoint at open time. Ports with a dedicated iso allocator +// (TUP_DCD_EDPT_ISO_ALLOC) reserve the FIFO here and (re)activate on altsetting selection; +// ports with dcd_edpt_close instead open it once here (open == allocate + activate). +static inline bool vendord_iso_ep_alloc(uint8_t rhport, const tusb_desc_endpoint_t* desc_ep) { + #ifdef TUP_DCD_EDPT_ISO_ALLOC + return usbd_edpt_iso_alloc(rhport, desc_ep->bEndpointAddress, tu_edpt_packet_size(desc_ep)); + #else + return usbd_edpt_open(rhport, desc_ep); + #endif +} + +// Deactivate a de-selected altsetting's isochronous endpoint: abort any in-flight +// transfer and release its usbd claim so a stale completion cannot fire into a +// no-longer-tracked endpoint (iso cannot be stalled like bulk/interrupt below). With the +// iso-alloc API, (re)activation with the endpoint's descriptor is the abort/scrub +// primitive; without it, close does (the next selection re-opens). +static inline void vendord_iso_ep_deactivate(uint8_t rhport, const tusb_desc_endpoint_t* desc_ep) { + if (desc_ep != NULL) { + #ifdef TUP_DCD_EDPT_ISO_ALLOC + usbd_edpt_iso_activate(rhport, desc_ep); + #else + usbd_edpt_close(rhport, desc_ep->bEndpointAddress); + #endif + } +} + +// (Re)activate an isochronous endpoint on altsetting selection. +static inline bool vendord_iso_ep_activate(uint8_t rhport, const tusb_desc_endpoint_t* desc_ep) { + #ifdef TUP_DCD_EDPT_ISO_ALLOC + return usbd_edpt_iso_activate(rhport, desc_ep); // resets ep_status, aborting any stale transfer + #else + // No iso alloc/activate API: close (which zeros ep_status and frees a stale claim left by a + // prior selection) then re-open, so a re-selected altsetting starts from a clean state. + usbd_edpt_close(rhport, desc_ep->bEndpointAddress); + return usbd_edpt_open(rhport, desc_ep); + #endif +} + +// Abort any in-flight transfer on a tracked endpoint and release its usbd claim; no-op for an +// unset (0) address. stall disables the endpoint in the dcd, clear-stall resets it to DATA0. +static inline void vendord_abort_ep(uint8_t rhport, uint8_t ep_addr) { + if (ep_addr) { + usbd_edpt_stall(rhport, ep_addr); + usbd_edpt_clear_stall(rhport, ep_addr); + } +} + +// Select an altsetting. Endpoints were hardware-opened once at vendord_open (dcds like +// dwc2 allocate FIFO linearly and cannot close/re-open endpoints dynamically): switching +// only re-targets the API to the selected altsetting's endpoints. Bulk/interrupt +// endpoints get a stall/clear-stall cycle, which portably aborts any in-flight transfer +// (stall disables the endpoint in the dcd) and resets the data toggle to DATA0 as +// SET_INTERFACE requires. Isochronous endpoints are (re)activated, which does the same. +// Single pass: the current altsetting's endpoints are dropped only once the target altsetting +// is confirmed present, so a SET_INTERFACE to an unknown alt leaves the interface intact. +static bool vendord_set_alt(uint8_t rhport, uint8_t idx, uint8_t alt) { + vendord_interface_t *p_vendor = &_vendord_itf[idx]; + const uint8_t* p_desc = p_vendor->p_itf_desc; + const uint8_t* desc_end = p_desc + p_vendor->itf_desc_len; + bool in_target_alt = false; + bool alt_found = false; + + while (tu_desc_in_bounds(p_desc, desc_end)) { + const uint8_t desc_type = tu_desc_type(p_desc); + if (desc_type == TUSB_DESC_INTERFACE) { + in_target_alt = (((const tusb_desc_interface_t*)p_desc)->bAlternateSetting == alt); + if (in_target_alt && !alt_found) { + alt_found = true; + // target altsetting confirmed present: abort then drop the previous altsetting's endpoints, + // so an endpoint absent from the target altsetting can't stay armed and keep its usbd + // claim in the dcd. (Endpoints the target altsetting reuses are reset again below; + // a double reset is harmless.) + vendord_abort_ep(rhport, p_vendor->ep_in); + vendord_abort_ep(rhport, p_vendor->ep_out); + #if CFG_TUD_VENDOR_EP_INT_OUT + vendord_abort_ep(rhport, p_vendor->ep_int_out); + #endif + #if CFG_TUD_VENDOR_EP_INT_IN + vendord_abort_ep(rhport, p_vendor->ep_int_in); + #endif + p_vendor->ep_in = 0; + p_vendor->ep_out = 0; + #if CFG_TUD_VENDOR_EP_INT_OUT + p_vendor->ep_int_out = 0; + #endif + #if CFG_TUD_VENDOR_EP_INT_IN + p_vendor->ep_int_in = 0; + #endif + #if CFG_TUD_VENDOR_EP_ISO_OUT + vendord_iso_ep_deactivate(rhport, p_vendor->iso_out_desc); + p_vendor->iso_out_desc = NULL; + p_vendor->ep_iso_out = 0; + #endif + #if CFG_TUD_VENDOR_EP_ISO_IN + vendord_iso_ep_deactivate(rhport, p_vendor->iso_in_desc); + p_vendor->iso_in_desc = NULL; + p_vendor->ep_iso_in = 0; + #endif + } + } else if (in_target_alt && desc_type == TUSB_DESC_ENDPOINT) { + const tusb_desc_endpoint_t* desc_ep = (const tusb_desc_endpoint_t*) p_desc; + const uint8_t ep_addr = desc_ep->bEndpointAddress; + const bool is_in = tu_edpt_dir(ep_addr) == TUSB_DIR_IN; + (void) is_in; + + switch (desc_ep->bmAttributes.xfer) { + case TUSB_XFER_BULK: + // abort in-flight transfer + reset data toggle + usbd_edpt_stall(rhport, ep_addr); + usbd_edpt_clear_stall(rhport, ep_addr); + if (is_in) { + p_vendor->ep_in = ep_addr; + } else { + p_vendor->ep_out = ep_addr; + p_vendor->rx_xfer_len = + CFG_TUD_VENDOR_RX_NEED_ZLP ? CFG_TUD_VENDOR_RX_EPSIZE : tu_edpt_packet_size(desc_ep); + #if CFG_TUD_VENDOR_RX_MANUAL_XFER == 0 + TU_ASSERT(usbd_edpt_xfer(rhport, p_vendor->ep_out, _vendord_epbuf[idx].epout, + p_vendor->rx_xfer_len, false)); + #endif + } + break; + + #if CFG_TUD_VENDOR_EP_INT_IN || CFG_TUD_VENDOR_EP_INT_OUT + case TUSB_XFER_INTERRUPT: + // stall/clear only for the enabled direction (an endpoint of a disabled + // direction was never opened, so must not be poked in the dcd) + #if CFG_TUD_VENDOR_EP_INT_IN + if (is_in) { + usbd_edpt_stall(rhport, ep_addr); + usbd_edpt_clear_stall(rhport, ep_addr); + p_vendor->ep_int_in = ep_addr; + } + #endif + #if CFG_TUD_VENDOR_EP_INT_OUT + if (!is_in) { + usbd_edpt_stall(rhport, ep_addr); + usbd_edpt_clear_stall(rhport, ep_addr); + p_vendor->ep_int_out = ep_addr; + p_vendor->int_rx_xfer_len = tu_edpt_packet_size(desc_ep); + } + #endif + break; + #endif + + #if CFG_TUD_VENDOR_EP_ISO_IN || CFG_TUD_VENDOR_EP_ISO_OUT + case TUSB_XFER_ISOCHRONOUS: + #if CFG_TUD_VENDOR_EP_ISO_IN + if (is_in) { + TU_ASSERT(vendord_iso_ep_activate(rhport, desc_ep)); + p_vendor->ep_iso_in = ep_addr; + p_vendor->iso_in_desc = desc_ep; // points into p_itf_desc (static app descriptor) + } + #endif + #if CFG_TUD_VENDOR_EP_ISO_OUT + if (!is_in) { + TU_ASSERT(vendord_iso_ep_activate(rhport, desc_ep)); + p_vendor->ep_iso_out = ep_addr; + p_vendor->iso_out_desc = desc_ep; // points into p_itf_desc (static app descriptor) + p_vendor->iso_rx_xfer_len = tu_edpt_packet_size(desc_ep); + } + #endif + break; + #endif + + default: + break; // unsupported endpoint type / direction gate disabled: ignore + } + } + p_desc = tu_desc_next(p_desc); + } + + TU_VERIFY(alt_found); // unknown alt: endpoints were never cleared, current altsetting intact + p_vendor->cur_alt = alt; + return true; +} + +uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t *desc_itf, uint16_t max_len) { + TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == desc_itf->bInterfaceClass, 0); + const uint8_t* desc_end = (const uint8_t*)desc_itf + max_len; + + const uint8_t idx = find_vendor_itf(0); + TU_ASSERT(idx < CFG_TUD_VENDOR, 0); + vendord_interface_t *p_vendor = &_vendord_itf[idx]; + p_vendor->rhport = rhport; + p_vendor->itf_num = desc_itf->bInterfaceNumber; + // p_itf_desc is assigned only after the parse succeeds: find_vendor_itf() treats a non-NULL + // p_itf_desc as an occupied slot, so setting it before a mid-parse TU_ASSERT could fail would + // leak the slot (a retry would find no free interface until the next bus reset). + + // Consume every altsetting of this interface and hardware-open each endpoint exactly once + // (bulk/interrupt via usbd_edpt_open, isochronous FIFO-allocated; iso activation and the + // toggle reset happen on altsetting selection). An endpoint address that recurs in another + // altsetting must carry an identical configuration, since it is opened only on first sight; + // reconfiguring the same address per-alt is not supported and is rejected here. + uint8_t seen_type[CFG_TUD_ENDPPOINT_MAX][2]; + uint16_t seen_mps[CFG_TUD_ENDPPOINT_MAX][2]; + tu_memclr(seen_type, sizeof(seen_type)); // 0 == TUSB_XFER_CONTROL, never used as a data ep here + const uint8_t* p_desc = tu_desc_next(desc_itf); + while (tu_desc_in_bounds(p_desc, desc_end)) { + const uint8_t desc_type = tu_desc_type(p_desc); + if (desc_type == TUSB_DESC_INTERFACE_ASSOCIATION) { + break; + } + if (desc_type == TUSB_DESC_INTERFACE) { + if (((const tusb_desc_interface_t*)p_desc)->bInterfaceNumber != p_vendor->itf_num) { + break; // next interface + } + } else if (desc_type == TUSB_DESC_ENDPOINT) { + const tusb_desc_endpoint_t* desc_ep = (const tusb_desc_endpoint_t*) p_desc; + const uint8_t epnum = tu_edpt_number(desc_ep->bEndpointAddress); + const uint8_t dir = tu_edpt_dir(desc_ep->bEndpointAddress); + const uint8_t xfer = desc_ep->bmAttributes.xfer; + const uint16_t mps = tu_edpt_packet_size(desc_ep); + TU_ASSERT(epnum < CFG_TUD_ENDPPOINT_MAX, 0); + + if (seen_type[epnum][dir] != 0) { + // reused address in a later altsetting: must be an exact match (opened only once) + TU_ASSERT(seen_type[epnum][dir] == xfer && seen_mps[epnum][dir] == mps, 0); + } else { + switch (xfer) { + case TUSB_XFER_BULK: + TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0); + break; + + #if CFG_TUD_VENDOR_EP_INT_IN || CFG_TUD_VENDOR_EP_INT_OUT + case TUSB_XFER_INTERRUPT: + #if CFG_TUD_VENDOR_EP_INT_IN + if (dir == TUSB_DIR_IN) { + TU_ASSERT(mps <= CFG_TUD_VENDOR_EP_INT_IN_BUFSIZE, 0); + TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0); + } + #endif + #if CFG_TUD_VENDOR_EP_INT_OUT + if (dir == TUSB_DIR_OUT) { + TU_ASSERT(mps <= CFG_TUD_VENDOR_EP_INT_OUT_BUFSIZE, 0); + TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0); + } + #endif + break; + #endif + + #if CFG_TUD_VENDOR_EP_ISO_IN || CFG_TUD_VENDOR_EP_ISO_OUT + case TUSB_XFER_ISOCHRONOUS: + #if CFG_TUD_VENDOR_EP_ISO_IN + if (dir == TUSB_DIR_IN) { + TU_ASSERT(mps <= CFG_TUD_VENDOR_EP_ISO_IN_BUFSIZE, 0); + TU_ASSERT(vendord_iso_ep_alloc(rhport, desc_ep), 0); + } + #endif + #if CFG_TUD_VENDOR_EP_ISO_OUT + if (dir == TUSB_DIR_OUT) { + TU_ASSERT(mps <= CFG_TUD_VENDOR_EP_ISO_OUT_BUFSIZE, 0); + TU_ASSERT(vendord_iso_ep_alloc(rhport, desc_ep), 0); + } + #endif + break; + #endif + + default: + break; // unsupported endpoint type / direction gate disabled: ignore + } + seen_type[epnum][dir] = xfer; + seen_mps[epnum][dir] = mps; + } + } + p_desc = tu_desc_next(p_desc); + } + // parse succeeded: commit the descriptor pointer (marks the slot occupied) before selecting alt 0 + p_vendor->p_itf_desc = (const uint8_t*) desc_itf; + p_vendor->itf_desc_len = (uint16_t)((uintptr_t)p_desc - (uintptr_t)desc_itf); + + // default altsetting active until the host selects another + TU_ASSERT(vendord_set_alt(rhport, idx, 0), 0); + return p_vendor->itf_desc_len; +} + +#else // !CFG_TUD_VENDOR_ALT_SETTINGS + uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t *desc_itf, uint16_t max_len) { TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == desc_itf->bInterfaceClass, 0); const uint8_t* desc_end = (const uint8_t*)desc_itf + max_len; @@ -294,6 +771,31 @@ uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t *desc_itf, uin break; // end of this interface } else if (desc_type == TUSB_DESC_ENDPOINT) { const tusb_desc_endpoint_t* desc_ep = (const tusb_desc_endpoint_t*) p_desc; + + #if CFG_TUD_VENDOR_EP_INT_OUT || CFG_TUD_VENDOR_EP_INT_IN + if (desc_ep->bmAttributes.xfer == TUSB_XFER_INTERRUPT) { + const bool is_int_in = tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN; + (void) is_int_in; + #if CFG_TUD_VENDOR_EP_INT_IN + if (is_int_in) { + TU_ASSERT(tu_edpt_packet_size(desc_ep) <= CFG_TUD_VENDOR_EP_INT_IN_BUFSIZE, 0); + TU_ASSERT(usbd_edpt_open(rhport, desc_ep)); + p_vendor->ep_int_in = desc_ep->bEndpointAddress; + } + #endif + #if CFG_TUD_VENDOR_EP_INT_OUT + if (!is_int_in) { + TU_ASSERT(tu_edpt_packet_size(desc_ep) <= CFG_TUD_VENDOR_EP_INT_OUT_BUFSIZE, 0); + TU_ASSERT(usbd_edpt_open(rhport, desc_ep)); + p_vendor->ep_int_out = desc_ep->bEndpointAddress; + p_vendor->int_rx_xfer_len = tu_edpt_packet_size(desc_ep); + } + #endif + p_desc = tu_desc_next(p_desc); + continue; + } + #endif + TU_ASSERT(usbd_edpt_open(rhport, desc_ep)); uint16_t rx_xfer_len = CFG_TUD_VENDOR_RX_NEED_ZLP ? CFG_TUD_VENDOR_RX_EPSIZE : tu_edpt_packet_size(desc_ep); @@ -332,6 +834,40 @@ uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t *desc_itf, uin return (uint16_t)((uintptr_t)p_desc - (uintptr_t)desc_itf); } +#endif // CFG_TUD_VENDOR_ALT_SETTINGS + +// Handle interface standard requests (GET/SET_INTERFACE when altsettings are enabled), +// delegate everything else to the application callback as before. +bool vendord_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { +#if CFG_TUD_VENDOR_ALT_SETTINGS + if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && + request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE) { + const uint8_t itf_num = tu_u16_low(request->wIndex); + uint8_t idx; + for (idx = 0; idx < CFG_TUD_VENDOR; idx++) { + if (_vendord_itf[idx].itf_num == itf_num && _vendord_itf[idx].p_itf_desc != NULL) { + break; + } + } + if (idx < CFG_TUD_VENDOR) { + if (request->bRequest == TUSB_REQ_SET_INTERFACE) { + if (stage == CONTROL_STAGE_SETUP) { + TU_VERIFY(vendord_set_alt(rhport, idx, tu_u16_low(request->wValue))); + return tud_control_status(rhport, request); + } + return true; + } else if (request->bRequest == TUSB_REQ_GET_INTERFACE) { + if (stage == CONTROL_STAGE_SETUP) { + return tud_control_xfer(rhport, request, &_vendord_itf[idx].cur_alt, 1); + } + return true; + } + } + } +#endif + return tud_vendor_control_xfer_cb(rhport, stage, request); +} + bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { (void)rhport; (void)result; @@ -339,6 +875,33 @@ bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint TU_VERIFY(idx < CFG_TUD_VENDOR); vendord_interface_t *p_vendor = &_vendord_itf[idx]; +#if CFG_TUD_VENDOR_EP_INT_OUT + if (ep_addr == p_vendor->ep_int_out) { + // not re-armed automatically: application calls tud_vendor_n_int_read_xfer() + tud_vendor_int_rx_cb(idx, _vendord_int_epbuf[idx].int_out, xferred_bytes); + return true; + } +#endif +#if CFG_TUD_VENDOR_EP_INT_IN + if (ep_addr == p_vendor->ep_int_in) { + tud_vendor_int_tx_cb(idx, xferred_bytes); + return true; + } +#endif +#if CFG_TUD_VENDOR_EP_ISO_OUT + if (ep_addr == p_vendor->ep_iso_out) { + // not re-armed automatically: application calls tud_vendor_n_iso_read_xfer() + tud_vendor_iso_rx_cb(idx, _vendord_iso_epbuf[idx].iso_out, xferred_bytes); + return true; + } +#endif +#if CFG_TUD_VENDOR_EP_ISO_IN + if (ep_addr == p_vendor->ep_iso_in) { + tud_vendor_iso_tx_cb(idx, xferred_bytes); + return true; + } +#endif + #if CFG_TUD_VENDOR_TXRX_BUFFERED if (ep_addr == p_vendor->rx_stream.ep_addr) { // Put received data to FIFO diff --git a/src/class/vendor/vendor_device.h b/src/class/vendor/vendor_device.h index cdca9fd15..ce33e2f62 100644 --- a/src/class/vendor/vendor_device.h +++ b/src/class/vendor/vendor_device.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -79,6 +60,68 @@ extern "C" { #define CFG_TUD_VENDOR_RX_NEED_ZLP 0 #endif +// Enable support for an optional interrupt OUT / interrupt IN endpoint in the vendor +// interface, each direction gated separately. Interrupt endpoints are non-buffered: +// OUT is armed manually one packet at a time with tud_vendor_n_int_read_xfer() (data +// delivered via tud_vendor_int_rx_cb), IN is a direct transfer via tud_vendor_n_int_write(). +#ifndef CFG_TUD_VENDOR_EP_INT_OUT + #define CFG_TUD_VENDOR_EP_INT_OUT 0 +#endif + +#ifndef CFG_TUD_VENDOR_EP_INT_IN + #define CFG_TUD_VENDOR_EP_INT_IN 0 +#endif + +// Buffer sizes for interrupt endpoint transfers, must be >= the endpoint max packet size +#ifndef CFG_TUD_VENDOR_EP_INT_OUT_BUFSIZE + #define CFG_TUD_VENDOR_EP_INT_OUT_BUFSIZE 64 +#endif + +#ifndef CFG_TUD_VENDOR_EP_INT_IN_BUFSIZE + #define CFG_TUD_VENDOR_EP_INT_IN_BUFSIZE 64 +#endif + +// Enable support for an optional isochronous OUT / IN endpoint, each direction gated +// separately, with the same non-buffered API shape as the interrupt pair. Isochronous +// endpoints must not claim bandwidth in the default altsetting (USB 2.0 5.6.3): place +// them in a non-zero altsetting and enable CFG_TUD_VENDOR_ALT_SETTINGS. +#ifndef CFG_TUD_VENDOR_EP_ISO_OUT + #define CFG_TUD_VENDOR_EP_ISO_OUT 0 +#endif + +#ifndef CFG_TUD_VENDOR_EP_ISO_IN + #define CFG_TUD_VENDOR_EP_ISO_IN 0 +#endif + +// Buffer sizes for isochronous endpoint transfers, must be >= the endpoint max packet size +#ifndef CFG_TUD_VENDOR_EP_ISO_OUT_BUFSIZE + #define CFG_TUD_VENDOR_EP_ISO_OUT_BUFSIZE 64 +#endif + +#ifndef CFG_TUD_VENDOR_EP_ISO_IN_BUFSIZE + #define CFG_TUD_VENDOR_EP_ISO_IN_BUFSIZE 64 +#endif + +// Enable alternate-setting support: the vendor interface may carry multiple altsettings, +// each with its own endpoint set. GET_INTERFACE is answered and SET_INTERFACE performed by +// closing the current altsetting's endpoints and opening the requested one's (isochronous +// endpoints are FIFO-allocated at open and activated on selection). The configuration +// descriptor must stay valid while mounted (static, the usual TinyUSB pattern). +// Non-buffered mode only. +#ifndef CFG_TUD_VENDOR_ALT_SETTINGS + #define CFG_TUD_VENDOR_ALT_SETTINGS 0 +#endif + +#if CFG_TUD_VENDOR_ALT_SETTINGS && CFG_TUD_VENDOR_TXRX_BUFFERED + #error CFG_TUD_VENDOR_ALT_SETTINGS requires non-buffered mode (CFG_TUD_VENDOR_RX/TX_BUFSIZE = 0) +#endif + +// An isochronous endpoint must not claim bandwidth in the default altsetting (USB 2.0 5.6.3), +// so it can only live in a non-zero altsetting, which requires alternate-setting support. +#if (CFG_TUD_VENDOR_EP_ISO_OUT || CFG_TUD_VENDOR_EP_ISO_IN) && !CFG_TUD_VENDOR_ALT_SETTINGS + #error CFG_TUD_VENDOR_EP_ISO_OUT/IN requires CFG_TUD_VENDOR_ALT_SETTINGS +#endif + //--------------------------------------------------------------------+ // Application API (Multiple Interfaces) i.e CFG_TUD_VENDOR > 1 //--------------------------------------------------------------------+ @@ -126,6 +169,43 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_n_write_str(uint8_t idx, return tud_vendor_n_write(idx, str, strlen(str)); } +//------------- Interrupt endpoints -------------// +#if CFG_TUD_VENDOR_EP_INT_OUT +// Arm the interrupt OUT endpoint for one packet, return false if a transfer is still ongoing. +// Received data is delivered via tud_vendor_int_rx_cb(); re-arm from the callback or by polling. +bool tud_vendor_n_int_read_xfer(uint8_t idx); +#endif + +#if CFG_TUD_VENDOR_EP_INT_IN +// Send on the interrupt IN endpoint (direct transfer, up to CFG_TUD_VENDOR_EP_INT_IN_BUFSIZE +// bytes). Returns number of bytes queued, 0 if the endpoint is busy or not opened. +uint32_t tud_vendor_n_int_write(uint8_t idx, const void *buffer, uint32_t bufsize); + +// Return available bytes for interrupt IN write: 0 while busy, else the buffer size +uint32_t tud_vendor_n_int_write_available(uint8_t idx); +#endif + +//------------- Isochronous endpoints -------------// +#if CFG_TUD_VENDOR_EP_ISO_OUT +// Arm the isochronous OUT endpoint for one packet, return false if a transfer is still ongoing. +// Received data is delivered via tud_vendor_iso_rx_cb(); re-arm from the callback or by polling. +bool tud_vendor_n_iso_read_xfer(uint8_t idx); +#endif + +#if CFG_TUD_VENDOR_EP_ISO_IN +// Send on the isochronous IN endpoint (direct transfer, up to CFG_TUD_VENDOR_EP_ISO_IN_BUFSIZE +// bytes). Returns number of bytes queued, 0 if the endpoint is busy or not opened. +uint32_t tud_vendor_n_iso_write(uint8_t idx, const void *buffer, uint32_t bufsize); + +// Return available bytes for isochronous IN write: 0 while busy, else the buffer size +uint32_t tud_vendor_n_iso_write_available(uint8_t idx); +#endif + +#if CFG_TUD_VENDOR_ALT_SETTINGS +// Return the currently selected alternate setting +uint8_t tud_vendor_n_alt(uint8_t idx); +#endif + // backward compatible #define tud_vendor_n_flush(idx) tud_vendor_n_write_flush(idx) @@ -180,6 +260,44 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write_available(void) { return tud_vendor_n_write_available(0); } +#if CFG_TUD_VENDOR_EP_INT_OUT +TU_ATTR_ALWAYS_INLINE static inline bool tud_vendor_int_read_xfer(void) { + return tud_vendor_n_int_read_xfer(0); +} +#endif + +#if CFG_TUD_VENDOR_EP_INT_IN +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_int_write(const void *buffer, uint32_t bufsize) { + return tud_vendor_n_int_write(0, buffer, bufsize); +} + +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_int_write_available(void) { + return tud_vendor_n_int_write_available(0); +} +#endif + +#if CFG_TUD_VENDOR_EP_ISO_OUT +TU_ATTR_ALWAYS_INLINE static inline bool tud_vendor_iso_read_xfer(void) { + return tud_vendor_n_iso_read_xfer(0); +} +#endif + +#if CFG_TUD_VENDOR_EP_ISO_IN +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_iso_write(const void *buffer, uint32_t bufsize) { + return tud_vendor_n_iso_write(0, buffer, bufsize); +} + +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_iso_write_available(void) { + return tud_vendor_n_iso_write_available(0); +} +#endif + +#if CFG_TUD_VENDOR_ALT_SETTINGS +TU_ATTR_ALWAYS_INLINE static inline uint8_t tud_vendor_alt(void) { + return tud_vendor_n_alt(0); +} +#endif + // backward compatible #define tud_vendor_flush() tud_vendor_write_flush() @@ -195,6 +313,29 @@ void tud_vendor_rx_cb(uint8_t idx, const uint8_t *buffer, uint32_t bufsize); // Invoked when tx transfer is finished void tud_vendor_tx_cb(uint8_t idx, uint32_t sent_bytes); +#if CFG_TUD_VENDOR_EP_INT_OUT +// Invoked when data is received on the interrupt OUT endpoint. The endpoint is not +// re-armed automatically: call tud_vendor_n_int_read_xfer() to receive more. +void tud_vendor_int_rx_cb(uint8_t idx, const uint8_t *buffer, uint32_t bufsize); +#endif + +#if CFG_TUD_VENDOR_EP_INT_IN +// Invoked when an interrupt IN transfer is finished +void tud_vendor_int_tx_cb(uint8_t idx, uint32_t sent_bytes); +#endif + +#if CFG_TUD_VENDOR_EP_ISO_OUT +// Invoked when data is received on the isochronous OUT endpoint. The endpoint is not +// re-armed automatically: call tud_vendor_n_iso_read_xfer() to receive more. +void tud_vendor_iso_rx_cb(uint8_t idx, const uint8_t *buffer, uint32_t bufsize); +#endif + +#if CFG_TUD_VENDOR_EP_ISO_IN +// Invoked when an isochronous IN transfer is finished (result may be a missed frame: +// the data was not necessarily taken by the host, re-arm regardless) +void tud_vendor_iso_tx_cb(uint8_t idx, uint32_t sent_bytes); +#endif + //--------------------------------------------------------------------+ // Internal Class Driver API //--------------------------------------------------------------------+ @@ -202,6 +343,7 @@ void vendord_init(void); bool vendord_deinit(void); void vendord_reset(uint8_t rhport); uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t *idx_desc, uint16_t max_len); +bool vendord_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request); bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); #ifdef __cplusplus diff --git a/src/class/vendor/vendor_host.c b/src/class/vendor/vendor_host.c deleted file mode 100644 index e66c5007f..000000000 --- a/src/class/vendor/vendor_host.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if (CFG_TUH_ENABLED && CFG_TUH_VENDOR) - -//--------------------------------------------------------------------+ -// INCLUDE -//--------------------------------------------------------------------+ -#include "host/usbh.h" -#include "vendor_host.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ -custom_interface_info_t custom_interface[CFG_TUH_DEVICE_MAX]; - -static tusb_error_t cush_validate_paras(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, uint16_t length) -{ - if ( !tusbh_custom_is_mounted(dev_addr, vendor_id, product_id) ) - { - return TUSB_ERROR_DEVICE_NOT_READY; - } - - TU_ASSERT( p_buffer != NULL && length != 0, TUSB_ERROR_INVALID_PARA); - - return TUSB_ERROR_NONE; -} -//--------------------------------------------------------------------+ -// APPLICATION API (need to check parameters) -//--------------------------------------------------------------------+ -tusb_error_t tusbh_custom_read(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, uint16_t length) -{ - TU_ASSERT_ERR( cush_validate_paras(dev_addr, vendor_id, product_id, p_buffer, length) ); - - if ( !hcd_pipe_is_idle(custom_interface[dev_addr-1].pipe_in) ) - { - return TUSB_ERROR_INTERFACE_IS_BUSY; - } - - (void) usbh_edpt_xfer( custom_interface[dev_addr-1].pipe_in, p_buffer, length); - - return TUSB_ERROR_NONE; -} - -tusb_error_t tusbh_custom_write(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void const * p_data, uint16_t length) -{ - TU_ASSERT_ERR( cush_validate_paras(dev_addr, vendor_id, product_id, p_data, length) ); - - if ( !hcd_pipe_is_idle(custom_interface[dev_addr-1].pipe_out) ) - { - return TUSB_ERROR_INTERFACE_IS_BUSY; - } - - (void) usbh_edpt_xfer( custom_interface[dev_addr-1].pipe_out, p_data, length); - - return TUSB_ERROR_NONE; -} - -//--------------------------------------------------------------------+ -// USBH-CLASS API -//--------------------------------------------------------------------+ -void cush_init(void) -{ - tu_memclr(&custom_interface, sizeof(custom_interface_info_t) * CFG_TUH_DEVICE_MAX); -} - -tusb_error_t cush_open_subtask(uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length) -{ - // FIXME quick hack to test lpc1k custom class with 2 bulk endpoints - uint8_t const *p_desc = (uint8_t const *) p_interface_desc; - p_desc = tu_desc_next(p_desc); - - //------------- Bulk Endpoints Descriptor -------------// - for(uint32_t i=0; i<2; i++) - { - tusb_desc_endpoint_t const *p_endpoint = (tusb_desc_endpoint_t const *) p_desc; - TU_ASSERT(TUSB_DESC_ENDPOINT == p_endpoint->bDescriptorType, TUSB_ERROR_INVALID_PARA); - - pipe_handle_t * p_pipe_hdl = ( p_endpoint->bEndpointAddress & TUSB_DIR_IN_MASK ) ? - &custom_interface[dev_addr-1].pipe_in : &custom_interface[dev_addr-1].pipe_out; - *p_pipe_hdl = usbh_edpt_open(dev_addr, p_endpoint, TUSB_CLASS_VENDOR_SPECIFIC); - TU_ASSERT ( pipehandle_is_valid(*p_pipe_hdl), TUSB_ERROR_HCD_OPEN_PIPE_FAILED ); - - p_desc = tu_desc_next(p_desc); - } - - (*p_length) = sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t); - return TUSB_ERROR_NONE; -} - -void cush_isr(pipe_handle_t pipe_hdl, xfer_result_t event) -{ - -} - -void cush_close(uint8_t dev_addr) -{ - tusb_error_t err1, err2; - custom_interface_info_t * p_interface = &custom_interface[dev_addr-1]; - - // TODO re-consider to check pipe valid before calling pipe_close - if( pipehandle_is_valid( p_interface->pipe_in ) ) - { - err1 = hcd_pipe_close( p_interface->pipe_in ); - } - - if ( pipehandle_is_valid( p_interface->pipe_out ) ) - { - err2 = hcd_pipe_close( p_interface->pipe_out ); - } - - tu_memclr(p_interface, sizeof(custom_interface_info_t)); - - TU_ASSERT(err1 == TUSB_ERROR_NONE && err2 == TUSB_ERROR_NONE, (void) 0 ); -} - -#endif diff --git a/src/class/vendor/vendor_host.h b/src/class/vendor/vendor_host.h deleted file mode 100644 index 00e3c3402..000000000 --- a/src/class/vendor/vendor_host.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef TUSB_VENDOR_HOST_H_ -#define TUSB_VENDOR_HOST_H_ - -#include "common/tusb_common.h" - -#ifdef __cplusplus - extern "C" { -#endif - -typedef struct { - pipe_handle_t pipe_in; - pipe_handle_t pipe_out; -}custom_interface_info_t; - -//--------------------------------------------------------------------+ -// USBH-CLASS DRIVER API -//--------------------------------------------------------------------+ -static inline bool tusbh_custom_is_mounted(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id) -{ - (void) vendor_id; // TODO check this later - (void) product_id; -// return (tusbh_device_get_mounted_class_flag(dev_addr) & TU_BIT(TUSB_CLASS_MAPPED_INDEX_END-1) ) != 0; - return false; -} - -bool tusbh_custom_read(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, uint16_t length); -bool tusbh_custom_write(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void const * p_data, uint16_t length); - -//--------------------------------------------------------------------+ -// Internal Class Driver API -//--------------------------------------------------------------------+ -void cush_init(void); -bool cush_open_subtask(uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length); -void cush_isr(pipe_handle_t pipe_hdl, xfer_result_t event); -void cush_close(uint8_t dev_addr); - -#ifdef __cplusplus - } -#endif - -#endif /* TUSB_VENDOR_HOST_H_ */ diff --git a/src/class/video/video.h b/src/class/video/video.h index 5bdf4b840..c62aa2791 100644 --- a/src/class/video/video.h +++ b/src/class/video/video.h @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021 Koji KITAYAMA - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021 Koji Kitayama + * SPDX-FileCopyrightText: Copyright (c) 2021 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c index e31ab4194..770595178 100644 --- a/src/class/video/video_device.c +++ b/src/class/video/video_device.c @@ -1,26 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021 Koji KITAYAMA - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021 Koji Kitayama + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -1163,6 +1144,9 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, video_probe_and_commit_control_t *param = &stm->probe_commit_payload; TU_VERIFY(_update_streaming_parameters(stm, param), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); /* Set the negotiated value */ + if (CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE < param->dwMaxPayloadTransferSize) { + param->dwMaxPayloadTransferSize = CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE; + } stm->max_payload_transfer_size = param->dwMaxPayloadTransferSize; int ret = tud_video_commit_cb(stm->index_vc, stm->index_vs, param); if (VIDEO_ERROR_NONE == ret) { diff --git a/src/class/video/video_device.h b/src/class/video/video_device.h index 2750bb2fb..f14473dc3 100644 --- a/src/class/video/video_device.h +++ b/src/class/video/video_device.h @@ -1,26 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * Copyright (c) 2021 Koji KITAYAMA - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-FileCopyrightText: Copyright (c) 2021 Koji Kitayama + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h index 6ac1405f3..b6f515e26 100644 --- a/src/common/tusb_common.h +++ b/src/common/tusb_common.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/common/tusb_compiler.h b/src/common/tusb_compiler.h index a8971c3df..2015475d9 100644 --- a/src/common/tusb_compiler.h +++ b/src/common/tusb_compiler.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/common/tusb_debug.h b/src/common/tusb_debug.h index ba5b4afd1..1f88dac6c 100644 --- a/src/common/tusb_debug.h +++ b/src/common/tusb_debug.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2022, Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2022, Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index a8ac99fd2..e5855fcbc 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -1,26 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * Copyright (c) 2020 Reinhard Panhuber - rework to unmasked pointers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-FileCopyrightText: Copyright (c) 2020 Reinhard Panhuber + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index b31a0802e..c5a0aaaef 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -1,26 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * Copyright (c) 2020 Reinhard Panhuber - rework to unmasked pointers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-FileCopyrightText: Copyright (c) 2020 Reinhard Panhuber + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index 35de47030..af43dfb12 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021, Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021, Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -145,6 +126,14 @@ #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32 #endif + // Errata ERR050101, listed for RT1015/RT1020/RT1024/RT1050 (no fix scheduled) and for + // RT1060/RT1064 rev A (fixed in rev B); not listed for RT1010 or the RT11xx family. + #if defined(MIMXRT1015_SERIES) || defined(MIMXRT1021_SERIES) || defined(MIMXRT1024_SERIES) || \ + defined(MIMXRT1051_SERIES) || defined(MIMXRT1052_SERIES) || defined(MIMXRT1061_SERIES) || \ + defined(MIMXRT1062_SERIES) || defined(MIMXRT1064_SERIES) + #define CFG_TUSB_MIMXRT1XXX_ERRATA_ERR050101 1 + #endif + #elif TU_CHECK_MCU(OPT_MCU_KINETIS_KL, OPT_MCU_KINETIS_K32L, OPT_MCU_KINETIS_K) #define TUP_USBIP_CHIPIDEA_FS #define TUP_USBIP_CHIPIDEA_FS_KINETIS @@ -160,7 +149,6 @@ #elif TU_CHECK_MCU(OPT_MCU_NRF5X) // 8 CBI + 1 ISO #define TUP_DCD_ENDPOINT_MAX 9 - #define TUP_DCD_EDPT_CLOSE_API #elif TU_CHECK_MCU(OPT_MCU_NRF54) #define TUP_USBIP_DWC2 @@ -692,7 +680,9 @@ #elif TU_CHECK_MCU(OPT_MCU_AT32F403A_407, OPT_MCU_AT32F413) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_AT32 - #define CFG_TUSB_FSDEV_PMA_SIZE 512u + #define CFG_TUSB_FSDEV_PMA_SIZE 768u + #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 2 + #define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 4 #elif TU_CHECK_MCU(OPT_MCU_AT32F415) #define TUP_USBIP_DWC2 @@ -723,6 +713,25 @@ #define TU_ATTR_FAST_FUNC __attribute__((section(".fast"))) +//--------------------------------------------------------------------+ +// Puya +//--------------------------------------------------------------------+ +#elif TU_CHECK_MCU(OPT_MCU_PY32F0) + #define TUP_USBIP_MUSB + #define TUP_USBIP_MUSB_PY32 + #define TUP_DCD_ENDPOINT_MAX 6 + // PY32 shares the buffer between IN and OUT of the same endpoint number. + // Possible to share IN/OUT if only one direction is armed at any one time + #define CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY 1 + +//--------------------------------------------------------------------+ +// Geehy +//--------------------------------------------------------------------+ +#elif TU_CHECK_MCU(OPT_MCU_APM32F0XX) + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_APM32 + #define CFG_TUSB_FSDEV_PMA_SIZE 1024u + #endif // External USB controller @@ -760,15 +769,24 @@ #define TU_ATTR_FAST_FUNC #endif -#if defined(TUP_USBIP_IP3511) || defined(TUP_USBIP_RUSB2) - #define TUP_DCD_EDPT_CLOSE_API -#endif - -// USBIP implement dcd_edpt_close() and does not support ISO alloc & activate API +// TUP_DCD_EDPT_CLOSE_API is deprecated: these USBIPs implement dcd_edpt_close() and lack the +// ISO alloc & activate API. IP3511, RUSB2 and NRF5X have been migrated to ISO_ALLOC; the remaining +// CLOSE_API MCUs (mm32, pic, da1469x, f1c100s, ch32-usbhs) are pending per-board verification. #ifndef TUP_DCD_EDPT_CLOSE_API #define TUP_DCD_EDPT_ISO_ALLOC #endif +// Set by silicon whose isochronous IN endpoint can be unprimed by an IN token sent to that same +// endpoint number on ANOTHER device sharing the host, taking one of this device's OUT endpoints +// down with it - undetectable in software. Descriptors must then give an isochronous IN endpoint +// a number no other device on the bus uses; a number is only safe while it stays unique, so two +// affected boards on one hub must not pick the same one. Default 0 (no such conflict). Set it to +// 0 by hand on RT1060/RT1064 rev B, which carry the fix - the revision cannot be told apart at +// compile time, so the affected parts are assumed to be rev A. +#ifndef CFG_TUSB_MIMXRT1XXX_ERRATA_ERR050101 + #define CFG_TUSB_MIMXRT1XXX_ERRATA_ERR050101 0 +#endif + // Some USBIPs (SAMG, SAMX7X, PIC32, MAX3266x/MAX78002) cannot assign the same endpoint // number to both IN and OUT. Default to 0 (same endpoint number may be used for IN and OUT). #ifndef CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY diff --git a/src/common/tusb_private.h b/src/common/tusb_private.h index a31bf7b03..b91fc0608 100644 --- a/src/common/tusb_private.h +++ b/src/common/tusb_private.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2022, Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2022, Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -82,7 +63,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool tu_edpt_validate(const tusb_desc_endpoi // Bind drivers to all interfaces and endpoints in the provided configuration descriptor bool tu_bind_driver_to_ep_itf(uint8_t driver_id, uint8_t ep2drv[][2], uint8_t itf2drv[], uint8_t itf_max, - const uint8_t *p_desc, uint16_t desc_len); + uint8_t ep_max, const uint8_t *p_desc, uint16_t desc_len); // Claim an endpoint with provided mutex bool tu_edpt_claim(volatile uint8_t* ep_state, osal_mutex_t mutex); diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h index cb06b89bb..fa4d67df1 100644 --- a/src/common/tusb_types.h +++ b/src/common/tusb_types.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -263,7 +244,7 @@ enum { TUSB_DESC_CONFIG_ATT_SELF_POWERED = 1 << 6, }; -#define TUSB_DESC_CONFIG_POWER_MA(x) ((x)/2) +#define TUSB_DESC_CONFIG_POWER_MA(x) ((uint8_t)TU_MIN((x)/2, UINT8_MAX)) // USB 2.0 Spec Table 9-7: Test Mode Selectors typedef enum { diff --git a/src/common/tusb_verify.h b/src/common/tusb_verify.h index c0e4d0883..a37de0c4d 100644 --- a/src/common/tusb_verify.h +++ b/src/common/tusb_verify.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/device/dcd.h b/src/device/dcd.h index f861eb258..a4006ae0c 100644 --- a/src/device/dcd.h +++ b/src/device/dcd.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -39,19 +20,27 @@ // MACRO CONSTANT TYPEDEF PROTYPES //--------------------------------------------------------------------+ +// Bus reset is reported as two edges. BUS_RESET_START is optional: a controller that +// cannot tell the edges apart emits only BUS_RESET_END, which stays self-sufficient (it +// performs the full teardown with or without a preceding START). Emit START when reset +// signaling is detected - the link is unusable and the speed is not negotiated yet - so +// the stack stops using endpoints immediately instead of at the end of the reset. typedef enum { - DCD_EVENT_INVALID = 0, // 0 - DCD_EVENT_BUS_RESET, // 1 - DCD_EVENT_UNPLUGGED, // 2 - DCD_EVENT_SOF, // 3 - DCD_EVENT_SUSPEND, // 4 TODO LPM Sleep L1 support - DCD_EVENT_RESUME, // 5 - DCD_EVENT_SETUP_RECEIVED, // 6 - DCD_EVENT_XFER_COMPLETE, // 7 - USBD_EVENT_FUNC_CALL, // 8 Not an DCD event, just a convenient way to defer ISR function + DCD_EVENT_INVALID = 0, // 0 + DCD_EVENT_BUS_RESET_START, // 1 + DCD_EVENT_BUS_RESET_END, // 2 with negotiated speed + DCD_EVENT_UNPLUGGED, // 3 + DCD_EVENT_SOF, // 4 + DCD_EVENT_SUSPEND, // 5 TODO LPM Sleep L1 support + DCD_EVENT_RESUME, // 6 + DCD_EVENT_SETUP_RECEIVED, // 7 + DCD_EVENT_XFER_COMPLETE, // 8 + USBD_EVENT_FUNC_CALL, // 9 Not an DCD event, just a convenient way to defer ISR function DCD_EVENT_COUNT } dcd_eventid_t; +#define DCD_EVENT_BUS_RESET DCD_EVENT_BUS_RESET_END // backward compatibility + typedef struct TU_ATTR_ALIGNED(4) { uint8_t rhport; uint8_t event_id; diff --git a/src/device/usbd.c b/src/device/usbd.c index c4c418cb5..21d865cf7 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -275,7 +256,7 @@ static const usbd_class_driver_t _usbd_driver[] = { .deinit = vendord_deinit, .reset = vendord_reset, .open = vendord_open, - .control_xfer_cb = tud_vendor_control_xfer_cb, + .control_xfer_cb = vendord_control_xfer_cb, .xfer_cb = vendord_xfer_cb, .xfer_isr = NULL, .sof = NULL @@ -380,13 +361,12 @@ static const usbd_class_driver_t _usbd_driver[] = { #endif }; -enum { BUILTIN_DRIVER_COUNT = TU_ARRAY_SIZE(_usbd_driver) }; - // Additional class drivers implemented by application -static const usbd_class_driver_t *_app_driver = NULL; -static uint8_t _app_driver_count = 0; +static const usbd_class_driver_t *_app_driver = NULL; +static const uint8_t _builtin_driver_count = TU_ARRAY_SIZE(_usbd_driver); +static uint8_t _app_driver_count = 0; -#define TOTAL_DRIVER_COUNT ((uint8_t) (_app_driver_count + BUILTIN_DRIVER_COUNT)) +#define TOTAL_DRIVER_COUNT ((uint8_t) (_app_driver_count + _builtin_driver_count)) // virtually joins built-in and application drivers together. // Application is positioned first to allow overwriting built-in ones. @@ -397,7 +377,7 @@ TU_ATTR_ALWAYS_INLINE static inline usbd_class_driver_t const * get_driver(uint8 driver = &_app_driver[drvid]; } else{ drvid -= _app_driver_count; - if (drvid < BUILTIN_DRIVER_COUNT) { + if (_builtin_driver_count > 0 && drvid < _builtin_driver_count) { driver = &_usbd_driver[drvid]; } } @@ -438,6 +418,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool queue_event(dcd_event_t const * event, //--------------------------------------------------------------------+ static bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); static bool process_setup_received(uint8_t rhport, tusb_control_request_t const * p_request); +static bool process_get_status(uint8_t rhport, tusb_control_request_t const * request, uint16_t status); static bool process_set_config(uint8_t rhport, uint8_t cfg_num); static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request); @@ -475,7 +456,8 @@ TU_ATTR_WEAK bool dcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg #if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL static char const *const _usbd_event_str[DCD_EVENT_COUNT] = { "Invalid", - "Bus Reset", + "Bus Reset Start", + "Bus Reset End", "Unplugged", "SOF", "Suspend", @@ -582,7 +564,7 @@ bool tud_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { // Get application driver if available _app_driver = usbd_app_driver_get_cb(&_app_driver_count); - TU_ASSERT(_app_driver_count + BUILTIN_DRIVER_COUNT <= UINT8_MAX); + TU_ASSERT(_app_driver_count + _builtin_driver_count <= UINT8_MAX); // Init class drivers for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) { @@ -661,6 +643,8 @@ static void configuration_reset(uint8_t rhport) { static void usbd_reset(uint8_t rhport) { configuration_reset(rhport); + // discard any pre-reset SETUP still counted: a stale count skips post-reset SETUPs + _usbd_queued_setup = 0; } bool tud_task_event_ready(void) { @@ -714,8 +698,15 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) { #endif switch (event.event_id) { - case DCD_EVENT_BUS_RESET: + case DCD_EVENT_BUS_RESET_START: + TU_LOG_USBD("\r\n"); + usbd_reset(event.rhport); + break; + + case DCD_EVENT_BUS_RESET_END: TU_LOG_USBD(": %s Speed\r\n", tu_str_speed[event.bus_reset.speed]); + // TODO a DCD that reports both edges pays for two teardowns: track a per-rhport + // "start seen" flag and skip this reset, keeping it for the single-event DCDs. usbd_reset(event.rhport); _usbd_dev.speed = event.bus_reset.speed; break; @@ -766,7 +757,14 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) { _usbd_dev.ep_status[epnum][ep_dir] &= (uint8_t) ~(TU_EDPT_STATE_BUSY | TU_EDPT_STATE_CLAIMED); if (0 == epnum) { - usbd_control_xfer_cb(event.rhport, ep_addr, (xfer_result_t) event.xfer_complete.result, event.xfer_complete.len); + // Not stalled on failure: a DCD refuses an EP0 prime when a newer setup is already + // latched, and EP0 stalls are cleared by hardware when that setup arrives - so a stall + // issued here lands after the auto-clear and would stall the transfer that superseded + // this one. The pending setup re-drives EP0 by itself. + if (!usbd_control_xfer_cb(event.rhport, ep_addr, (xfer_result_t) event.xfer_complete.result, + event.xfer_complete.len)) { + TU_LOG_USBD(" Control stage not continued\r\n"); + } } else { usbd_class_driver_t const* driver = get_driver(_usbd_dev.ep2drv[epnum][ep_dir]); TU_ASSERT(driver,); @@ -884,10 +882,10 @@ bool tud_control_xfer(uint8_t rhport, const tusb_control_request_t* request, voi if (ctrl_xfer->data_len > 0U) { TU_ASSERT(buffer); } - TU_ASSERT(data_stage_xact(rhport)); + TU_VERIFY(data_stage_xact(rhport)); } else { // wLength == 0: Status stage is always IN per USB 2.0 §9.3.1 - TU_ASSERT(status_stage_xact(rhport, TU_EP0_IN)); + TU_VERIFY(status_stage_xact(rhport, TU_EP0_IN)); } return true; @@ -938,7 +936,7 @@ static bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t } if (is_ok) { - TU_ASSERT(status_stage_xact(rhport, ep_status)); + TU_VERIFY(status_stage_xact(rhport, ep_status)); } else { // Stall both IN and OUT control endpoint dcd_edpt_stall(rhport, TU_EP0_OUT); @@ -946,7 +944,7 @@ static bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t } } else { // More data to transfer - TU_ASSERT(data_stage_xact(rhport)); + TU_VERIFY(data_stage_xact(rhport)); } return true; @@ -1061,9 +1059,7 @@ static bool process_std_device_request(uint8_t rhport, tusb_control_request_t co // Device status bit mask // - Bit 0: Self Powered TODO must invoke callback to get actual status // - Bit 1: Remote Wakeup enabled - uint16_t status = (uint16_t) _usbd_dev.dev_state_bm; - tud_control_xfer(rhport, p_request, &status, 2); - return true; + return process_get_status(rhport, p_request, (uint16_t) _usbd_dev.dev_state_bm); } default: @@ -1073,6 +1069,14 @@ static bool process_std_device_request(uint8_t rhport, tusb_control_request_t co } +// Reply to a standard GET_STATUS (device/interface/endpoint) with its 2-byte status word. +// GET_STATUS is Device-to-host only; reject a mis-directed (OUT) request rather than handing +// usbd the address of a stack local to write host data into after this frame has returned. +static bool process_get_status(uint8_t rhport, tusb_control_request_t const * request, uint16_t status) { + TU_VERIFY(request->bmRequestType_bit.direction == TUSB_DIR_IN); + return tud_control_xfer(rhport, request, &status, 2); +} + // This handles the actual request and its response. // Returns false if unable to complete the request, causing caller to stall control endpoints. static bool process_setup_received(uint8_t rhport, tusb_control_request_t const * p_request) { @@ -1170,9 +1174,18 @@ static bool process_setup_received(uint8_t rhport, tusb_control_request_t const } case TUSB_REQ_SET_INTERFACE: + // A class that implements altsettings handles SET_INTERFACE itself and returns true, + // so reaching here means the class does not — where only alt 0 is valid. Any non-zero + // alt (unimplemented, or rejected as invalid by the class) is a Request Error (stall). + TU_VERIFY(tu_u16_low(p_request->wValue) == 0); tud_control_status(rhport, p_request); break; + case TUSB_REQ_GET_STATUS: + // USB 2.0 9.4.5: interface GET_STATUS returns 2 reserved (zero) bytes + TU_VERIFY(process_get_status(rhport, p_request, 0x0000)); + break; + default: return false; } } @@ -1195,35 +1208,34 @@ static bool process_setup_received(uint8_t rhport, tusb_control_request_t const } else { // Handle STD request to endpoint switch (p_request->bRequest) { //-V2520 - case TUSB_REQ_GET_STATUS: { - uint16_t status = usbd_edpt_stalled(rhport, ep_addr) ? 0x0001u : 0x0000u; - tud_control_xfer(rhport, p_request, &status, 2); - } - break; + case TUSB_REQ_GET_STATUS: + // USB 2.0 9.4.5: endpoint GET_STATUS bit 0 = Halt + TU_VERIFY(process_get_status(rhport, p_request, usbd_edpt_stalled(rhport, ep_addr) ? 0x0001u : 0x0000u)); + break; case TUSB_REQ_CLEAR_FEATURE: case TUSB_REQ_SET_FEATURE: { - if ( TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue ) { - if ( TUSB_REQ_CLEAR_FEATURE == p_request->bRequest ) { - usbd_edpt_clear_stall(rhport, ep_addr); - }else { - usbd_edpt_stall(rhport, ep_addr); - } - } + // ENDPOINT_HALT is the only endpoint feature; it exists only on a non-control endpoint + // that an interface actually owns. Any other selector, the control endpoint (EP0 has no + // Halt feature, USB 2.0 9.4.9), or an endpoint no driver owns is a Request Error (stall). + TU_VERIFY(TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue); + TU_VERIFY(ep_num != 0); + TU_VERIFY(driver != NULL); - if (driver != NULL) { - // Some classes such as USBTMC needs to clear/re-init its buffer when receiving CLEAR_FEATURE request - // We will also forward std request targeted endpoint to class drivers as well + if ( TUSB_REQ_CLEAR_FEATURE == p_request->bRequest ) { + usbd_edpt_clear_stall(rhport, ep_addr); + } else { + usbd_edpt_stall(rhport, ep_addr); + } - // STD request must always be ACKed regardless of driver returned value - // Also clear complete callback if driver set since it can also stall the request. - (void) invoke_class_control(rhport, driver, p_request); - ctrl_xfer->complete_cb = NULL; + // Some classes such as USBTMC need to clear/re-init their buffer on CLEAR_FEATURE. + // Clear complete callback if driver set since it can also stall the request. + (void) invoke_class_control(rhport, driver, p_request); + ctrl_xfer->complete_cb = NULL; - // skip ZLP status if driver already did that - if (!(_usbd_dev.ep_status[0][TUSB_DIR_IN] & TU_EDPT_STATE_BUSY)) { - tud_control_status(rhport, p_request); - } + // STD request must always be ACKed; skip ZLP status if driver already did that. + if (!(_usbd_dev.ep_status[0][TUSB_DIR_IN] & TU_EDPT_STATE_BUSY)) { + tud_control_status(rhport, p_request); } } break; @@ -1284,8 +1296,8 @@ static bool process_set_config(uint8_t rhport, uint8_t cfg_num) { TU_LOG_USBD(" %s opened\r\n", driver->name); // bind found driver to all interfaces and endpoint within drv_len - TU_ASSERT(tu_bind_driver_to_ep_itf(drv_id, _usbd_dev.ep2drv, _usbd_dev.itf2drv, CFG_TUD_INTERFACE_MAX, p_desc, - drv_len)); + TU_ASSERT(tu_bind_driver_to_ep_itf(drv_id, _usbd_dev.ep2drv, _usbd_dev.itf2drv, CFG_TUD_INTERFACE_MAX, + CFG_TUD_ENDPPOINT_MAX, p_desc, drv_len)); p_desc += drv_len; // next Interface break; // exit driver find loop @@ -1478,8 +1490,18 @@ TU_ATTR_FAST_FUNC void dcd_event_handler(dcd_event_t const* event, bool in_isr) break; } - if (send) { - queue_event(event, in_isr); + if (send && !queue_event(event, in_isr)) { + // event dropped by a full queue: undo state that would otherwise wedge permanently + if (event->event_id == DCD_EVENT_SETUP_RECEIVED) { + // undo the increment, else every later SETUP is skipped as "other SETUP in queue" + // and EP0 is deaf until re-init + _usbd_queued_setup--; + } else if (event->event_id == DCD_EVENT_XFER_COMPLETE) { + // clear busy + claimed, else the endpoint can never be claimed or re-armed again + uint8_t const epnum = tu_edpt_number(event->xfer_complete.ep_addr); + uint8_t const ep_dir = tu_edpt_dir(event->xfer_complete.ep_addr); + _usbd_dev.ep_status[epnum][ep_dir] &= (uint8_t) ~(TU_EDPT_STATE_BUSY | TU_EDPT_STATE_CLAIMED); + } } } @@ -1593,10 +1615,12 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t t if (dcd_edpt_xfer(rhport, ep_addr, buffer, total_bytes, is_isr)) { return true; } else { - // DCD error, mark endpoint as ready to allow next transfer + // Driver refused the transfer, mark endpoint as ready to allow next transfer. This is a + // recoverable condition (e.g. a new setup superseding a control response), not a bug, so + // do not break into the debugger - TU_BREAKPOINT() halts the CPU whenever a probe is + // attached, which on a test rig is always. _usbd_dev.ep_status[epnum][dir] &= (uint8_t) ~(TU_EDPT_STATE_BUSY | TU_EDPT_STATE_CLAIMED); TU_LOG_USBD("FAILED\r\n"); - TU_BREAKPOINT(); return false; } } @@ -1668,10 +1692,21 @@ void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); - // only clear if currently stalled TU_LOG_USBD(" Clear Stall EP %02X\r\n", ep_addr); + const bool was_stalled = (_usbd_dev.ep_status[epnum][dir] & TU_EDPT_STATE_STALLED) != 0; dcd_edpt_clear_stall(rhport, ep_addr); - _usbd_dev.ep_status[epnum][dir] &= (uint8_t) ~(TU_EDPT_STATE_STALLED | TU_EDPT_STATE_BUSY); + // Clear STALLED|BUSY unconditionally (long-standing behavior; some classes, e.g. audio's + // set-interface, call this on a non-stalled endpoint solely to drop a leftover BUSY bit). + // Only release the CLAIMED ownership bit when the endpoint was actually stalled: the stall + // aborts the in-flight transfer in the dcd with no completion event to release the claim, so + // clearing it here prevents starvation. On a non-stalled clear (e.g. a data-toggle reset) a + // transfer may still be legitimately claimed by another task, so keep CLAIMED to preserve the + // claim->xfer mutual exclusion. + uint8_t clear_mask = TU_EDPT_STATE_STALLED | TU_EDPT_STATE_BUSY; + if (was_stalled) { + clear_mask |= TU_EDPT_STATE_CLAIMED; + } + _usbd_dev.ep_status[epnum][dir] &= (uint8_t) ~clear_mask; } bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr) { diff --git a/src/device/usbd.h b/src/device/usbd.h index abce5a887..2015d1869 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -248,7 +229,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ // Config number, interface count, string index, total length, attribute, power in mA #define TUD_CONFIG_DESCRIPTOR(config_num, _itfcount, _stridx, _total_len, _attribute, _power_ma) \ - 9, TUSB_DESC_CONFIGURATION, U16_TO_U8S_LE(_total_len), _itfcount, config_num, _stridx, TU_BIT(7) | _attribute, (_power_ma)/2 + 9, TUSB_DESC_CONFIGURATION, U16_TO_U8S_LE(_total_len), _itfcount, config_num, _stridx, TU_BIT(7) | _attribute, (uint8_t)TU_MIN((_power_ma)/2, UINT8_MAX) //--------------------------------------------------------------------+ // CDC Descriptor Templates diff --git a/src/device/usbd_pvt.h b/src/device/usbd_pvt.h index be778f9af..abf136e5c 100644 --- a/src/device/usbd_pvt.h +++ b/src/device/usbd_pvt.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/host/hcd.h b/src/host/hcd.h index 47d672f9e..e77a761c8 100644 --- a/src/host/hcd.h +++ b/src/host/hcd.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/host/hub.c b/src/host/hub.c index 7c6735ed4..4d2c30893 100644 --- a/src/host/hub.c +++ b/src/host/hub.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/host/hub.h b/src/host/hub.h index 8a7feda70..595b8b645 100644 --- a/src/host/hub.h +++ b/src/host/hub.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/host/usbh.c b/src/host/usbh.c index de53bfd03..94d075813 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -325,26 +306,14 @@ static usbh_class_driver_t const usbh_class_drivers[] = { }, #endif - #if CFG_TUH_VENDOR - { - .name = DRIVER_NAME("VENDOR"), - .init = cush_init, - .deinit = cush_deinit, - .open = cush_open, - .set_config = cush_set_config, - .xfer_cb = cush_isr, - .close = cush_close - } - #endif }; -enum { BUILTIN_DRIVER_COUNT = TU_ARRAY_SIZE(usbh_class_drivers) }; - // Additional class drivers implemented by application static usbh_class_driver_t const * _app_driver = NULL; -static uint8_t _app_driver_count = 0; +static const uint8_t _builtin_driver_count = TU_ARRAY_SIZE(usbh_class_drivers); +static uint8_t _app_driver_count = 0; -#define TOTAL_DRIVER_COUNT (_app_driver_count + BUILTIN_DRIVER_COUNT) +#define TOTAL_DRIVER_COUNT (_app_driver_count + _builtin_driver_count) // virtually joins built-in and application drivers together. // Application is positioned first to allow overwriting built-in ones. @@ -354,7 +323,7 @@ TU_ATTR_ALWAYS_INLINE static inline usbh_class_driver_t const *get_driver(uint8_ driver = &_app_driver[drv_id]; } else { drv_id -= _app_driver_count; - if (drv_id < BUILTIN_DRIVER_COUNT) { + if (_builtin_driver_count > 0 && drv_id < _builtin_driver_count) { driver = &usbh_class_drivers[drv_id]; } } @@ -417,12 +386,6 @@ TU_ATTR_ALWAYS_INLINE static inline void usbh_device_close(uint8_t rhport, uint8 _usbh_data.daddr_gen[daddr]++; (void) osal_mutex_unlock(_usbh_mutex); - // If this device has in-flight control xfer, complete as FAILED - usbh_ctrl_xfer_info_t* ctrl_info = &_usbh_data.ctrl_xfer_info; - if (daddr == ctrl_info->daddr && ctrl_info->stage != CONTROL_STAGE_IDLE) { - control_xfer_complete(daddr, XFER_RESULT_FAILED); - } - // invalidate if enumerating if (daddr == _usbh_data.enumerating_daddr) { _usbh_data.enumerating_daddr = TUSB_INDEX_INVALID_8; @@ -431,6 +394,12 @@ TU_ATTR_ALWAYS_INLINE static inline void usbh_device_close(uint8_t rhport, uint8 _usbh_data.call_after.func = NULL; } } + + // If this device has in-flight control xfer, complete as FAILED + usbh_ctrl_xfer_info_t* ctrl_info = &_usbh_data.ctrl_xfer_info; + if (daddr == ctrl_info->daddr && ctrl_info->stage != CONTROL_STAGE_IDLE) { + control_xfer_complete(daddr, XFER_RESULT_FAILED); + } } //--------------------------------------------------------------------+ @@ -566,6 +535,7 @@ bool tuh_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { // Get application driver if available _app_driver = usbh_app_driver_get_cb(&_app_driver_count); + TU_ASSERT(_app_driver_count + _builtin_driver_count <= UINT8_MAX); // Device tu_memclr(_usbh_devices, sizeof(_usbh_devices)); @@ -1130,7 +1100,10 @@ static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t // DATA stage: initial data toggle is always 1 control_xfer_set_stage(CONTROL_STAGE_DATA); const uint8_t ep_data = tu_edpt_addr(0, request->bmRequestType_bit.direction); - TU_ASSERT(hcd_edpt_xfer(rhport, daddr, ep_data, ctrl_info->buffer, request->wLength)); + if (!hcd_edpt_xfer(rhport, daddr, ep_data, ctrl_info->buffer, request->wLength)) { + control_xfer_complete(daddr, XFER_RESULT_FAILED); + return false; + } return true; } TU_ATTR_FALLTHROUGH; @@ -1145,7 +1118,10 @@ static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t // ACK stage: toggle is always 1 control_xfer_set_stage(CONTROL_STAGE_ACK); const uint8_t ep_status = tu_edpt_addr(0, 1 - request->bmRequestType_bit.direction); - TU_ASSERT(hcd_edpt_xfer(rhport, daddr, ep_status, NULL, 0)); + if (!hcd_edpt_xfer(rhport, daddr, ep_status, NULL, 0)) { + control_xfer_complete(daddr, XFER_RESULT_FAILED); + return false; + } break; } @@ -1747,8 +1723,10 @@ static void enum_delay_async(uintptr_t state) { if (dev0_bus->hub_addr != 0) { // connected via hub TU_VERIFY(dev0_bus->hub_port != 0, ); - TU_ASSERT(hub_port_get_status(dev0_bus->hub_addr, dev0_bus->hub_port, NULL, process_enumeration, - ENUM_HUB_RERSET), ); + if (!hub_port_get_status(dev0_bus->hub_addr, dev0_bus->hub_port, NULL, process_enumeration, + ENUM_HUB_RERSET)) { + enum_full_complete(false); + } } else #endif { @@ -1791,9 +1769,11 @@ static void enum_delay_async(uintptr_t state) { case ENUM_AFTER_RESET_HUB_DELAY: case ENUM_AFTER_RESET_HUB_DELAY_RETRY: // get status after reset complete to check for reset change - TU_ASSERT(hub_port_get_status(dev0_bus->hub_addr, dev0_bus->hub_port, NULL, process_enumeration, - state == ENUM_AFTER_RESET_HUB_DELAY ? ENUM_HUB_CLEAR_RESET - : ENUM_HUB_CLEAR_RESET_RETRY), ); + if (!hub_port_get_status(dev0_bus->hub_addr, dev0_bus->hub_port, NULL, process_enumeration, + state == ENUM_AFTER_RESET_HUB_DELAY ? ENUM_HUB_CLEAR_RESET + : ENUM_HUB_CLEAR_RESET_RETRY)) { + enum_full_complete(false); + } break; #endif @@ -1806,7 +1786,9 @@ static void enum_delay_async(uintptr_t state) { } // Get first 8 bytes of device descriptor for control endpoint size TU_LOG_USBH("Get 8 byte of Device Descriptor\r\n"); - TU_ASSERT(tuh_descriptor_get_device(0, _usbh_epbuf.ctrl, 8, process_enumeration, ENUM_SET_ADDR), ); + if (!tuh_descriptor_get_device(0, _usbh_epbuf.ctrl, 8, process_enumeration, ENUM_SET_ADDR)) { + enum_full_complete(false); + } break; case ENUM_AFTER_SET_ADDRESS_RECOVERY_DELAY: { @@ -1815,13 +1797,14 @@ static void enum_delay_async(uintptr_t state) { TU_ASSERT(new_dev, ); if (!usbh_edpt_control_open(new_addr, new_dev->desc_device.bMaxPacketSize0)) { TU_LOG_USBH("Failed to open new device's control endpoint\r\n"); - clear_device(new_dev); enum_full_complete(false); return; } TU_LOG_USBH("Get Device Descriptor\r\n"); - TU_ASSERT(tuh_descriptor_get_device(new_addr, _usbh_epbuf.ctrl, sizeof(tusb_desc_device_t), process_enumeration, - ENUM_GET_STRING_LANGUAGE_ID_LEN), ); + if (!tuh_descriptor_get_device(new_addr, _usbh_epbuf.ctrl, sizeof(tusb_desc_device_t), process_enumeration, + ENUM_GET_STRING_LANGUAGE_ID_LEN)) { + enum_full_complete(false); + } break; } @@ -1866,8 +1849,8 @@ static void process_enumeration(tuh_xfer_t *xfer) { TU_LOG_USBH("Device unplugged from hub while debouncing\r\n"); is_enum_failed = true; } else { - TU_ASSERT(hub_port_reset(dev0_bus->hub_addr, dev0_bus->hub_port, process_enumeration, - ENUM_HUB_RESET_COMPLETE), ); + is_enum_failed = !hub_port_reset(dev0_bus->hub_addr, dev0_bus->hub_port, process_enumeration, + ENUM_HUB_RESET_COMPLETE); } break; } @@ -1884,8 +1867,8 @@ static void process_enumeration(tuh_xfer_t *xfer) { if (1 == port_status.change.reset) { // Acknowledge Port Reset Change - TU_ASSERT(hub_port_clear_reset_change(dev0_bus->hub_addr, dev0_bus->hub_port, process_enumeration, - ENUM_HUB_CLEAR_RESET_COMPLETE), ); + is_enum_failed = !hub_port_clear_reset_change(dev0_bus->hub_addr, dev0_bus->hub_port, process_enumeration, + ENUM_HUB_CLEAR_RESET_COMPLETE); } else if (state == ENUM_HUB_CLEAR_RESET) { // retry one more time if reset change not set yet usbh_defer_func_ms_async(ENUM_RESET_HUB_DELAY_MS, enum_delay_async, ENUM_AFTER_RESET_HUB_DELAY_RETRY); @@ -1930,10 +1913,9 @@ static void process_enumeration(tuh_xfer_t *xfer) { usbh_device_t* new_dev = get_device(new_addr); new_dev->bus_info = *dev0_bus; - new_dev->connected = 1; new_dev->desc_device.bMaxPacketSize0 = desc_device->bMaxPacketSize0; - TU_ASSERT(tuh_address_set(0, new_addr, process_enumeration, ENUM_GET_DEVICE_DESC), ); + is_enum_failed = !tuh_address_set(0, new_addr, process_enumeration, ENUM_GET_DEVICE_DESC); break; } @@ -1941,6 +1923,7 @@ static void process_enumeration(tuh_xfer_t *xfer) { const uint8_t new_addr = (uint8_t)tu_le16toh(xfer->setup->wValue); usbh_device_t *new_dev = get_device(new_addr); TU_ASSERT(new_dev, ); + new_dev->connected = 1; new_dev->addressed = 1; _usbh_data.enumerating_daddr = new_addr; @@ -1958,15 +1941,15 @@ static void process_enumeration(tuh_xfer_t *xfer) { memcpy(&dev->desc_device, (const uint8_t*) desc_device + offsetof(tusb_desc_device_t, bcdUSB), sizeof(desc_device_noheader_t)); tuh_enum_descriptor_device_cb(daddr, desc_device); // callback - tuh_descriptor_get_string_langid(daddr, _usbh_epbuf.ctrl, 2, - process_enumeration, ENUM_GET_STRING_LANGUAGE_ID); + is_enum_failed = !tuh_descriptor_get_string_langid(daddr, _usbh_epbuf.ctrl, 2, + process_enumeration, ENUM_GET_STRING_LANGUAGE_ID); break; } case ENUM_GET_STRING_LANGUAGE_ID: { const uint8_t str_len = xfer->buffer[0]; - tuh_descriptor_get_string_langid(daddr, _usbh_epbuf.ctrl, str_len, - process_enumeration, ENUM_GET_STRING_MANUFACTURER_LEN); + is_enum_failed = !tuh_descriptor_get_string_langid(daddr, _usbh_epbuf.ctrl, str_len, + process_enumeration, ENUM_GET_STRING_MANUFACTURER_LEN); break; } @@ -1976,8 +1959,8 @@ static void process_enumeration(tuh_xfer_t *xfer) { langid = tu_le16toh(desc_langid->utf16le[0]); // previous request is langid } if (dev->desc_device.iManufacturer != 0) { - tuh_descriptor_get_string(daddr, dev->desc_device.iManufacturer, langid, _usbh_epbuf.ctrl, 2, - process_enumeration, ENUM_GET_STRING_MANUFACTURER); + is_enum_failed = !tuh_descriptor_get_string(daddr, dev->desc_device.iManufacturer, langid, _usbh_epbuf.ctrl, 2, + process_enumeration, ENUM_GET_STRING_MANUFACTURER); break; } TU_ATTR_FALLTHROUGH; @@ -1987,8 +1970,8 @@ static void process_enumeration(tuh_xfer_t *xfer) { if (dev->desc_device.iManufacturer != 0) { langid = tu_le16toh(xfer->setup->wIndex); // langid from length's request const uint8_t str_len = xfer->buffer[0]; - tuh_descriptor_get_string(daddr, dev->desc_device.iManufacturer, langid, _usbh_epbuf.ctrl, str_len, - process_enumeration, ENUM_GET_STRING_PRODUCT_LEN); + is_enum_failed = !tuh_descriptor_get_string(daddr, dev->desc_device.iManufacturer, langid, _usbh_epbuf.ctrl, + str_len, process_enumeration, ENUM_GET_STRING_PRODUCT_LEN); break; } TU_ATTR_FALLTHROUGH; @@ -1999,8 +1982,8 @@ static void process_enumeration(tuh_xfer_t *xfer) { if (state == ENUM_GET_STRING_PRODUCT_LEN) { langid = tu_le16toh(xfer->setup->wIndex); // get langid from previous setup packet if not fall through } - tuh_descriptor_get_string( - daddr, dev->desc_device.iProduct, langid, _usbh_epbuf.ctrl, 2, process_enumeration, ENUM_GET_STRING_PRODUCT); + is_enum_failed = !tuh_descriptor_get_string(daddr, dev->desc_device.iProduct, langid, _usbh_epbuf.ctrl, 2, + process_enumeration, ENUM_GET_STRING_PRODUCT); break; } TU_ATTR_FALLTHROUGH; @@ -2010,8 +1993,8 @@ static void process_enumeration(tuh_xfer_t *xfer) { if (dev->desc_device.iProduct != 0) { langid = tu_le16toh(xfer->setup->wIndex); // langid from length's request const uint8_t str_len = xfer->buffer[0]; - tuh_descriptor_get_string(daddr, dev->desc_device.iProduct, langid, _usbh_epbuf.ctrl, str_len, - process_enumeration, ENUM_GET_STRING_SERIAL_LEN); + is_enum_failed = !tuh_descriptor_get_string(daddr, dev->desc_device.iProduct, langid, _usbh_epbuf.ctrl, str_len, + process_enumeration, ENUM_GET_STRING_SERIAL_LEN); break; } TU_ATTR_FALLTHROUGH; @@ -2022,8 +2005,8 @@ static void process_enumeration(tuh_xfer_t *xfer) { if (state == ENUM_GET_STRING_SERIAL_LEN) { langid = tu_le16toh(xfer->setup->wIndex); // get langid from previous setup packet if not fall through } - tuh_descriptor_get_string( - daddr, dev->desc_device.iSerialNumber, langid, _usbh_epbuf.ctrl, 2, process_enumeration, ENUM_GET_STRING_SERIAL); + is_enum_failed = !tuh_descriptor_get_string(daddr, dev->desc_device.iSerialNumber, langid, _usbh_epbuf.ctrl, 2, + process_enumeration, ENUM_GET_STRING_SERIAL); break; } TU_ATTR_FALLTHROUGH; @@ -2033,8 +2016,8 @@ static void process_enumeration(tuh_xfer_t *xfer) { if (dev->desc_device.iSerialNumber != 0) { langid = tu_le16toh(xfer->setup->wIndex); // langid from length's request const uint8_t str_len = xfer->buffer[0]; - tuh_descriptor_get_string(daddr, dev->desc_device.iSerialNumber, langid, _usbh_epbuf.ctrl, str_len, - process_enumeration, ENUM_GET_9BYTE_CONFIG_DESC); + is_enum_failed = !tuh_descriptor_get_string(daddr, dev->desc_device.iSerialNumber, langid, _usbh_epbuf.ctrl, + str_len, process_enumeration, ENUM_GET_9BYTE_CONFIG_DESC); break; } TU_ATTR_FALLTHROUGH; @@ -2044,8 +2027,8 @@ static void process_enumeration(tuh_xfer_t *xfer) { // Get 9-byte for total length uint8_t const config_idx = 0; TU_LOG_USBH("Get Configuration[%u] Descriptor (9 bytes)\r\n", config_idx); - TU_ASSERT(tuh_descriptor_get_configuration(daddr, config_idx, _usbh_epbuf.ctrl, 9, - process_enumeration, ENUM_GET_FULL_CONFIG_DESC),); + is_enum_failed = !tuh_descriptor_get_configuration(daddr, config_idx, _usbh_epbuf.ctrl, 9, + process_enumeration, ENUM_GET_FULL_CONFIG_DESC); break; } @@ -2061,21 +2044,21 @@ static void process_enumeration(tuh_xfer_t *xfer) { // Get full configuration descriptor uint8_t const config_idx = (uint8_t) tu_le16toh(xfer->setup->wIndex); TU_LOG_USBH("Get Configuration[%u] Descriptor\r\n", config_idx); - TU_ASSERT(tuh_descriptor_get_configuration(daddr, config_idx, _usbh_epbuf.ctrl, total_len, - process_enumeration, ENUM_SET_CONFIG),); + is_enum_failed = !tuh_descriptor_get_configuration(daddr, config_idx, _usbh_epbuf.ctrl, total_len, + process_enumeration, ENUM_SET_CONFIG); break; } case ENUM_SET_CONFIG: { uint8_t config_idx = (uint8_t) tu_le16toh(xfer->setup->wIndex); if (tuh_enum_descriptor_configuration_cb(daddr, config_idx, (const tusb_desc_configuration_t*) _usbh_epbuf.ctrl)) { - TU_ASSERT(tuh_configuration_set(daddr, config_idx+1u, process_enumeration, ENUM_CONFIG_DRIVER),); + is_enum_failed = !tuh_configuration_set(daddr, config_idx+1u, process_enumeration, ENUM_CONFIG_DRIVER); } else { config_idx++; TU_ASSERT(config_idx < dev->desc_device.bNumConfigurations,); TU_LOG_USBH("Get Configuration[%u] Descriptor (9 bytes)\r\n", config_idx); - TU_ASSERT(tuh_descriptor_get_configuration(daddr, config_idx, _usbh_epbuf.ctrl, 9, - process_enumeration, ENUM_GET_FULL_CONFIG_DESC),); + is_enum_failed = !tuh_descriptor_get_configuration(daddr, config_idx, _usbh_epbuf.ctrl, 9, + process_enumeration, ENUM_GET_FULL_CONFIG_DESC); } break; } @@ -2179,7 +2162,8 @@ static bool enum_parse_configuration_desc(uint8_t dev_addr, tusb_desc_configurat TU_LOG_USBH(" %s opened\r\n", driver->name); // bind found driver to all interfaces and endpoint within drv_len - tu_bind_driver_to_ep_itf(drv_id, dev->ep2drv, dev->itf2drv, CFG_TUH_INTERFACE_MAX, p_desc, drv_len); + TU_ASSERT(tu_bind_driver_to_ep_itf(drv_id, dev->ep2drv, dev->itf2drv, CFG_TUH_INTERFACE_MAX, + CFG_TUH_ENDPOINT_MAX, p_desc, drv_len)); p_desc += drv_len; // next Interface break; // exit driver find loop @@ -2229,12 +2213,19 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num) { } static void enum_full_complete(bool success) { - (void)success; TU_LOG_USBH("Enumeration complete: success = %u\r\n", success); + const uint8_t daddr = _usbh_data.enumerating_daddr; _usbh_data.enumerating_daddr = TUSB_INDEX_INVALID_8; // mark enumeration as complete _usbh_data.call_after.func = NULL; + if (!success && daddr <= TOTAL_DEVICES) { + usbh_device_close(_usbh_data.dev0_bus.rhport, daddr); + if (daddr > 0) { + clear_device(get_device(daddr)); + } + } + #if CFG_TUH_HUB // Hub status is already requested in case of successful enumeration if (!success && _usbh_data.dev0_bus.hub_addr != 0) { diff --git a/src/host/usbh.h b/src/host/usbh.h index 7ddec35b7..ee80489e1 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/host/usbh_pvt.h b/src/host/usbh_pvt.h index adb6a8c44..8afda41ad 100644 --- a/src/host/usbh_pvt.h +++ b/src/host/usbh_pvt.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021, Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021, Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/osal/osal.h b/src/osal/osal.h index 2114c0a61..96ef604f0 100644 --- a/src/osal/osal.h +++ b/src/osal/osal.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/osal/osal_freertos.h b/src/osal/osal_freertos.h index 128626159..54bb6ab75 100644 --- a/src/osal/osal_freertos.h +++ b/src/osal/osal_freertos.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/osal/osal_mynewt.h b/src/osal/osal_mynewt.h index 5dd275cc4..faef74fc6 100644 --- a/src/osal/osal_mynewt.h +++ b/src/osal/osal_mynewt.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/osal/osal_none.h b/src/osal/osal_none.h index 49439cef0..c4b4d251e 100644 --- a/src/osal/osal_none.h +++ b/src/osal/osal_none.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/osal/osal_pico.h b/src/osal/osal_pico.h index 12dce839f..f20da71c4 100644 --- a/src/osal/osal_pico.h +++ b/src/osal/osal_pico.h @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * SPDX-FileCopyrightText: Copyright (c) 2020 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/osal/osal_rtthread.h b/src/osal/osal_rtthread.h index d65a2a783..a63db9c47 100644 --- a/src/osal/osal_rtthread.h +++ b/src/osal/osal_rtthread.h @@ -1,26 +1,8 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2020 tfx2001 ([email protected]) - * Copyright (c) 2020 yekai ([email protected]) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2020 tfx2001 ([email protected]) + * SPDX-FileCopyrightText: Copyright (c) 2020 yekai ([email protected]) + * SPDX-FileCopyrightText: Copyright (c) 2020 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/osal/osal_rtx4.h b/src/osal/osal_rtx4.h index ba082998a..3b5300622 100644 --- a/src/osal/osal_rtx4.h +++ b/src/osal/osal_rtx4.h @@ -1,26 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021 Tian Yunhao (t123yh) - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021 Tian Yunhao (t123yh) + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/osal/osal_threadx.h b/src/osal/osal_threadx.h index 020fd26aa..6cfbc009c 100644 --- a/src/osal/osal_threadx.h +++ b/src/osal/osal_threadx.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/osal/osal_zephyr.h b/src/osal/osal_zephyr.h index c84ce3970..0afa10eaf 100644 --- a/src/osal/osal_zephyr.h +++ b/src/osal/osal_zephyr.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2025 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2025 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index 971dbd62e..a3aefb829 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2023 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2023 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -82,6 +63,11 @@ enum { }; enum { + TIME_TO_EXIT_SUSPEND_MS = 4u, // datasheet: PWRDOWN = 1 to 0 to OSCOKIRQ = 3 ms + 1 ms margin + TIME_CHIPRES_DELAY_MS = 2u // CHIPRES hold: 2 guarantees >= 1 ms actual despite ms-tick quantization +}; + +enum { CPUCTL_IE = 1u << 0, CPUCTL_PULSEWID0 = 1u << 6, CPUCTL_PULSEWID1 = 1u << 7, @@ -490,8 +476,6 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { _hcd_data.spi_mutex = osal_mutex_create(&_hcd_data.spi_mutexdef); #endif - // NOTE: driver does not seem to work without nRST pin signal - // full duplex, interrupt negative edge reg_write(rhport, PINCTL_ADDR, _tuh_cfg.pinctl | PINCTL_FDUPSPI, false); @@ -501,12 +485,21 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { TU_LOG2_HEX(revision); TU_ASSERT(revision == 0x01 || revision == 0x12 || revision == 0x13, false); - // reset + // Software reset via CHIPRES. Per the Programming Guide, CHIPRES stops the internal oscillator; + // clearing it restarts the oscillator, and OSCOKIRQ latches on the resulting OSCOK 0->1 edge. + // Back-to-back writes hold reset for only ~us, too short for the high-Q crystal to actually stop, + // so no edge is generated and OSCOK never re-latches - this is the startup hang. Hold reset >= 1 ms + // (datasheet "PWRDOWN = 1 to oscillator stop = 5 us") so the oscillator fully stops and the edge fires. reg_write(rhport, USBCTL_ADDR, USBCTL_CHIPRES, false); + const uint32_t reset_start_ms = tusb_time_millis_api(); + while (tusb_time_millis_api() - reset_start_ms < TIME_CHIPRES_DELAY_MS) {} // hold reset so the oscillator stops reg_write(rhport, USBCTL_ADDR, 0, false); - while( !(reg_read(rhport, USBIRQ_ADDR, false) & USBIRQ_OSCOK_IRQ) ) { - // wait for oscillator to stabilize - } + + // Wait for OSCOK (12 MHz oscillator + 48 MHz PLL relock). Bounded as a safety net, so the host never + // hangs if the edge is still missed on some board - the clock is running regardless. + const uint32_t oscok_start_ms = tusb_time_millis_api(); + while (!(reg_read(rhport, USBIRQ_ADDR, false) & USBIRQ_OSCOK_IRQ) && + (tusb_time_millis_api() - oscok_start_ms < TIME_TO_EXIT_SUSPEND_MS)) {} // Mode: Host and DP/DM pull down mode_write(rhport, MODE_DPPULLDN | MODE_DMPULLDN | MODE_HOST, false); diff --git a/src/portable/analog/max3421/hcd_max3421.h b/src/portable/analog/max3421/hcd_max3421.h index 4631fa21a..38d78c8c2 100644 --- a/src/portable/analog/max3421/hcd_max3421.h +++ b/src/portable/analog/max3421/hcd_max3421.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2025 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2025 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/bridgetek/ft9xx/dcd_ft9xx.c b/src/portable/bridgetek/ft9xx/dcd_ft9xx.c index 89477b9ac..f6c8507db 100644 --- a/src/portable/bridgetek/ft9xx/dcd_ft9xx.c +++ b/src/portable/bridgetek/ft9xx/dcd_ft9xx.c @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright 2021 Bridgetek Pte Ltd - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright 2021 Bridgetek Pte Ltd + * SPDX-FileCopyrightText: Copyright (c) 2021 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/chipidea/ci_fs/ci_fs_kinetis.h b/src/portable/chipidea/ci_fs/ci_fs_kinetis.h index 31e14a546..e9370140d 100644 --- a/src/portable/chipidea/ci_fs/ci_fs_kinetis.h +++ b/src/portable/chipidea/ci_fs/ci_fs_kinetis.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2023 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2023 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/chipidea/ci_fs/ci_fs_mcx.h b/src/portable/chipidea/ci_fs/ci_fs_mcx.h index 4b93a03a7..425265cca 100644 --- a/src/portable/chipidea/ci_fs/ci_fs_mcx.h +++ b/src/portable/chipidea/ci_fs/ci_fs_mcx.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2023 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2023 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/chipidea/ci_fs/ci_fs_type.h b/src/portable/chipidea/ci_fs/ci_fs_type.h index 5a5e53fb0..857a75253 100644 --- a/src/portable/chipidea/ci_fs/ci_fs_type.h +++ b/src/portable/chipidea/ci_fs/ci_fs_type.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2023 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2023 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -46,6 +27,60 @@ extern "C" { // align 4 is used to get rid of reserved fields #define _va32 volatile TU_ATTR_ALIGNED(4) +//--------------------------------------------------------------------+ +// Buffer Descriptor Table (BDT) - shared by the device (dcd) and host (hcd) drivers +// since both target the same ChipIdea-FS silicon. Keep the layout in one place so a +// fix cannot silently drift between the two drivers. +//--------------------------------------------------------------------+ + +// Token PID values reported in the BDT tok_pid field / written to the TOKEN register. +// The device driver only uses OUT/IN/SETUP; the rest are host-only. +enum { + TOK_PID_OUT = 0x1u, + TOK_PID_IN = 0x9u, + TOK_PID_SETUP = 0xDu, + TOK_PID_DATA0 = 0x3u, + TOK_PID_DATA1 = 0xbu, + TOK_PID_ACK = 0x2u, + TOK_PID_STALL = 0xeu, + TOK_PID_NAK = 0xau, + TOK_PID_BUSTO = 0x0u, + TOK_PID_ERR = 0xfu, +}; + +// Note: this header is included before the CMSIS device header, so use plain `volatile` +// rather than CMSIS `__IO`. +typedef struct TU_ATTR_PACKED +{ + union { + uint32_t head; + struct { + union { + struct { + uint16_t : 2; + volatile uint16_t tok_pid : 4; + uint16_t data : 1; + volatile uint16_t own : 1; + uint16_t : 8; + }; + struct { + uint16_t : 2; + uint16_t bdt_stall : 1; + uint16_t dts : 1; + uint16_t ninc : 1; + uint16_t keep : 1; + uint16_t : 10; + }; + }; + volatile uint16_t bc : 10; + uint16_t : 6; + }; + }; + uint8_t *addr; +}buffer_descriptor_t; + +TU_VERIFY_STATIC( sizeof(buffer_descriptor_t) == 8, "size is not correct" ); + typedef struct { _va32 uint8_t PER_ID; // [00] Peripheral ID register _va32 uint8_t ID_COMP; // [04] Peripheral ID complement register diff --git a/src/portable/chipidea/ci_fs/dcd_ci_fs.c b/src/portable/chipidea/ci_fs/dcd_ci_fs.c index 62df1a6d5..295f2e578 100644 --- a/src/portable/chipidea/ci_fs/dcd_ci_fs.c +++ b/src/portable/chipidea/ci_fs/dcd_ci_fs.c @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2020 Koji Kitayama - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2020 Koji Kitayama + * SPDX-FileCopyrightText: Copyright (c) 2020 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -42,43 +24,7 @@ //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM DECLARATION //--------------------------------------------------------------------+ - -enum { - TOK_PID_OUT = 0x1u, - TOK_PID_IN = 0x9u, - TOK_PID_SETUP = 0xDu, -}; - -typedef struct TU_ATTR_PACKED -{ - union { - uint32_t head; - struct { - union { - struct { - uint16_t : 2; - __IO uint16_t tok_pid : 4; - uint16_t data : 1; - __IO uint16_t own : 1; - uint16_t : 8; - }; - struct { - uint16_t : 2; - uint16_t bdt_stall : 1; - uint16_t dts : 1; - uint16_t ninc : 1; - uint16_t keep : 1; - uint16_t : 10; - }; - }; - __IO uint16_t bc : 10; - uint16_t : 6; - }; - }; - uint8_t *addr; -}buffer_descriptor_t; - -TU_VERIFY_STATIC( sizeof(buffer_descriptor_t) == 8, "size is not correct" ); +// TOK_PID_* and buffer_descriptor_t are shared with the host driver in ci_fs_type.h typedef struct TU_ATTR_PACKED { @@ -193,6 +139,17 @@ static void process_tokdne(uint8_t rhport) return; } const unsigned length = ep->length; + + /* Transfer is complete. For OUT, a multi-packet transfer speculatively arms the + * sibling (even/odd) BDT to avoid NAK. When the transfer ends early - e.g. the host + * sends a short packet before filling both buffers - that sibling is left armed + * (own=1). A leftover armed BDT desyncs the even/odd ping-pong so the next OUT + * packet lands in the wrong buffer half (buffer + max_packet_size instead of + * buffer), making the stack read stale data. Disarm it here. */ + if (dir == TUSB_DIR_OUT) { + _dcd.bdt[epnum][dir][odd ^ 1].own = 0; + } + dcd_event_xfer_complete(rhport, tu_edpt_addr(epnum, dir), length - remaining, XFER_RESULT_SUCCESS, true); diff --git a/src/portable/nxp/khci/hcd_khci.c b/src/portable/chipidea/ci_fs/hcd_ci_fs.c index 45732a866..a6f5405b5 100644 --- a/src/portable/nxp/khci/hcd_khci.c +++ b/src/portable/chipidea/ci_fs/hcd_ci_fs.c @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021 Koji Kitayama - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021 Koji Kitayama + * SPDX-FileCopyrightText: Copyright (c) 2021 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -28,63 +10,28 @@ #if CFG_TUH_ENABLED && defined(TUP_USBIP_CHIPIDEA_FS) -#ifdef TUP_USBIP_CHIPIDEA_FS_KINETIS +#include "host/hcd.h" +#include "host/usbh.h" +#include "ci_fs_type.h" + +// Host is currently only available on NXP Kinetis. The ChipIdea-FS host controller +// interface is register-compatible via ci_fs_regs_t. Unlike the device driver, the host +// driver does not include the ci_fs_<family>.h header because those define the device +// dcd_int_enable()/dcd_int_disable() functions, which would collide in a dual-role build. +#if defined(TUP_USBIP_CHIPIDEA_FS_KINETIS) #include "fsl_device_registers.h" - #define KHCI USB0 + #define CI_FS_REG(_port) ((ci_fs_regs_t*) USB0_BASE) + #define CI_FS_IRQN USB0_IRQn #else #error "MCU is not supported" #endif -#include "host/hcd.h" -#include "host/usbh.h" +#define CI_REG CI_FS_REG(0) //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM DECLARATION //--------------------------------------------------------------------+ - -enum { - TOK_PID_OUT = 0x1u, - TOK_PID_IN = 0x9u, - TOK_PID_SETUP = 0xDu, - TOK_PID_DATA0 = 0x3u, - TOK_PID_DATA1 = 0xbu, - TOK_PID_ACK = 0x2u, - TOK_PID_STALL = 0xeu, - TOK_PID_NAK = 0xau, - TOK_PID_BUSTO = 0x0u, - TOK_PID_ERR = 0xfu, -}; - -typedef struct TU_ATTR_PACKED -{ - union { - uint32_t head; - struct { - union { - struct { - uint16_t : 2; - __IO uint16_t tok_pid : 4; - uint16_t data : 1; - __IO uint16_t own : 1; - uint16_t : 8; - }; - struct { - uint16_t : 2; - uint16_t bdt_stall : 1; - uint16_t dts : 1; - uint16_t ninc : 1; - uint16_t keep : 1; - uint16_t : 10; - }; - }; - __IO uint16_t bc : 10; - uint16_t : 6; - }; - }; - uint8_t *addr; -}buffer_descriptor_t; - -TU_VERIFY_STATIC( sizeof(buffer_descriptor_t) == 8, "size is not correct" ); +// TOK_PID_* and buffer_descriptor_t are shared with the device driver in ci_fs_type.h typedef struct TU_ATTR_PACKED { @@ -125,7 +72,10 @@ typedef struct union { /* [OUT,IN][EVEN,ODD] */ buffer_descriptor_t bdt[2][2]; - uint16_t bda[2*2]; + /* bda aliases bdt for STAT-register indexing: STAT gives the byte-offset/2 of the + * completed BD, so it indexes bda[] in uint16_t units. Each buffer_descriptor_t is + * 4 uint16_t, hence 2*2*4 elements to span the whole table (must equal sizeof bdt). */ + uint16_t bda[2*2*4]; }; endpoint_state_t endpoint[2]; pipe_state_t pipe[CFG_TUH_ENDPOINT_MAX * 2]; @@ -160,7 +110,9 @@ static int prepare_packets(int pipenum) endpoint_state_t *ep = &_hcd.endpoint[dir_tx]; unsigned const odd = ep->odd; buffer_descriptor_t *bd = _hcd.bdt[dir_tx]; - TU_ASSERT(0 == bd[odd].own, -1); + // The host shares a single BDT set across all pipes. If it is still owned by an + // in-flight transfer on another pipe, report busy so the caller can defer & retry. + if (bd[odd].own) return -1; // TU_LOG1(" %p dir %d odd %d data %d\r\n", &bd[odd], dir_tx, odd, pipe->data); @@ -218,11 +170,11 @@ static bool continue_transfer(int pipenum, buffer_descriptor_t *bd) bd->bc = next_rem > pipe->max_packet_size ? pipe->max_packet_size: next_rem; __DSB(); bd->own = 1; /* This bit must be set last */ - while (KHCI->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ; - KHCI->TOKEN = KHCI->TOKEN; /* Queue the same token as the last */ + while (CI_REG->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ; + CI_REG->TOKEN = CI_REG->TOKEN; /* Queue the same token as the last */ } else if (TUSB_DIR_IN == tu_edpt_dir(pipe->ep_addr)) { /* IN */ - while (KHCI->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ; - KHCI->TOKEN = KHCI->TOKEN; + while (CI_REG->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ; + CI_REG->TOKEN = CI_REG->TOKEN; } return true; } @@ -233,13 +185,21 @@ static bool continue_transfer(int pipenum, buffer_descriptor_t *bd) static bool resume_transfer(int pipenum) { int num_tokens = prepare_packets(pipenum); - TU_ASSERT(0 <= num_tokens); + if (num_tokens < 0) { + // Shared BDT still owned by an in-flight transfer on another pipe. Defer this + // pipe and retry on the next SOF once the BDT is free (avoids dropping the + // transfer, which stalls e.g. a 2nd device enumerating behind a hub while the + // app issues concurrent control transfers). + _hcd.pending |= TU_BIT(pipenum); + CI_REG->INT_EN |= USB_ISTAT_SOFTOK_MASK; + return true; + } - const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn); - NVIC_DisableIRQ(USB0_IRQn); + const unsigned ie = NVIC_GetEnableIRQ(CI_FS_IRQN); + NVIC_DisableIRQ(CI_FS_IRQN); pipe_state_t *pipe = &_hcd.pipe[pipenum]; - unsigned flags = KHCI->ENDPOINT[0].ENDPT & USB_ENDPT_HOSTWOHUB_MASK; + unsigned flags = CI_REG->EP[0].CTL & USB_ENDPT_HOSTWOHUB_MASK; flags |= USB_ENDPT_EPRXEN_MASK | USB_ENDPT_EPTXEN_MASK; switch (pipe->xfer) { case TUSB_XFER_CONTROL: @@ -254,16 +214,16 @@ static bool resume_transfer(int pipenum) } // TU_LOG1(" resume pipenum %d flags %x\r\n", pipenum, flags); - KHCI->ENDPOINT[0].ENDPT = flags; - KHCI->ADDR = (KHCI->ADDR & USB_ADDR_LSEN_MASK) | pipe->dev_addr; + CI_REG->EP[0].CTL = flags; + CI_REG->ADDR = (CI_REG->ADDR & USB_ADDR_LSEN_MASK) | pipe->dev_addr; unsigned const token = tu_edpt_number(pipe->ep_addr) | ((tu_edpt_dir(pipe->ep_addr) ? TOK_PID_IN: TOK_PID_OUT) << USB_TOKEN_TOKENPID_SHIFT); do { - while (KHCI->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ; - KHCI->TOKEN = token; + while (CI_REG->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ; + CI_REG->TOKEN = token; } while (--num_tokens); - if (ie) NVIC_EnableIRQ(USB0_IRQn); + if (ie) NVIC_EnableIRQ(CI_FS_IRQN); return true; } @@ -271,19 +231,38 @@ static void suspend_transfer(int pipenum, buffer_descriptor_t *bd) { pipe_state_t *pipe = &_hcd.pipe[pipenum]; pipe->buffer = bd->addr; - pipe->data = bd->data ^ 1; + // A NAK transfers no data, so the data toggle must be preserved for the retry. + // (Do NOT flip pipe->data here: flipping it makes the retried packet use the wrong + // DATA0/DATA1, which the device silently discards - breaking any bulk/interrupt + // transfer that is NAKed, e.g. the MSC CBW/CSW when the device is momentarily busy.) if ((TUSB_XFER_INTERRUPT == pipe->xfer) || (TUSB_XFER_BULK == pipe->xfer)) { _hcd.pending |= TU_BIT(pipenum); - KHCI->INTEN |= USB_ISTAT_SOFTOK_MASK; + CI_REG->INT_EN |= USB_ISTAT_SOFTOK_MASK; + } +} + +// Release the speculatively-armed sibling BDT of a multi-packet transfer. +// prepare_packets arms the sibling (odd^1) BDT (own=1) so a multi-packet transfer can +// ping-pong without NAKs. When the transfer ends - completes early on a short IN packet, +// stalls/errors, or (for IN) is NAKed before the sibling's token is issued - that sibling +// is left owned by the SIE. Because the host shares ONE BDT set across all pipes, a +// leftover armed sibling blocks every other pipe forever (e.g. a 2nd device stuck +// enumerating behind a hub). Release it - but ONLY for a multi-packet transfer: a +// single-packet transfer never armed a sibling, so that BDT slot may legitimately belong +// to another pipe's in-flight transfer. +static inline void release_sibling_bd(unsigned s, const pipe_state_t *pipe) +{ + if (pipe->length > pipe->max_packet_size) { + ((buffer_descriptor_t *)&_hcd.bda[s ^ USB_STAT_ODD_MASK])->own = 0; } } static void process_tokdne(uint8_t rhport) { (void)rhport; - const unsigned s = KHCI->STAT; - KHCI->ISTAT = USB_ISTAT_TOKDNE_MASK; /* fetch the next token if received */ + const unsigned s = CI_REG->STAT; + CI_REG->INT_STAT = USB_ISTAT_TOKDNE_MASK; /* fetch the next token if received */ uint8_t const dir_in = (s & USB_STAT_TX_MASK) ? TUSB_DIR_OUT: TUSB_DIR_IN; unsigned const odd = (s & USB_STAT_ODD_MASK) ? 1 : 0; @@ -313,6 +292,12 @@ static void process_tokdne(uint8_t rhport) result = XFER_RESULT_SUCCESS; break; case TOK_PID_NAK: + // Release the speculatively-armed sibling so the deferred retry (and any other pipe + // sharing the single BDT) can claim it; otherwise it stays own=1 forever and every + // same-direction transfer wedges. IN only: an IN issues just one token so the sibling + // was never put on the wire, whereas an OUT issues both tokens and its sibling may + // still be in flight - touching it there would race the SIE write-back. + if (TUSB_DIR_IN == dir_in) release_sibling_bd(s, &_hcd.pipe[pipenum]); suspend_transfer(pipenum, bd); next_pipenum = select_next_pipenum(pipenum); if (0 <= next_pipenum) @@ -328,8 +313,9 @@ static void process_tokdne(uint8_t rhport) } _hcd.in_progress &= ~TU_BIT(pipenum); pipe_state_t *pipe = &_hcd.pipe[ep->pipenum]; + release_sibling_bd(s, pipe); hcd_event_xfer_complete(pipe->dev_addr, - tu_edpt_addr(KHCI->TOKEN & USB_TOKEN_TOKENENDPT_MASK, dir_in), + tu_edpt_addr(CI_REG->TOKEN & USB_TOKEN_TOKENENDPT_MASK, dir_in), pipe->length - pipe->remaining, result, true); next_pipenum = select_next_pipenum(pipenum); @@ -339,29 +325,32 @@ static void process_tokdne(uint8_t rhport) static void process_attach(uint8_t rhport) { - unsigned ctl = KHCI->CTL; + unsigned ctl = CI_REG->CTL; if (!(ctl & USB_CTL_JSTATE_MASK)) { /* The attached device is a low speed device. */ - KHCI->ADDR = USB_ADDR_LSEN_MASK; - KHCI->ENDPOINT[0].ENDPT = USB_ENDPT_HOSTWOHUB_MASK; + CI_REG->ADDR = USB_ADDR_LSEN_MASK; + CI_REG->EP[0].CTL = USB_ENDPT_HOSTWOHUB_MASK; } hcd_event_device_attach(rhport, true); } static void process_bus_reset(uint8_t rhport) { - KHCI->ISTAT = USB_ISTAT_TOKDNE_MASK; - KHCI->USBCTRL &= ~USB_USBCTRL_SUSP_MASK; - KHCI->CTL &= ~USB_CTL_USBENSOFEN_MASK; - KHCI->ADDR = 0; - KHCI->ENDPOINT[0].ENDPT = 0; + CI_REG->INT_STAT = USB_ISTAT_TOKDNE_MASK; + CI_REG->USBCTRL &= ~USB_USBCTRL_SUSP_MASK; + CI_REG->CTL &= ~USB_CTL_USBENSOFEN_MASK; + CI_REG->ADDR = 0; + CI_REG->EP[0].CTL = 0; hcd_event_device_remove(rhport, true); _hcd.in_progress = 0; _hcd.pending = 0; + // Clear the ENTIRE shared BDT (both directions, both even/odd). Clearing only the IN + // pair left a stale OUT/SETUP descriptor (own=1) after a disconnect mid-OUT, which then + // blocks the first control transfer on re-enumeration. buffer_descriptor_t *bd = &_hcd.bdt[0][0]; - for (unsigned i = 0; i < 2; ++i, ++bd) { + for (unsigned i = 0; i < 2 * 2; ++i, ++bd) { bd->head = 0; } } @@ -372,31 +361,31 @@ static void process_bus_reset(uint8_t rhport) bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { (void) rhport; (void) rh_init; - KHCI->USBTRC0 |= USB_USBTRC0_USBRESET_MASK; - while (KHCI->USBTRC0 & USB_USBTRC0_USBRESET_MASK); + CI_REG->USBTRC0 |= USB_USBTRC0_USBRESET_MASK; + while (CI_REG->USBTRC0 & USB_USBTRC0_USBRESET_MASK); tu_memclr(&_hcd, sizeof(_hcd)); - KHCI->USBTRC0 |= TU_BIT(6); /* software must set this bit to 1 */ - KHCI->BDTPAGE1 = (uint8_t)((uintptr_t)_hcd.bdt >> 8); - KHCI->BDTPAGE2 = (uint8_t)((uintptr_t)_hcd.bdt >> 16); - KHCI->BDTPAGE3 = (uint8_t)((uintptr_t)_hcd.bdt >> 24); + CI_REG->USBTRC0 |= TU_BIT(6); /* software must set this bit to 1 */ + CI_REG->BDT_PAGE1 = (uint8_t)((uintptr_t)_hcd.bdt >> 8); + CI_REG->BDT_PAGE2 = (uint8_t)((uintptr_t)_hcd.bdt >> 16); + CI_REG->BDT_PAGE3 = (uint8_t)((uintptr_t)_hcd.bdt >> 24); - KHCI->USBCTRL &= ~USB_USBCTRL_SUSP_MASK; - KHCI->CTL |= USB_CTL_ODDRST_MASK; + CI_REG->USBCTRL &= ~USB_USBCTRL_SUSP_MASK; + CI_REG->CTL |= USB_CTL_ODDRST_MASK; for (unsigned i = 0; i < 16; ++i) { - KHCI->ENDPOINT[i].ENDPT = 0; + CI_REG->EP[i].CTL = 0; } - KHCI->CTL &= ~USB_CTL_ODDRST_MASK; + CI_REG->CTL &= ~USB_CTL_ODDRST_MASK; - KHCI->SOFTHLD = 74; /* for 64-byte packets */ - // KHCI->SOFTHLD = 144; /* for low speed 8-byte packets */ - KHCI->CTL = USB_CTL_HOSTMODEEN_MASK | USB_CTL_SE0_MASK; - KHCI->USBCTRL = USB_USBCTRL_PDE_MASK; + CI_REG->SOF_THLD = 74; /* for 64-byte packets */ + // CI_REG->SOF_THLD = 144; /* for low speed 8-byte packets */ + CI_REG->CTL = USB_CTL_HOSTMODEEN_MASK | USB_CTL_SE0_MASK; + CI_REG->USBCTRL = USB_USBCTRL_PDE_MASK; - NVIC_ClearPendingIRQ(USB0_IRQn); - KHCI->INTEN = USB_INTEN_ATTACHEN_MASK | USB_INTEN_TOKDNEEN_MASK | + NVIC_ClearPendingIRQ(CI_FS_IRQN); + CI_REG->INT_EN = USB_INTEN_ATTACHEN_MASK | USB_INTEN_TOKDNEEN_MASK | USB_INTEN_USBRSTEN_MASK | USB_INTEN_ERROREN_MASK | USB_INTEN_STALLEN_MASK; - KHCI->ERREN = 0xff; + CI_REG->ERR_ENB = 0xff; return true; } @@ -404,13 +393,13 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { void hcd_int_enable(uint8_t rhport) { (void)rhport; - NVIC_EnableIRQ(USB0_IRQn); + NVIC_EnableIRQ(CI_FS_IRQN); } void hcd_int_disable(uint8_t rhport) { (void)rhport; - NVIC_DisableIRQ(USB0_IRQn); + NVIC_DisableIRQ(CI_FS_IRQN); } uint32_t hcd_frame_number(uint8_t rhport) @@ -419,8 +408,8 @@ uint32_t hcd_frame_number(uint8_t rhport) /* The device must be reset at least once after connection * in order to start the frame counter. */ if (_hcd.need_reset) hcd_port_reset(rhport); - uint32_t frmnum = KHCI->FRMNUML; - frmnum |= KHCI->FRMNUMH << 8u; + uint32_t frmnum = CI_REG->FRM_NUML; + frmnum |= CI_REG->FRM_NUMH << 8u; return frmnum; } @@ -430,7 +419,7 @@ uint32_t hcd_frame_number(uint8_t rhport) bool hcd_port_connect_status(uint8_t rhport) { (void)rhport; - if (KHCI->ISTAT & USB_ISTAT_ATTACH_MASK) + if (CI_REG->INT_STAT & USB_ISTAT_ATTACH_MASK) return true; return false; } @@ -438,12 +427,12 @@ bool hcd_port_connect_status(uint8_t rhport) void hcd_port_reset(uint8_t rhport) { (void)rhport; - KHCI->CTL &= ~USB_CTL_USBENSOFEN_MASK; - KHCI->CTL |= USB_CTL_RESET_MASK; + CI_REG->CTL &= ~USB_CTL_USBENSOFEN_MASK; + CI_REG->CTL |= USB_CTL_RESET_MASK; unsigned cnt = SystemCoreClock / 100; while (cnt--) __NOP(); - KHCI->CTL &= ~USB_CTL_RESET_MASK; - KHCI->CTL |= USB_CTL_USBENSOFEN_MASK; + CI_REG->CTL &= ~USB_CTL_RESET_MASK; + CI_REG->CTL |= USB_CTL_USBENSOFEN_MASK; _hcd.need_reset = false; } @@ -455,26 +444,26 @@ tusb_speed_t hcd_port_speed_get(uint8_t rhport) { (void)rhport; tusb_speed_t speed = TUSB_SPEED_FULL; - const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn); - NVIC_DisableIRQ(USB0_IRQn); - if (KHCI->ADDR & USB_ADDR_LSEN_MASK) + const unsigned ie = NVIC_GetEnableIRQ(CI_FS_IRQN); + NVIC_DisableIRQ(CI_FS_IRQN); + if (CI_REG->ADDR & USB_ADDR_LSEN_MASK) speed = TUSB_SPEED_LOW; - if (ie) NVIC_EnableIRQ(USB0_IRQn); + if (ie) NVIC_EnableIRQ(CI_FS_IRQN); return speed; } void hcd_device_close(uint8_t rhport, uint8_t dev_addr) { (void)rhport; - const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn); - NVIC_DisableIRQ(USB0_IRQn); + const unsigned ie = NVIC_GetEnableIRQ(CI_FS_IRQN); + NVIC_DisableIRQ(CI_FS_IRQN); pipe_state_t *p = &_hcd.pipe[0]; pipe_state_t *end = &_hcd.pipe[CFG_TUH_ENDPOINT_MAX * 2]; for (;p != end; ++p) { if (p->dev_addr == dev_addr) tu_memclr(p, sizeof(*p)); } - if (ie) NVIC_EnableIRQ(USB0_IRQn); + if (ie) NVIC_EnableIRQ(CI_FS_IRQN); } //--------------------------------------------------------------------+ @@ -501,12 +490,12 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet _hcd.in_progress |= TU_BIT(pipenum); - unsigned hostwohub = KHCI->ENDPOINT[0].ENDPT & USB_ENDPT_HOSTWOHUB_MASK; - KHCI->ENDPOINT[0].ENDPT = hostwohub | + unsigned hostwohub = CI_REG->EP[0].CTL & USB_ENDPT_HOSTWOHUB_MASK; + CI_REG->EP[0].CTL = hostwohub | USB_ENDPT_EPHSHK_MASK | USB_ENDPT_EPRXEN_MASK | USB_ENDPT_EPTXEN_MASK; - KHCI->ADDR = (KHCI->ADDR & USB_ADDR_LSEN_MASK) | dev_addr; - while (KHCI->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ; - KHCI->TOKEN = (TOK_PID_SETUP << USB_TOKEN_TOKENPID_SHIFT); + CI_REG->ADDR = (CI_REG->ADDR & USB_ADDR_LSEN_MASK) | dev_addr; + while (CI_REG->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ; + CI_REG->TOKEN = (TOK_PID_SETUP << USB_TOKEN_TOKENPID_SHIFT); return true; } @@ -558,16 +547,16 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * TU_ASSERT(0 <= pipenum); TU_ASSERT(0 == (_hcd.in_progress & TU_BIT(pipenum))); - unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn); - NVIC_DisableIRQ(USB0_IRQn); + unsigned const ie = NVIC_GetEnableIRQ(CI_FS_IRQN); + NVIC_DisableIRQ(CI_FS_IRQN); pipe_state_t *pipe = &_hcd.pipe[pipenum]; pipe->buffer = buffer; pipe->length = buflen; pipe->remaining = buflen; _hcd.in_progress |= TU_BIT(pipenum); _hcd.pending |= TU_BIT(pipenum); /* Send at the next Frame */ - KHCI->INTEN |= USB_ISTAT_SOFTOK_MASK; - if (ie) NVIC_EnableIRQ(USB0_IRQn); + CI_REG->INT_EN |= USB_ISTAT_SOFTOK_MASK; + if (ie) NVIC_EnableIRQ(CI_FS_IRQN); return true; } @@ -595,42 +584,42 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { void hcd_int_handler(uint8_t rhport, bool in_isr) { (void) in_isr; - uint32_t is = KHCI->ISTAT; - uint32_t msk = KHCI->INTEN; + uint32_t is = CI_REG->INT_STAT; + uint32_t msk = CI_REG->INT_EN; // TU_LOG1("S %lx\r\n", is); /* clear disabled interrupts */ - KHCI->ISTAT = (is & ~msk & ~USB_ISTAT_TOKDNE_MASK) | USB_ISTAT_SOFTOK_MASK; + CI_REG->INT_STAT = (is & ~msk & ~USB_ISTAT_TOKDNE_MASK) | USB_ISTAT_SOFTOK_MASK; is &= msk; if (is & USB_ISTAT_ERROR_MASK) { - unsigned err = KHCI->ERRSTAT; + unsigned err = CI_REG->ERR_STAT; if (err) { TU_LOG1(" ERR %x\r\n", err); - KHCI->ERRSTAT = err; + CI_REG->ERR_STAT = err; } else { - KHCI->INTEN &= ~USB_ISTAT_ERROR_MASK; + CI_REG->INT_EN &= ~USB_ISTAT_ERROR_MASK; } } if (is & USB_ISTAT_USBRST_MASK) { - KHCI->INTEN = (msk & ~USB_INTEN_USBRSTEN_MASK) | USB_INTEN_ATTACHEN_MASK; + CI_REG->INT_EN = (msk & ~USB_INTEN_USBRSTEN_MASK) | USB_INTEN_ATTACHEN_MASK; process_bus_reset(rhport); return; } if (is & USB_ISTAT_ATTACH_MASK) { - KHCI->INTEN = (msk & ~USB_INTEN_ATTACHEN_MASK) | USB_INTEN_USBRSTEN_MASK; + CI_REG->INT_EN = (msk & ~USB_INTEN_ATTACHEN_MASK) | USB_INTEN_USBRSTEN_MASK; _hcd.need_reset = true; process_attach(rhport); return; } if (is & USB_ISTAT_STALL_MASK) { - KHCI->ISTAT = USB_ISTAT_STALL_MASK; + CI_REG->INT_STAT = USB_ISTAT_STALL_MASK; } if (is & USB_ISTAT_SOFTOK_MASK) { msk &= ~USB_ISTAT_SOFTOK_MASK; - KHCI->INTEN = msk; + CI_REG->INT_EN = msk; if (_hcd.pending) { int pipenum = __builtin_ctz(_hcd.pending); _hcd.pending = 0; diff --git a/src/portable/chipidea/ci_hs/ci_hs_hpm.h b/src/portable/chipidea/ci_hs/ci_hs_hpm.h index 68211448c..327ffb2c4 100644 --- a/src/portable/chipidea/ci_hs/ci_hs_hpm.h +++ b/src/portable/chipidea/ci_hs/ci_hs_hpm.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021, Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021, Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/chipidea/ci_hs/ci_hs_imxrt.h b/src/portable/chipidea/ci_hs/ci_hs_imxrt.h index 75d1d55b8..8f0d6083e 100644 --- a/src/portable/chipidea/ci_hs/ci_hs_imxrt.h +++ b/src/portable/chipidea/ci_hs/ci_hs_imxrt.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021, Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021, Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -55,6 +36,9 @@ static const ci_hs_controller_t _ci_controller[] = #define CI_HS_REG(_port) ((ci_hs_regs_t*) _ci_controller[_port].reg_base) +// NXP recommends AHBBRST = INCR16 (remainder as unspecified-length bursts) +#define CI_HS_SET_AHB_BURST(_p) (CI_HS_REG(_p)->SBUSCFG = SBUSCFG_AHBBRST_INCR16_UNSPEC) + //------------- DCD -------------// #define CI_DCD_INT_ENABLE(_p) NVIC_EnableIRQ ((IRQn_Type)_ci_controller[_p].irqnum) #define CI_DCD_INT_DISABLE(_p) NVIC_DisableIRQ((IRQn_Type)_ci_controller[_p].irqnum) diff --git a/src/portable/chipidea/ci_hs/ci_hs_lpc18_43.h b/src/portable/chipidea/ci_hs/ci_hs_lpc18_43.h index c22aea887..c7dc7e69f 100644 --- a/src/portable/chipidea/ci_hs/ci_hs_lpc18_43.h +++ b/src/portable/chipidea/ci_hs/ci_hs_lpc18_43.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021, Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021, Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -53,4 +34,9 @@ static const ci_hs_controller_t _ci_controller[] = #define CI_HCD_INT_ENABLE(_p) NVIC_EnableIRQ ((IRQn_Type)_ci_controller[_p].irqnum) #define CI_HCD_INT_DISABLE(_p) NVIC_DisableIRQ((IRQn_Type)_ci_controller[_p].irqnum) +// USB0 (high-speed) only: NXP recommends AHBBRST = INCR16 (remainder as +// unspecified-length bursts) +#define CI_HS_SET_AHB_BURST(_p) \ + do { if ((_p) == 0) { CI_HS_REG(_p)->SBUSCFG = SBUSCFG_AHBBRST_INCR16_UNSPEC; } } while (0) + #endif diff --git a/src/portable/chipidea/ci_hs/ci_hs_mcx.h b/src/portable/chipidea/ci_hs/ci_hs_mcx.h index f940f4a9d..ebf52de39 100644 --- a/src/portable/chipidea/ci_hs/ci_hs_mcx.h +++ b/src/portable/chipidea/ci_hs/ci_hs_mcx.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021, Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021, Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/chipidea/ci_hs/ci_hs_rw61x.h b/src/portable/chipidea/ci_hs/ci_hs_rw61x.h index 114fe26c3..ddd08da6b 100644 --- a/src/portable/chipidea/ci_hs/ci_hs_rw61x.h +++ b/src/portable/chipidea/ci_hs/ci_hs_rw61x.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021, Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021, Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/chipidea/ci_hs/ci_hs_type.h b/src/portable/chipidea/ci_hs/ci_hs_type.h index 2f3aa3694..b3ef3b6af 100644 --- a/src/portable/chipidea/ci_hs/ci_hs_type.h +++ b/src/portable/chipidea/ci_hs/ci_hs_type.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021, Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021, Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -48,6 +29,14 @@ enum { USBCMD_INTR_THRESHOLD_MASK = 0x00FF0000u, // Interrupt Threshold bit 23:16 }; +// DEVICEADDR +#define DEVICEADDR_USBADR_POS 25 + +enum { + DEVICEADDR_USBADRA = TU_BIT(24), ///< Device Address Advance: stage USBADR until the next EP0 IN is ACKed + DEVICEADDR_USBADR_MASK = 0xFE000000u, ///< Device Address bit 31:25 +}; + // PORTSC1 #define PORTSC1_PORT_SPEED_POS 26 @@ -55,10 +44,18 @@ enum { PORTSC1_CURRENT_CONNECT_STATUS = TU_BIT(0), PORTSC1_FORCE_PORT_RESUME = TU_BIT(6), PORTSC1_SUSPEND = TU_BIT(7), + PORTSC1_PORT_RESET = TU_BIT(8), // read-only in device mode: a reset is being driven PORTSC1_FORCE_FULL_SPEED = TU_BIT(24), PORTSC1_PORT_SPEED = TU_BIT(26) | TU_BIT(27) }; +// PORTSC1 PSPD field values, once shifted down by PORTSC1_PORT_SPEED_POS. 3 is undefined. +enum { + PORTSC1_PORT_SPEED_FULL = 0, + PORTSC1_PORT_SPEED_LOW = 1, + PORTSC1_PORT_SPEED_HIGH = 2, +}; + // OTGSC enum { OTGSC_VBUS_DISCHARGE = TU_BIT(0), @@ -90,11 +87,18 @@ enum { USBMODE_VBUS_POWER_SELECT = TU_BIT(5), // Need to be enabled for LPC18XX/43XX in host mode }; +// SBUSCFG +enum { + SBUSCFG_AHBBRST_INCR16_UNSPEC = 7, // INCR16 burst, remainder as unspecified-length bursts +}; + // Device Registers typedef struct { //------------- ID + HW Parameter Registers-------------// - volatile uint32_t TU_RESERVED[64]; ///< For iMX RT10xx, but not used by LPC18XX/LPC43XX + volatile uint32_t TU_RESERVED[36]; ///< ID/HW parameter registers, not used by this driver + volatile uint32_t SBUSCFG; ///< System Bus Interface Configuration (not present on every MCU) + volatile uint32_t TU_RESERVED[27]; //------------- Capability Registers-------------// volatile uint8_t CAPLENGTH; ///< Capability Registers Length diff --git a/src/portable/chipidea/ci_hs/dcd_ci_hs.c b/src/portable/chipidea/ci_hs/dcd_ci_hs.c index 9ed75ffd9..f1c333280 100644 --- a/src/portable/chipidea/ci_hs/dcd_ci_hs.c +++ b/src/portable/chipidea/ci_hs/dcd_ci_hs.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -173,6 +154,14 @@ TU_VERIFY_STATIC(sizeof(dcd_qhd_t) == 64, "size is not correct"); #define QTD_NEXT_INVALID 0x01 +// Bounded spin for register waits. The longest legitimate wait is a flush held off by a packet +// already in progress: ~50 us for a full-speed 64-byte packet, a low thousands of dependent +// register reads, so healthy hardware never approaches this bound. Exceeding it means the +// controller has stopped responding, and the spin then only serves to keep an ISR (or an +// IRQ-masked caller) from hanging outright - the 3 ms reset-cleanup window of IMXRT1060RM 42.5.6.2.1 (p.2394) +// is already unreachable in that state, and the manual's remedy there is a controller reset. +#define CI_HS_BUSY_SPIN 10000u + typedef struct { // Must be at 2K alignment // Each endpoint with direction (IN/OUT) occupies a queue head @@ -183,6 +172,17 @@ typedef struct { CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(2048) static dcd_data_t _dcd_data; +// What the next Port Change Detect will be. Each one is preceded by the interrupt that causes it: +// a reset interrupt for the end of a bus reset - where the speed first becomes final - or a +// suspend interrupt for the resume that ends the suspend. A suspend itself raises no port change, +// which is why there is no such value here. Indexed by rhport, which is 0 or 1 on every ci_hs +// variant (NOT the controller count: mcx/rw61x map rhport 1 to controller 0). +enum { + PORT_CHANGE_REASON_RESET = 0, + PORT_CHANGE_REASON_RESUME = 1, +}; +static volatile uint8_t _port_change_reason[2]; + //--------------------------------------------------------------------+ // Prototypes and Helper Functions //--------------------------------------------------------------------+ @@ -191,12 +191,37 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t ci_ep_count(const ci_hs_regs_t *dcd_ return dcd_reg->DCCPARAMS & DCCPARAMS_DEN_MASK; } +static bool controller_reset(uint8_t rhport); + //--------------------------------------------------------------------+ // Controller API //--------------------------------------------------------------------+ -/// follows LPC43xx User Manual 23.10.3 -static void bus_reset(uint8_t rhport) { +// Flush endpoint buffers, following IMXRT1060RM 42.5.6.6.5 Flushing/De-priming an Endpoint +// (p.2413): write ENDPTFLUSH, wait for the controller +// to acknowledge, then confirm ENDPTSTAT went to zero. The controller refuses the flush when a +// packet is in progress, and the manual requires the procedure be repeated until it takes. +// Callers proceed regardless of the result; the bound only prevents an ISR-context hang on dead +// hardware. +static bool flush_endpoints(ci_hs_regs_t *dcd_reg, uint32_t mask) { + uint32_t guard = CI_HS_BUSY_SPIN; + do { + dcd_reg->ENDPTFLUSH = mask; + while (dcd_reg->ENDPTFLUSH & mask) { + if (!guard--) { + return false; + } + } + } while ((dcd_reg->ENDPTSTAT & mask) && guard--); + + return !(dcd_reg->ENDPTSTAT & mask); +} + +/// Everything the manual asks of the DCD when a reset is detected, in its order: clear the setup +/// and completion semaphores, cancel every prime, check the reset is still being driven, and free +/// the dTDs. All of it belongs inside the reset window (IMXRT1060RM 42.5.6.2.1, p.2394); nothing +/// is left for the port change that ends the reset, which only reports the negotiated speed. +static void bus_reset_begin(uint8_t rhport) { ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport); // The reset value for all endpoint types is the control endpoint. If one endpoint @@ -212,17 +237,24 @@ static void bus_reset(uint8_t rhport) { //------------- Clear All Registers -------------// dcd_reg->ENDPTNAK = dcd_reg->ENDPTNAK; dcd_reg->ENDPTNAKEN = 0; - dcd_reg->USBSTS = dcd_reg->USBSTS; dcd_reg->ENDPTSETUPSTAT = dcd_reg->ENDPTSETUPSTAT; dcd_reg->ENDPTCOMPLETE = dcd_reg->ENDPTCOMPLETE; - while (dcd_reg->ENDPTPRIME) {} - dcd_reg->ENDPTFLUSH = 0xFFFFFFFF; - while (dcd_reg->ENDPTFLUSH) {} + uint32_t guard = CI_HS_BUSY_SPIN; + while (dcd_reg->ENDPTPRIME && guard--) {} + dcd_reg->ENDPTFLUSH = 0xFFFFFFFFUL; - // read reset bit in portsc + // All of the above must land while the reset is still being driven - it lasts at least 3 ms. + // Arriving late leaves the controller in an undefined state, and the manual's remedy is to + // hardware-reset it. That clears Run/Stop, so the device detaches and the host will drive a + // fresh reset and enumeration - which is why nothing below this point is worth doing here. + if (!(dcd_reg->PORTSC1 & PORTSC1_PORT_RESET)) { + TU_LOG1("ci_hs: reset cleanup ran past the end of the reset, resetting controller\r\n"); + controller_reset(rhport); + return; // the controller detached; the host's next reset redoes everything below + } - //------------- Queue Head & Queue TD -------------// + //------------- Free all allocated dTDs: the controller will not execute them again -------------// tu_memclr(&_dcd_data, sizeof(dcd_data_t)); //------------- Set up Control Endpoints (0 OUT, 1 IN) -------------// @@ -235,27 +267,29 @@ static void bus_reset(uint8_t rhport) { dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t)); } -bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { - (void)rh_init; - tu_memclr(&_dcd_data, sizeof(dcd_data_t)); - +/// Reset the controller and bring it back up in device mode. Also the manual's remedy when the +/// reset cleanup misses its window: the controller reset clears Run/Stop and detaches the device, +/// so it must be re-initialised completely afterwards (IMXRT1060RM 42.5.6.2.1, p.2394). +static bool controller_reset(uint8_t rhport) { ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport); - TU_ASSERT(ci_ep_count(dcd_reg) <= TUP_DCD_ENDPOINT_MAX); - - #if TU_CHECK_MCU(OPT_MCU_HPM) - usb_phy_init((USB_Type *)dcd_reg, false); - #endif + tu_memclr(&_dcd_data, sizeof(dcd_data_t)); // Reset controller dcd_reg->USBCMD |= USBCMD_RESET; - while (dcd_reg->USBCMD & USBCMD_RESET) {} + uint32_t guard = CI_HS_BUSY_SPIN; + while ((dcd_reg->USBCMD & USBCMD_RESET) && guard--) {} + TU_VERIFY(!(dcd_reg->USBCMD & USBCMD_RESET)); // reached from the ISR too, so never halt here // Set mode to device, must be set immediately after reset uint32_t usbmode = dcd_reg->USBMODE & ~USBMOD_CM_MASK; usbmode |= USBMODE_CM_DEVICE; dcd_reg->USBMODE = usbmode; + #ifdef CI_HS_SET_AHB_BURST + CI_HS_SET_AHB_BURST(rhport); + #endif + #ifdef CFG_TUD_CI_HS_VBUS_CHARGE dcd_reg->OTGSC = OTGSC_VBUS_CHARGE | OTGSC_OTG_TERMINATION; #else @@ -272,9 +306,11 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t)); + _port_change_reason[rhport] = PORT_CHANGE_REASON_RESET; + dcd_reg->ENDPTLISTADDR = (uint32_t)_dcd_data.qhd; // Endpoint List Address has to be 2K alignment dcd_reg->USBSTS = dcd_reg->USBSTS; - dcd_reg->USBINTR = INTR_USB | INTR_ERROR | INTR_PORT_CHANGE | INTR_SUSPEND; + dcd_reg->USBINTR = INTR_USB | INTR_ERROR | INTR_PORT_CHANGE | INTR_RESET | INTR_SUSPEND; uint32_t usbcmd = dcd_reg->USBCMD; usbcmd &= ~USBCMD_INTR_THRESHOLD_MASK; // Interrupt Threshold Interval = 0 @@ -285,8 +321,22 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { return true; } +bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { + (void)rh_init; + ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport); + + TU_ASSERT(ci_ep_count(dcd_reg) <= TUP_DCD_ENDPOINT_MAX); + + #if TU_CHECK_MCU(OPT_MCU_HPM) + usb_phy_init((USB_Type *)dcd_reg, false); + #endif + + return controller_reset(rhport); +} + bool dcd_deinit(uint8_t rhport) { ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport); + _port_change_reason[rhport] = PORT_CHANGE_REASON_RESET; // disable all interrupt dcd_reg->USBINTR = 0; @@ -295,9 +345,9 @@ bool dcd_deinit(uint8_t rhport) { dcd_reg->USBCMD &= ~USBCMD_RUN_STOP; // flush all endpoints - while (dcd_reg->ENDPTPRIME) {} - dcd_reg->ENDPTFLUSH = 0xFFFFFFFF; - while (dcd_reg->ENDPTFLUSH) {} + uint32_t guard = CI_HS_BUSY_SPIN; + while (dcd_reg->ENDPTPRIME && guard--) {} + flush_endpoints(dcd_reg, 0xFFFFFFFF); return true; } @@ -311,11 +361,18 @@ void dcd_int_disable(uint8_t rhport) { } void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { - // Response with status first before changing device address - dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0, false); + ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport); + const uint32_t prev = dcd_reg->DEVICEADDR & DEVICEADDR_USBADR_MASK; - ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport); - dcd_reg->DEVICEADDR = (dev_addr << 25) | TU_BIT(24); + // IMXRT1060RM 42.7.23 / UM10503 Table 478: stage the address before priming the status stage so + // hardware loads USBADR at the status ACK. Priming first races that ACK against this write. + dcd_reg->DEVICEADDR = ((uint32_t)dev_addr << DEVICEADDR_USBADR_POS) | DEVICEADDR_USBADRA; + + if (!dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0, false)) { + // USB 2.0 9.4.6: the address changes only after the status stage completes successfully. The + // status never went out, so drop the stage - USBADRA=0 takes effect instantly. + dcd_reg->DEVICEADDR = prev; + } } void dcd_remote_wakeup(uint8_t rhport) { @@ -412,7 +469,8 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport); dcd_reg->ENDPTCTRL[epnum] |= ENDPTCTRL_STALL << (dir ? 16 : 0); - // flush to abort any primed buffer + // flush to abort any primed buffer; the aborted transfer's dQH overlay can be left + // ACTIVE with mid-transfer state - qhd_start_xfer clears it before the next prime dcd_reg->ENDPTFLUSH = TU_BIT(epnum + (dir ? 16 : 0)); } @@ -482,9 +540,7 @@ bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) // dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t)); // Flush EP - const uint32_t flush_mask = TU_BIT(epnum + (dir ? 16 : 0)); - dcd_reg->ENDPTFLUSH = flush_mask; - while (dcd_reg->ENDPTFLUSH & flush_mask) {} + flush_endpoints(dcd_reg, TU_BIT(epnum + (dir ? 16 : 0))); // disable to change max packet size ep_ctrl_clear(endptctrl, dir, ENDPTCTRL_ENABLE); @@ -510,25 +566,35 @@ void dcd_edpt_close_all(uint8_t rhport) { } } -static void qhd_start_xfer(uint8_t rhport, uint8_t epnum, uint8_t dir) { +static bool qhd_start_xfer(uint8_t rhport, uint8_t epnum, uint8_t dir) { ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport); dcd_qhd_t *p_qhd = &_dcd_data.qhd[epnum][dir]; dcd_qtd_t *p_qtd = &_dcd_data.qtd[epnum][dir]; p_qhd->qtd_overlay.halted = false; // clear any previous error + p_qhd->qtd_overlay.active = false; // a flushed prime leaves stale ACTIVE state; clear it so the fresh qtd loads p_qhd->qtd_overlay.next = (uint32_t)p_qtd; // link qtd to qhd // flush cache dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t)); if (epnum == 0) { - // follows UM 24.10.8.1.1 Setup packet handling using setup lockout mechanism - // wait until ENDPTSETUPSTAT before priming data/status in response TODO add time out - while (dcd_reg->ENDPTSETUPSTAT & TU_BIT(0)) {} + // Setup lockout (IMXRT1060RM 42.5.6.4.2.1 Setup Phase, p.2403): never prime EP0 while a new + // SETUP is pending. The ISR + // normally consumes ENDPTSETUPSTAT quickly; if the guard trips, fail the transfer so usbd + // releases the endpoint (a pending SETUP supersedes this response anyway; without one, usbd + // stalls EP0 and the host recovers with a fresh control transfer). + uint32_t guard = CI_HS_BUSY_SPIN; + while (dcd_reg->ENDPTSETUPSTAT & TU_BIT(0)) { + if (!guard--) { + return false; + } + } } // start transfer dcd_reg->ENDPTPRIME = TU_BIT(epnum + (dir ? 16 : 0)); + return true; } bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes, bool is_isr) { @@ -544,9 +610,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to // Start qhd transfer p_qhd->ff = NULL; - qhd_start_xfer(rhport, epnum, dir); - - return true; + return qhd_start_xfer(rhport, epnum, dir); } #if !CFG_TUD_MEM_DCACHE_ENABLE @@ -597,9 +661,7 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t // Start qhd transfer p_qhd->ff = ff; - qhd_start_xfer(rhport, epnum, dir); - - return true; + return qhd_start_xfer(rhport, epnum, dir); } #endif @@ -647,43 +709,43 @@ void dcd_int_handler(uint8_t rhport) { return; } - // Set if the port controller enters the full or high-speed operational state. - // either from Bus Reset or Suspended state - if (int_status & INTR_PORT_CHANGE) { - // TU_LOG2("PortChange %08lx\r\n", dcd_reg->PORTSC1); - - // Reset interrupt is not enabled, we manually check if Port Change is due - // to connection / disconnection - if (dcd_reg->USBSTS & INTR_RESET) { - dcd_reg->USBSTS = INTR_RESET; + const uint8_t pci_reason = _port_change_reason[rhport]; // save current pci_reason - if (dcd_reg->PORTSC1 & PORTSC1_CURRENT_CONNECT_STATUS) { - const uint32_t speed = (dcd_reg->PORTSC1 & PORTSC1_PORT_SPEED) >> PORTSC1_PORT_SPEED_POS; - bus_reset(rhport); - dcd_event_bus_reset(rhport, (tusb_speed_t)speed, true); - } else { - dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true); - } - } else { - // Triggered by resuming from suspended state - if (!(dcd_reg->PORTSC1 & PORTSC1_SUSPEND)) { - dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true); - } - } + if (int_status & INTR_SUSPEND) { + _port_change_reason[rhport] = PORT_CHANGE_REASON_RESUME; // next PCI is resume + dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true); } - if (int_status & INTR_SUSPEND) { - // TU_LOG2("Suspend %08lx\r\n", dcd_reg->PORTSC1); + // USB Reset Received: register cleanup runs here within the reset window (IMXRT1060RM 42.5.6.2.1, p.2394) + // and BUS_RESET_START fires now; BUS_RESET_END, with the final speed, is triggered later by PCI. + if (int_status & INTR_RESET) { + _port_change_reason[rhport] = PORT_CHANGE_REASON_RESET; + bus_reset_begin(rhport); + dcd_event_bus_signal(rhport, DCD_EVENT_BUS_RESET_START, true); + } - if (dcd_reg->PORTSC1 & PORTSC1_SUSPEND) { - // Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration. - // Skip suspend event if we are not addressed - if ((dcd_reg->DEVICEADDR >> 25) & 0x0f) { - dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true); - } + // Port entered the full/high-speed operational state: the end of a bus reset, or a resume. + if (int_status & INTR_PORT_CHANGE) { + if (pci_reason == PORT_CHANGE_REASON_RESUME) { + dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true); + } else { + // the undefined encoding falls back to full speed + const uint32_t pspd = (dcd_reg->PORTSC1 & PORTSC1_PORT_SPEED) >> PORTSC1_PORT_SPEED_POS; + const tusb_speed_t speed = (pspd == PORTSC1_PORT_SPEED_LOW) ? TUSB_SPEED_LOW : + (pspd == PORTSC1_PORT_SPEED_HIGH) ? TUSB_SPEED_HIGH : TUSB_SPEED_FULL; + dcd_event_bus_reset(rhport, speed, true); + // This reset is over, so the next port change is a resume. Leaving it at RESET instead would + // dispatch every later resume as another end-of-reset, clearing the queue heads mid-session. + _port_change_reason[rhport] = PORT_CHANGE_REASON_RESUME; } } + // No unplug detection yet, by the manual rather than by omission: IMXRT1060RM 42.7.31 (p.2470) says a zero + // Current Connect Status means the device "did not attach successfully or was forcibly + // disconnected by the software writing a zero to the Run bit ... It does not state the device + // being disconnected or suspended", so a cable pull raises no port change at all. VBUS via + // OTGSC BSV is the manual's disconnect indicator, and it is board dependent. + if (int_status & INTR_USB) { // Make sure we read the latest version of _dcd_data. dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t)); @@ -691,7 +753,7 @@ void dcd_int_handler(uint8_t rhport) { const uint32_t edpt_complete = dcd_reg->ENDPTCOMPLETE; dcd_reg->ENDPTCOMPLETE = edpt_complete; // acknowledge - // 23.10.12.3 Failed QTD also get ENDPTCOMPLETE set + // 42.5.6.6.4 Transfer Completion (p.2413): a failed dTD also sets ENDPTCOMPLETE // nothing to do, we will submit xfer as error to usbd // if (int_status & INTR_ERROR) { } @@ -707,12 +769,39 @@ void dcd_int_handler(uint8_t rhport) { } // Set up Received - // 23.10.10.2 Operational model for setup transfers + // 42.5.6.4.2 Control Endpoint Operation Model (p.2403) // Must be after normal transfer complete since it is possible to have both previous control status + new setup // in the same frame and we should handle previous status first. if (dcd_reg->ENDPTSETUPSTAT) { + // 42.5.6.4.2.1 Setup Phase (p.2403) steps 1-2: duplicate the setup payload BEFORE clearing + // ENDPTSETUPSTAT - + // the clear releases the setup lockout and a back-to-back SETUP (usbtest case 10) can + // overwrite the queue-head buffer immediately after. The copy is read through the volatile + // qualifier rather than memcpy'd because C orders volatile accesses only against each + // other: a plain copy may legally be sunk past the lockout-releasing store below. + union { + tusb_control_request_t request; + uint8_t byte[8]; + } setup; + const volatile uint8_t *setup_src = (const volatile uint8_t *)&_dcd_data.qhd[0][0].setup_request; + for (uint8_t i = 0; i < sizeof(setup.request); i++) { + setup.byte[i] = setup_src[i]; + } dcd_reg->ENDPTSETUPSTAT = dcd_reg->ENDPTSETUPSTAT; - dcd_event_setup_received(rhport, (uint8_t *)(uintptr_t)&_dcd_data.qhd[0][0].setup_request, true); + + // Retire a status/handshake phase left primed by the previous control sequence + // (IMXRT1060RM 42.5.6.4.2.1, p.2403), which would otherwise retire the response the task is about to + // prime for this setup. Skipped when EP0 has nothing primed or priming, since the manual + // does not want the flush wait in an interrupt handler when it has nothing to do. + // One volatile read per statement: C leaves their order unspecified within a single + // expression, which IAR rejects outright (Pa082). + const uint32_t ep0_mask = TU_BIT(0) | TU_BIT(16); + const uint32_t ep0_stat = dcd_reg->ENDPTSTAT; + const uint32_t ep0_prime = dcd_reg->ENDPTPRIME; + if ((ep0_stat | ep0_prime) & ep0_mask) { + flush_endpoints(dcd_reg, ep0_mask); + } + dcd_event_setup_received(rhport, setup.byte, true); } } diff --git a/src/portable/chipidea/ci_hs/hcd_ci_hs.c b/src/portable/chipidea/ci_hs/hcd_ci_hs.c index c0d14fe57..0f24f5bb6 100644 --- a/src/portable/chipidea/ci_hs/hcd_ci_hs.c +++ b/src/portable/chipidea/ci_hs/hcd_ci_hs.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -101,6 +82,10 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { hcd_reg->USBMODE = USBMODE_CM_HOST; #endif + #ifdef CI_HS_SET_AHB_BURST + CI_HS_SET_AHB_BURST(rhport); + #endif + #if !TUH_OPT_HIGH_SPEED hcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED; #endif diff --git a/src/portable/dialog/da146xx/dcd_da146xx.c b/src/portable/dialog/da146xx/dcd_da146xx.c index 7d90b1f94..dc662857e 100644 --- a/src/portable/dialog/da146xx/dcd_da146xx.c +++ b/src/portable/dialog/da146xx/dcd_da146xx.c @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2020 Jerzy Kasenberg - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2020 Jerzy Kasenberg + * SPDX-FileCopyrightText: Copyright (c) 2020 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/ehci/ehci.c b/src/portable/ehci/ehci.c index 03c3b91fd..660c38d8f 100644 --- a/src/portable/ehci/ehci.c +++ b/src/portable/ehci/ehci.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/ehci/ehci.h b/src/portable/ehci/ehci.h index 719bdeafc..9d86ed04f 100644 --- a/src/portable/ehci/ehci.h +++ b/src/portable/ehci/ehci.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/ehci/ehci_api.h b/src/portable/ehci/ehci_api.h index e9018639f..6e3ddfb66 100644 --- a/src/portable/ehci/ehci_api.h +++ b/src/portable/ehci/ehci_api.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021, Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021, Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/mentor/musb/dcd_musb.c b/src/portable/mentor/musb/dcd_musb.c index 1d1280bf4..92c9fe92e 100644 --- a/src/portable/mentor/musb/dcd_musb.c +++ b/src/portable/mentor/musb/dcd_musb.c @@ -1,26 +1,8 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021 Koji KITAYAMA - * Copyright (c) 2024, Brent Kowal (Analog Devices, Inc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021 Koji Kitayama + * SPDX-FileCopyrightText: Copyright (c) 2024, Brent Kowal (Analog Devices, Inc) + * SPDX-FileCopyrightText: Copyright (c) 2021 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -42,6 +24,8 @@ #include "musb_ti.h" #elif defined(TUP_USBIP_MUSB_ADI) #include "musb_max32.h" +#elif defined(TUP_USBIP_MUSB_PY32) + #include "musb_py32.h" #else #error "Unsupported MCU" #endif @@ -63,6 +47,7 @@ typedef struct { }; uint16_t length; /* the number of bytes in the buffer */ uint16_t remaining; /* the number of bytes remaining in the buffer */ + uint16_t mps; /* maximum packet size */ bool armed; /* true while a transfer is posted */ bool use_fifo; /* true: buf is tu_fifo_t*; false: buf is plain byte pointer. */ } pipe_state_t; @@ -177,6 +162,14 @@ TU_ATTR_ALWAYS_INLINE static inline pipe_state_t* pipe_get(uint8_t epnum, tusb_d return &_dcd.pipe[idx]; } +TU_ATTR_ALWAYS_INLINE static inline uint16_t musb_mps_to_maxp(uint16_t mps) { +#if defined(TUP_USBIP_MUSB_PY32) + return (uint8_t) ((mps + 7u) / 8u); +#else + return mps; +#endif +} + //-------------------------------------------------------------------- // HW FIFO Helper // Note: Index register is already set by caller @@ -241,7 +234,12 @@ TU_ATTR_ALWAYS_INLINE static inline bool hwfifo_config(musb_regs_t* musb, unsign bool double_packet) { (void) mps; - #if defined(TUP_USBIP_MUSB_ADI) + #if defined(TUP_USBIP_MUSB_PY32) + (void) musb; (void) is_rx; (void) double_packet; + // Puya FIFO sizes: EP0 = 64 B, EP1 = 512 B, EP2..4 = 128 B, EP5 = 64 B, shared between IN and OUT. + static const uint16_t py32_fifo_size[] = { 64, 512, 128, 128, 128, 64 }; + return epnum < TU_ARRAY_SIZE(py32_fifo_size) && mps <= py32_fifo_size[epnum]; + #elif defined(TUP_USBIP_MUSB_ADI) // AnalogDevice FIFO sizes: EP1..7 = 512 B, EP8..9 = 2048 B, EP10..11 = 4096 B. // DPB requires FIFO >= 2 * MPS. For HS bulk (MPS=512) only EP >= 8 qualifies. // Force single-buffered on EP < 8 even if the caller requested DPB. @@ -284,7 +282,7 @@ TU_ATTR_ALWAYS_INLINE static inline void hwfifo_flush(musb_regs_t* musb, unsigne // write to txfifo using pipe_state_t info static void pipe_write(musb_regs_t* musb_regs, pipe_state_t* pipe, uint8_t epnum) { musb_ep_csr_t* ep_csr = &musb_regs->indexed_csr; - const uint16_t mps = ep_csr->tx_maxp & MUSB_TXMAXP_PACKET_SIZE_M; + const uint16_t mps = pipe->mps; const uint16_t xact_len = tu_min16(mps, pipe->remaining); volatile void *hwfifo = &musb_regs->fifo[epnum]; if (xact_len) { @@ -310,6 +308,12 @@ static void process_epin_isr(uint8_t rhport, musb_regs_t *musb_regs, uint8_t epn } pipe_state_t* pipe = pipe_get(epnum, TUSB_DIR_IN); + // No active transfer: a halt/abort disarmed the pipe (armed=false) but may leave remaining>0. + // Do not keep loading the aborted transfer — that would re-fill the just-flushed FIFO and the + // next (re-armed) transfer's data would stack on top (host sees an oversized packet -> babble). + if (!pipe->armed) { + return; + } if (pipe->remaining > 0) { pipe_write(musb_regs, pipe, epnum); } else { @@ -332,7 +336,7 @@ static void process_epin_isr(uint8_t rhport, musb_regs_t *musb_regs, uint8_t epn // release the FIFO slot by clearing RXRDY. return true if short packet static bool pipe_read(musb_regs_t* musb_regs, pipe_state_t* pipe, uint8_t epnum) { musb_ep_csr_t* ep_csr = &musb_regs->indexed_csr; // index already set in process_epout_isr() - const uint16_t mps = ep_csr->rx_maxp & MUSB_RXMAXP_PACKET_SIZE_M; + const uint16_t mps = pipe->mps; const uint16_t rx_count = ep_csr->rx_count; const uint16_t xact_len = tu_min16(tu_min16(pipe->remaining, mps), rx_count); volatile void *hwfifo = &musb_regs->fifo[epnum]; @@ -644,7 +648,11 @@ static void process_bus_reset_isr(uint8_t rhport) { hwfifo_reset(musb, i, 0); hwfifo_reset(musb, i, 1); } +#if defined(TUP_USBIP_MUSB_PY32) + dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true); +#else dcd_event_bus_reset(rhport, (musb->power & MUSB_POWER_HSMODE) ? TUSB_SPEED_HIGH : TUSB_SPEED_FULL, true); +#endif } /*------------------------------------------------------------------ @@ -653,6 +661,11 @@ static void process_bus_reset_isr(uint8_t rhport) { #if CFG_TUSB_DEBUG >= MUSB_DEBUG static void print_musb_info(musb_regs_t* musb_regs) { +#if defined(TUP_USBIP_MUSB_PY32) + (void) musb_regs; + // musb discovery fields not present + TU_LOG1("musb py32 fixed full-speed configuration\r\n"); +#else // print version, epinfo, raminfo, config_data0, fifo_size TU_LOG1("musb version = %u.%u\r\n", musb_regs->hwvers_bit.major, musb_regs->hwvers_bit.minor); TU_LOG1("Number of endpoints: %u TX, %u RX\r\n", musb_regs->epinfo_bit.tx_ep_num, musb_regs->epinfo_bit.rx_ep_num); @@ -669,6 +682,7 @@ static void print_musb_info(musb_regs_t* musb_regs) { TU_LOG1("FIFO %u Size: TX %u RX %u\r\n", i, musb_regs->indexed_csr.fifo_size_bit.tx, musb_regs->indexed_csr.fifo_size_bit.rx); } #endif +#endif } #endif @@ -724,6 +738,18 @@ void dcd_remote_wakeup(uint8_t rhport) { musb_regs->power &= ~MUSB_POWER_RESUME; } +#if defined(TUP_USBIP_MUSB_PY32) +void dcd_connect(uint8_t rhport) +{ + (void) rhport; +} + +void dcd_disconnect(uint8_t rhport) +{ + (void) rhport; +} +#else + // Connect by enabling internal pull-up resistor on D+/D- void dcd_connect(uint8_t rhport) { @@ -739,6 +765,8 @@ void dcd_disconnect(uint8_t rhport) musb_regs->power &= ~MUSB_POWER_SOFTCONN; } +#endif + void dcd_sof_enable(uint8_t rhport, bool en) { (void) rhport; @@ -762,6 +790,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) { pipe->buf = NULL; pipe->length = 0; pipe->remaining = 0; + pipe->mps = (uint16_t) mps; pipe->armed = false; musb_regs_t* musb = MUSB_REGS(rhport); @@ -769,7 +798,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) { const uint8_t is_rx = (1 - epdir); musb_ep_maxp_csr_t* maxp_csr = &ep_csr->maxp_csr[is_rx]; - maxp_csr->maxp = mps; + maxp_csr->maxp = musb_mps_to_maxp((uint16_t) mps); maxp_csr->csrh = 0; #if MUSB_CFG_SHARED_FIFO if (epdir) { @@ -780,7 +809,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) { hwfifo_flush(musb, epn, is_rx, true); TU_ASSERT(hwfifo_config(musb, epn, is_rx, mps, ep_desc->bmAttributes.xfer == TUSB_XFER_BULK)); - musb->intren_ep[is_rx] |= TU_BIT(epn); + musb->intren_ep[is_rx ^ MUSB_INTR_EP_TX_RX_SWAP] |= TU_BIT(epn); return true; } @@ -791,8 +820,11 @@ bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet musb_regs_t* musb = MUSB_REGS(rhport); musb_ep_csr_t* ep_csr = get_ep_csr(musb, epn); const uint8_t is_rx = 1 - dir_in; + pipe_state_t *pipe = pipe_get(epn, dir_in); + pipe->mps = largest_packet_size; ep_csr->maxp_csr[is_rx].csrh = 0; - return hwfifo_config(musb, epn, is_rx, largest_packet_size, true); + TU_ASSERT(hwfifo_config(musb, epn, is_rx, largest_packet_size, true)); + return true; } bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *ep_desc ) { @@ -808,6 +840,7 @@ bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *ep_desc ) pipe->buf = NULL; pipe->length = 0; pipe->remaining = 0; + pipe->mps = (uint16_t) mps; pipe->armed = false; musb_regs_t* musb = MUSB_REGS(rhport); @@ -815,7 +848,7 @@ bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *ep_desc ) const uint8_t is_rx = 1 - dir_in; musb_ep_maxp_csr_t* maxp_csr = &ep_csr->maxp_csr[is_rx]; - maxp_csr->maxp = mps; + maxp_csr->maxp = musb_mps_to_maxp((uint16_t) mps); maxp_csr->csrh |= MUSB_CSRH_ISO; #if MUSB_CFG_SHARED_FIFO if (dir_in) { @@ -830,7 +863,7 @@ bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *ep_desc ) musb->fifo_size[is_rx] = hwfifo_byte2size(mps) | MUSB_FIFOSZ_DOUBLE_PACKET; #endif - musb->intren_ep[is_rx] |= TU_BIT(epn); + musb->intren_ep[is_rx ^ MUSB_INTR_EP_TX_RX_SWAP] |= TU_BIT(epn); if (ie) musb_dcd_int_enable(rhport); @@ -851,7 +884,7 @@ void dcd_edpt_close_all(uint8_t rhport) musb_ep_maxp_csr_t* maxp_csr = &ep_csr->maxp_csr[d]; hwfifo_flush(musb, i, d, true); hwfifo_reset(musb, i, d); - maxp_csr->maxp = 0; + maxp_csr->maxp = musb_mps_to_maxp(0); maxp_csr->csrh = 0; } } @@ -928,6 +961,10 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { } else { const tusb_dir_t ep_dir = tu_edpt_dir(ep_addr); const uint8_t is_rx = (ep_dir == TUSB_DIR_OUT ? 1u : 0u); + // A halt aborts the transfer: flush staged FIFO packet(s) before stalling, else leftover TX data + // concatenates with the next transfer after un-halt -> host sees an oversized packet (babble). + // FLUSH must precede SEND_STALL, which clears the TXRDY that hwfifo_flush() gates on. + hwfifo_flush(musb_regs, epn, is_rx, false); ep_csr->maxp_csr[is_rx].csrl = MUSB_CSRL_SEND_STALL(is_rx); pipe_state_t* pipe = pipe_get(epn, ep_dir); pipe->armed = false; diff --git a/src/portable/mentor/musb/hcd_musb.c b/src/portable/mentor/musb/hcd_musb.c index dcc023e0b..6a1601963 100644 --- a/src/portable/mentor/musb/hcd_musb.c +++ b/src/portable/mentor/musb/hcd_musb.c @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021 Koji KITAYAMA - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021 Koji Kitayama + * SPDX-FileCopyrightText: Copyright (c) 2021 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/mentor/musb/musb_max32.h b/src/portable/mentor/musb/musb_max32.h index 134b47122..9cf99126e 100644 --- a/src/portable/mentor/musb/musb_max32.h +++ b/src/portable/mentor/musb/musb_max32.h @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2024, Brent Kowal (Analog Devices, Inc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2024, Brent Kowal (Analog Devices, Inc) + * SPDX-FileCopyrightText: Copyright (c) 2024 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -46,6 +28,7 @@ extern "C" { #define MUSB_CFG_SHARED_FIFO 1 // shared FIFO for TX and RX endpoints #define MUSB_CFG_DYNAMIC_FIFO 0 // dynamic EP FIFO sizing +#define MUSB_INTR_EP_TX_RX_SWAP 0 static const uintptr_t MUSB_BASES[] = { MXC_BASE_USBHS }; diff --git a/src/portable/mentor/musb/musb_py32.h b/src/portable/mentor/musb/musb_py32.h new file mode 100644 index 000000000..68d58ccb8 --- /dev/null +++ b/src/portable/mentor/musb/musb_py32.h @@ -0,0 +1,79 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2026, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef TUSB_MUSB_PY32_H_ +#define TUSB_MUSB_PY32_H_ + +#include "py32f0xx.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// PY32 does not expose generic MUSB shared FIFO allocation registers; this +// selects the existing TX_MODE path required for IN endpoints. +#define MUSB_CFG_SHARED_FIFO 1 +#define MUSB_CFG_DYNAMIC_FIFO 0 +#define MUSB_INTR_EP_TX_RX_SWAP 1 + +static const uintptr_t MUSB_BASES[] = { USBD_BASE }; +static const IRQn_Type musb_irqs[] = { USB_IRQn }; + +TU_ATTR_ALWAYS_INLINE static inline void musb_dcd_phy_init(uint8_t rhport) { + musb_regs_t* musb_regs = MUSB_REGS(rhport); + + musb_regs->index = 0; + musb_regs->faddr = 0; + musb_regs->intr_usben = MUSB_IE_RESET | MUSB_IE_RESUME | MUSB_IE_SUSPND; + musb_regs->intr_txen = TU_BIT(0); + musb_regs->intr_rxen = 0; +} + +TU_ATTR_ALWAYS_INLINE static inline void musb_dcd_int_enable(uint8_t rhport) { + NVIC_EnableIRQ(musb_irqs[rhport]); +} + +TU_ATTR_ALWAYS_INLINE static inline void musb_dcd_int_disable(uint8_t rhport) { + NVIC_DisableIRQ(musb_irqs[rhport]); +} + +TU_ATTR_ALWAYS_INLINE static inline void musb_dcd_int_clear(uint8_t rhport) { + NVIC_ClearPendingIRQ(musb_irqs[rhport]); +} + +TU_ATTR_ALWAYS_INLINE static inline unsigned musb_dcd_get_int_enable(uint8_t rhport) { + return NVIC_GetEnableIRQ(musb_irqs[rhport]); +} + +TU_ATTR_ALWAYS_INLINE static inline void musb_dcd_int_handler_enter(uint8_t rhport) { + (void) rhport; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/portable/mentor/musb/musb_ti.h b/src/portable/mentor/musb/musb_ti.h index deaea8017..1cf26b1cb 100644 --- a/src/portable/mentor/musb/musb_ti.h +++ b/src/portable/mentor/musb/musb_ti.h @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2024, Brent Kowal (Analog Devices, Inc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2024, Brent Kowal (Analog Devices, Inc) + * SPDX-FileCopyrightText: Copyright (c) 2024 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -48,6 +30,7 @@ #define MUSB_CFG_SHARED_FIFO 0 #define MUSB_CFG_DYNAMIC_FIFO 1 #define MUSB_CFG_DYNAMIC_FIFO_SIZE 4096 +#define MUSB_INTR_EP_TX_RX_SWAP 0 static const uintptr_t MUSB_BASES[] = { USB0_BASE }; diff --git a/src/portable/mentor/musb/musb_type.h b/src/portable/mentor/musb/musb_type.h index 3d3c3c834..1e8a761c0 100644 --- a/src/portable/mentor/musb/musb_type.h +++ b/src/portable/mentor/musb/musb_type.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -83,6 +64,75 @@ #define __R volatile const #endif +#if defined(TUP_USBIP_MUSB_PY32) + +typedef struct TU_ATTR_PACKED { + __IO uint8_t csrh; // 0x04, 0x08: CSRH + __IO uint8_t csrl; // 0x05, 0x09: CSRL + __IO uint8_t maxp; // 0x06, 0x0A: MAXP + __I uint8_t reserved; +} musb_ep_maxp_csr_t; + +TU_VERIFY_STATIC(sizeof(musb_ep_maxp_csr_t) == 4, "size is not correct"); + +typedef struct TU_ATTR_PACKED { + __IO uint8_t csr0l; // 0x00: CSR0 + __IO uint8_t count0; // 0x01: COUNT0 + __I uint8_t reserved_0x02[2]; + + union { + struct { + __IO uint8_t tx_csrh; // 0x04: TX CSRH + __IO uint8_t tx_csrl; // 0x05: TX CSRL + __IO uint8_t tx_maxp; // 0x06: TX MAXP + __I uint8_t reserved_0x07; + + __IO uint8_t rx_csrh; // 0x08: RX CSRH + __IO uint8_t rx_csrl; // 0x09: RX CSRL + __IO uint8_t rx_maxp; // 0x0A: RX MAXP + __I uint8_t reserved_0x0b; + }; + + musb_ep_maxp_csr_t maxp_csr[2]; + }; + + __IO uint16_t rx_count; // 0x0C: RX COUNT + __I uint8_t reserved_0x0e[2]; +} musb_ep_csr_t; + +TU_VERIFY_STATIC(sizeof(musb_ep_csr_t) == 16, "size is not correct"); + +typedef struct TU_ATTR_PACKED { + __IO uint8_t faddr; // 0x00: FADDR + __IO uint8_t power; // 0x01: POWER + __I uint8_t reserved_0x02[2]; + + __IO uint8_t intr_usb; // 0x04: INTRUSB + __IO uint8_t intr_rx; // 0x05: INTRRX + __IO uint8_t intr_tx; // 0x06: INTRTX + __I uint8_t reserved_0x07; + + __IO uint8_t intr_usben; // 0x08: INTRUSBEN + union { + struct { + __IO uint8_t intr_rxen; // 0x09: INTRRXEN + __IO uint8_t intr_txen; // 0x0A: INTRTXEN + }; + + __IO uint8_t intren_ep[2]; // 0x09-0x0A: RX, TX + }; + __I uint8_t reserved_0x0b; + + __IO uint16_t frame; // 0x0C: FRAME + __IO uint8_t index; // 0x0E: INDEX + __I uint8_t reserved_0x0f; + + musb_ep_csr_t indexed_csr; // 0x10-0x1F: Indexed CSR + __IO uint32_t fifo[16]; // 0x20-0x5F: FIFO 0-15 +} musb_regs_t; + +#else + typedef struct TU_ATTR_PACKED { __IO uint16_t maxp; // 0x00, 0x04: MAXP __IO uint8_t csrl; // 0x02, 0x06: CSRL @@ -296,6 +346,8 @@ typedef struct { TU_VERIFY_STATIC(sizeof(musb_regs_t) == 0x350, "size is not correct"); +#endif + //--------------------------------------------------------------------+ // Helper //--------------------------------------------------------------------+ diff --git a/src/portable/microchip/pic/dcd_pic.c b/src/portable/microchip/pic/dcd_pic.c index fedede8ab..7e490905c 100644 --- a/src/portable/microchip/pic/dcd_pic.c +++ b/src/portable/microchip/pic/dcd_pic.c @@ -1,31 +1,14 @@ /* - * The MIT License (MIT) + * SPDX-FileCopyrightText: Copyright (c) 2022 SudoMaker, Ltd. + * SPDX-FileCopyrightText: Copyright (c) 2020 Koji Kitayama + * SPDX-FileCopyrightText: Copyright (c) 2022 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * - * Copyright (c) 2022-2024 SudoMaker, Ltd. - * Author: Mike Yang (Reimu NotMoe) <[email protected]> + * This file is part of the TinyUSB stack. * + * Author: Mike Yang (Reimu NotMoe) <[email protected]> * Based on usb_device.c - Copyright (c) 2015 Microchip Technology Inc. * Based on dcd_khci.c - Copyright (c) 2020 Koji Kitayama - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. */ #include "tusb_option.h" diff --git a/src/portable/microchip/pic32mz/dcd_pic32mz.c b/src/portable/microchip/pic32mz/dcd_pic32mz.c index 94ecf1455..1fb5d08ad 100644 --- a/src/portable/microchip/pic32mz/dcd_pic32mz.c +++ b/src/portable/microchip/pic32mz/dcd_pic32mz.c @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2022 Jerzy Kasenberg - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2022 Jerzy Kasenberg + * SPDX-FileCopyrightText: Copyright (c) 2022 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/microchip/samd/dcd_samd.c b/src/portable/microchip/samd/dcd_samd.c index cdfb00e3c..54ef34c8e 100644 --- a/src/portable/microchip/samd/dcd_samd.c +++ b/src/portable/microchip/samd/dcd_samd.c @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2018 Scott Shawcroft for Adafruit Industries + * SPDX-FileCopyrightText: Copyright (c) 2018 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -247,15 +229,49 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { (void) rhport; - (void) ep_addr; - (void)largest_packet_size; - return false; + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + // Reserve the endpoint bank with the largest packet size (persists across altsettings). The + // buffer address/count are filled per-transfer in dcd_edpt_xfer; only the SIZE bucket is fixed. + UsbDeviceDescBank* bank = &sram_registers[epnum][dir]; + uint32_t size_value = 0; + while (size_value < 7) { + if (1 << (size_value + 3) >= largest_packet_size) { + break; + } + size_value++; + } + if ( size_value == 7 && largest_packet_size > 1023 ) return false; + + bank->PCKSIZE.bit.SIZE = size_value; + return true; } bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { (void)rhport; - (void)desc_ep; - return false; + uint8_t const epnum = tu_edpt_number(desc_ep->bEndpointAddress); + uint8_t const dir = tu_edpt_dir(desc_ep->bEndpointAddress); + + // Configure and enable the ISO endpoint on altsetting selection (bank SIZE already reserved by + // dcd_edpt_iso_alloc). Mirrors the per-direction setup in dcd_edpt_open(), plus a bank scrub: + // under ISO_ALLOC the EP is never disabled on alt0 (usbd_edpt_close is a no-op), so the bank-ready + // state from the previous streaming session survives into re-activation. Leave the EP un-armed so + // a stale bank can't move a packet before dcd_edpt_xfer re-arms it (a leftover BK1RDY with a stale + // BYTE_COUNT would otherwise babble on the first IN token after re-selecting alt1). + UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum]; + if ( dir == TUSB_DIR_OUT ) { + ep->EPCFG.bit.EPTYPE0 = desc_ep->bmAttributes.xfer + 1; + ep->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ0 | USB_DEVICE_EPSTATUSCLR_DTGLOUT; + ep->EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_BK0RDY; // OUT: not ready to receive until armed + ep->EPINTENSET.bit.TRCPT0 = true; + } else { + ep->EPCFG.bit.EPTYPE1 = desc_ep->bmAttributes.xfer + 1; + ep->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ1 | USB_DEVICE_EPSTATUSCLR_DTGLIN | + USB_DEVICE_EPSTATUSCLR_BK1RDY; // IN: clear stale "loaded" bank + ep->EPINTENSET.bit.TRCPT1 = true; + } + return true; } void dcd_edpt_close_all (uint8_t rhport) diff --git a/src/portable/microchip/samd/hcd_samd.c b/src/portable/microchip/samd/hcd_samd.c index 0de7ddeb6..8636200dd 100644 --- a/src/portable/microchip/samd/hcd_samd.c +++ b/src/portable/microchip/samd/hcd_samd.c @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2024 ChrisDeadman - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2024 ChrisDeadman + * SPDX-FileCopyrightText: Copyright (c) 2024 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/microchip/samg/dcd_samg.c b/src/portable/microchip/samg/dcd_samg.c index f8980b775..c4fb28cac 100644 --- a/src/portable/microchip/samg/dcd_samg.c +++ b/src/portable/microchip/samg/dcd_samg.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2018, hathach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2018, Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/microchip/samx7x/dcd_samx7x.c b/src/portable/microchip/samx7x/dcd_samx7x.c index 6da1e9778..ea6492ad4 100644 --- a/src/portable/microchip/samx7x/dcd_samx7x.c +++ b/src/portable/microchip/samx7x/dcd_samx7x.c @@ -1,26 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2018, hathach (tinyusb.org) - * Copyright (c) 2021, HiFiPhile - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2018, Ha Thach (tinyusb.org) + * SPDX-FileCopyrightText: Copyright (c) 2021, HiFiPhile (Zixun LI) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/microchip/samx7x/samx7x_common.h b/src/portable/microchip/samx7x/samx7x_common.h index 5e3c20c0f..b34da2c36 100644 --- a/src/portable/microchip/samx7x/samx7x_common.h +++ b/src/portable/microchip/samx7x/samx7x_common.h @@ -1,30 +1,11 @@ /* -* The MIT License (MIT) -* -* Copyright (c) 2019 Microchip Technology Inc. -* Copyright (c) 2018, hathach (tinyusb.org) -* Copyright (c) 2021, HiFiPhile -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -* THE SOFTWARE. -* -* This file is part of the TinyUSB stack. -*/ + * SPDX-FileCopyrightText: Copyright (c) 2019 Microchip Technology Inc. + * SPDX-FileCopyrightText: Copyright (c) 2018, Ha Thach (tinyusb.org) + * SPDX-FileCopyrightText: Copyright (c) 2021, HiFiPhile (Zixun LI) + * SPDX-License-Identifier: MIT + * + * This file is part of the TinyUSB stack. + */ #ifndef _COMMON_USB_REGS_H_ #define _COMMON_USB_REGS_H_ diff --git a/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c b/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c index 6f88e0a24..b40d2a9f5 100644 --- a/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c +++ b/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2020 SE TEAM - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2020 SE TEAM + * SPDX-FileCopyrightText: Copyright (c) 2020 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c index befbaa338..5170e0645 100644 --- a/src/portable/nordic/nrf5x/dcd_nrf5x.c +++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -141,8 +122,22 @@ TU_ATTR_ALWAYS_INLINE static inline bool is_in_isr(void) { return (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) ? true : false; } +// Errata 199 "USBD cannot receive tasks during DMA": while an EasyDMA transfer is in progress the +// controller may drop an incoming SETUP/IN/OUT token (lost event -> stuck EP0, esp. under rapid +// back-to-back control transfers). The workaround latches an undocumented "DMA in progress" test +// register (0x40027C1C) so tokens are held instead. Gated on the anomaly being present (all +// nRF52840 revisions; absent on other nRF52 parts). Mirrors nrfx usbd_dma_pending_set/clear(). +#define NRF_USBD_ERRATA_199_REG (*((volatile uint32_t*) 0x40027C1CUL)) + // helper to start DMA static void start_dma(volatile uint32_t* reg_startep) { + // EP0STATUS / EP0RCVOUT take the EasyDMA slot but do not transfer data, so no ERRATA-199 latch. + const bool no_dma = (reg_startep == &NRF_USBD->TASKS_EP0STATUS) || (reg_startep == &NRF_USBD->TASKS_EP0RCVOUT); + + if (!no_dma && nrf52_errata_199()) { + NRF_USBD_ERRATA_199_REG = 0x00000082UL; + } + (*reg_startep) = 1; __ISB(); __DSB(); @@ -150,7 +145,7 @@ static void start_dma(volatile uint32_t* reg_startep) { // TASKS_EP0STATUS, TASKS_EP0RCVOUT seem to need EasyDMA to be available // However these don't trigger any DMA transfer and got ENDED event subsequently // Therefore dma_pending is corrected right away - if ((reg_startep == &NRF_USBD->TASKS_EP0STATUS) || (reg_startep == &NRF_USBD->TASKS_EP0RCVOUT)) { + if (no_dma) { atomic_flag_clear(&_dcd.dma_running); } } @@ -165,6 +160,10 @@ static void edpt_dma_start(volatile uint32_t* reg_startep) { // DMA is complete static void edpt_dma_end(void) { + // Clear the ERRATA-199 "DMA in progress" latch set in start_dma(). + if (nrf52_errata_199()) { + NRF_USBD_ERRATA_199_REG = 0x00000000UL; + } atomic_flag_clear(&_dcd.dma_running); } @@ -396,58 +395,52 @@ void dcd_edpt_close_all(uint8_t rhport) { dcd_int_enable(rhport); } -void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { - (void) rhport; +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { + (void)rhport; + (void)largest_packet_size; + // nRF ISO endpoints are hardware-fixed to EP8 and use EasyDMA, so there is no packet buffer to + // pre-allocate here; the endpoint is enabled on dcd_edpt_iso_activate(). + TU_ASSERT(tu_edpt_number(ep_addr) == EP_ISO_NUM); + return true; +} +bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { + (void)rhport; + uint8_t const ep_addr = desc_ep->bEndpointAddress; uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); + TU_ASSERT(epnum == EP_ISO_NUM); - if (epnum != EP_ISO_NUM) { - // CBI - if (dir == TUSB_DIR_OUT) { - NRF_USBD->INTENCLR = TU_BIT(USBD_INTEN_ENDEPOUT0_Pos + epnum); - NRF_USBD->EPOUTEN &= ~TU_BIT(epnum); - } else { - NRF_USBD->INTENCLR = TU_BIT(USBD_INTEN_ENDEPIN0_Pos + epnum); - NRF_USBD->EPINEN &= ~TU_BIT(epnum); - } + // A transfer armed before SET_INTERFACE survives to here (this port has no dcd close); usbd has + // just reset the endpoint's claim/busy state, so drop the stale descriptor too — otherwise the + // class's next arm trips TU_ASSERT(!xfer->started) in dcd_edpt_xfer(). + _dcd.xfer[epnum][dir].started = false; + _dcd.xfer[epnum][dir].data_received = false; + _dcd.xfer[epnum][dir].iso_in_transfer_ready = false; + + _dcd.xfer[epnum][dir].mps = tu_edpt_packet_size(desc_ep); + + if (dir == TUSB_DIR_OUT) { + // SPLIT ISO buffer when the ISO IN endpoint is already active. + if (_dcd.xfer[EP_ISO_NUM][TUSB_DIR_IN].mps) NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_HalfIN; + NRF_USBD->EVENTS_ENDISOOUT = 0; + if ((NRF_USBD->INTEN & USBD_INTEN_SOF_Msk) == 0) NRF_USBD->EVENTS_SOF = 0; + NRF_USBD->INTENSET = USBD_INTENSET_ENDISOOUT_Msk | USBD_INTENSET_SOF_Msk; + NRF_USBD->EPOUTEN |= USBD_EPOUTEN_ISOOUT_Msk; } else { - _dcd.xfer[EP_ISO_NUM][dir].mps = 0; - // ISO - if (dir == TUSB_DIR_OUT) { - NRF_USBD->INTENCLR = USBD_INTENCLR_ENDISOOUT_Msk; - NRF_USBD->EPOUTEN &= ~USBD_EPOUTEN_ISOOUT_Msk; - NRF_USBD->EVENTS_ENDISOOUT = 0; - } else { - NRF_USBD->INTENCLR = USBD_INTENCLR_ENDISOIN_Msk; - NRF_USBD->EPINEN &= ~USBD_EPINEN_ISOIN_Msk; - } - // One of the ISO endpoints closed, no need to split buffers any more. - NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_OneDir; - // When both ISO endpoint are close there is no need for SOF any more. - if (_dcd.xfer[EP_ISO_NUM][TUSB_DIR_IN].mps + _dcd.xfer[EP_ISO_NUM][TUSB_DIR_OUT].mps == 0) - NRF_USBD->INTENCLR = USBD_INTENCLR_SOF_Msk; + NRF_USBD->EVENTS_ENDISOIN = 0; + // SPLIT ISO buffer when the ISO OUT endpoint is already active. + if (_dcd.xfer[EP_ISO_NUM][TUSB_DIR_OUT].mps) NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_HalfIN; + if ((NRF_USBD->INTEN & USBD_INTEN_SOF_Msk) == 0) NRF_USBD->EVENTS_SOF = 0; + NRF_USBD->INTENSET = USBD_INTENSET_ENDISOIN_Msk | USBD_INTENSET_SOF_Msk; + NRF_USBD->EPINEN |= USBD_EPINEN_ISOIN_Msk; } - _dcd.xfer[epnum][dir].started = false; + __ISB(); __DSB(); + return true; } -#if 0 -bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { - (void)rhport; - (void)ep_addr; - (void)largest_packet_size; - return false; -} - -bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { - (void)rhport; - (void)desc_ep; - return false; -} -#endif - bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes, bool is_isr) { (void) rhport; (void) is_isr; @@ -862,6 +855,10 @@ static bool hfclk_running(void) { #if CFG_TUD_NRF_NRFX_VERSION == 1 return nrf_clock_hf_is_running(NRF_CLOCK_HFCLK_HIGH_ACCURACY); + #elif CFG_TUD_NRF_NRFX_VERSION == 2 + // nrfx 2.0.0 (MDK 8.29.0) has no nrf_clock_is_running(); it arrived in 2.1.0. + // nrf_clock_hf_is_running() is present in all of 2.0.0-2.11.0 (deprecated from 2.1.0). + return nrf_clock_hf_is_running(NRF_CLOCK, NRF_CLOCK_HFCLK_HIGH_ACCURACY); #else return nrf_clock_is_running(NRF_CLOCK, NRF_CLOCK_DOMAIN_HFCLK, NULL); #endif diff --git a/src/portable/nuvoton/nuc120/dcd_nuc120.c b/src/portable/nuvoton/nuc120/dcd_nuc120.c index 2edb1bc7a..513262ea4 100644 --- a/src/portable/nuvoton/nuc120/dcd_nuc120.c +++ b/src/portable/nuvoton/nuc120/dcd_nuc120.c @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019-2020 Peter Lawrence - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Peter Lawrence + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/nuvoton/nuc121/dcd_nuc121.c b/src/portable/nuvoton/nuc121/dcd_nuc121.c index 008c9df6b..b2859347c 100644 --- a/src/portable/nuvoton/nuc121/dcd_nuc121.c +++ b/src/portable/nuvoton/nuc121/dcd_nuc121.c @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Peter Lawrence - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Peter Lawrence + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/nuvoton/nuc505/dcd_nuc505.c b/src/portable/nuvoton/nuc505/dcd_nuc505.c index a0f3d4c3f..ece7911a1 100644 --- a/src/portable/nuvoton/nuc505/dcd_nuc505.c +++ b/src/portable/nuvoton/nuc505/dcd_nuc505.c @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2020 Peter Lawrence - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2020 Peter Lawrence + * SPDX-FileCopyrightText: Copyright (c) 2020 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/nxp/khci/dcd_khci.c b/src/portable/nxp/khci/dcd_khci.c deleted file mode 100644 index ad27b8528..000000000 --- a/src/portable/nxp/khci/dcd_khci.c +++ /dev/null @@ -1,578 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020 Koji Kitayama - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if CFG_TUD_ENABLED && defined(TUP_USBIP_CHIPIDEA_FS) - -#ifdef TUP_USBIP_CHIPIDEA_FS_KINETIS - #include "fsl_device_registers.h" - #define KHCI USB0 -#else - #error "MCU is not supported" -#endif - -#include "device/dcd.h" - -//--------------------------------------------------------------------+ -// MACRO TYPEDEF CONSTANT ENUM DECLARATION -//--------------------------------------------------------------------+ - -enum { - TOK_PID_OUT = 0x1u, - TOK_PID_IN = 0x9u, - TOK_PID_SETUP = 0xDu, -}; - -typedef struct TU_ATTR_PACKED -{ - union { - uint32_t head; - struct { - union { - struct { - uint16_t : 2; - __IO uint16_t tok_pid : 4; - uint16_t data : 1; - __IO uint16_t own : 1; - uint16_t : 8; - }; - struct { - uint16_t : 2; - uint16_t bdt_stall : 1; - uint16_t dts : 1; - uint16_t ninc : 1; - uint16_t keep : 1; - uint16_t : 10; - }; - }; - __IO uint16_t bc : 10; - uint16_t : 6; - }; - }; - uint8_t *addr; -}buffer_descriptor_t; - -TU_VERIFY_STATIC( sizeof(buffer_descriptor_t) == 8, "size is not correct" ); - -typedef struct TU_ATTR_PACKED -{ - union { - uint32_t state; - struct { - uint32_t max_packet_size :11; - uint32_t : 5; - uint32_t odd : 1; - uint32_t :15; - }; - }; - uint16_t length; - uint16_t remaining; -}endpoint_state_t; - -TU_VERIFY_STATIC( sizeof(endpoint_state_t) == 8, "size is not correct" ); - -typedef struct -{ - union { - /* [#EP][OUT,IN][EVEN,ODD] */ - buffer_descriptor_t bdt[16][2][2]; - uint16_t bda[512]; - }; - TU_ATTR_ALIGNED(4) union { - endpoint_state_t endpoint[16][2]; - endpoint_state_t endpoint_unified[16 * 2]; - }; - uint8_t setup_packet[8]; - uint8_t addr; -}dcd_data_t; - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ -// BDT(Buffer Descriptor Table) must be 256-byte aligned -CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(512) static dcd_data_t _dcd; - -TU_VERIFY_STATIC( sizeof(_dcd.bdt) == 512, "size is not correct" ); - -static void prepare_next_setup_packet(uint8_t rhport) -{ - const unsigned out_odd = _dcd.endpoint[0][0].odd; - const unsigned in_odd = _dcd.endpoint[0][1].odd; - TU_ASSERT(0 == _dcd.bdt[0][0][out_odd].own, ); - - _dcd.bdt[0][0][out_odd].data = 0; - _dcd.bdt[0][0][out_odd ^ 1].data = 1; - _dcd.bdt[0][1][in_odd].data = 1; - _dcd.bdt[0][1][in_odd ^ 1].data = 0; - dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_OUT), - _dcd.setup_packet, sizeof(_dcd.setup_packet), false); -} - -static void process_stall(uint8_t rhport) -{ - for (int i = 0; i < 16; ++i) { - unsigned const endpt = KHCI->ENDPOINT[i].ENDPT; - - if (endpt & USB_ENDPT_EPSTALL_MASK) { - // prepare next setup if endpoint0 - if ( i == 0 ) prepare_next_setup_packet(rhport); - - // clear stall bit - KHCI->ENDPOINT[i].ENDPT = endpt & ~USB_ENDPT_EPSTALL_MASK; - } - } -} - -static void process_tokdne(uint8_t rhport) -{ - const unsigned s = KHCI->STAT; - KHCI->ISTAT = USB_ISTAT_TOKDNE_MASK; /* fetch the next token if received */ - - uint8_t const epnum = (s >> USB_STAT_ENDP_SHIFT); - uint8_t const dir = (s & USB_STAT_TX_MASK) >> USB_STAT_TX_SHIFT; - unsigned const odd = (s & USB_STAT_ODD_MASK) ? 1 : 0; - - buffer_descriptor_t *bd = (buffer_descriptor_t *)&_dcd.bda[s]; - endpoint_state_t *ep = &_dcd.endpoint_unified[s >> 3]; - - /* fetch pid before discarded by the next steps */ - const unsigned pid = bd->tok_pid; - - /* reset values for a next transfer */ - bd->bdt_stall = 0; - bd->dts = 1; - bd->ninc = 0; - bd->keep = 0; - /* update the odd variable to prepare for the next transfer */ - ep->odd = odd ^ 1; - if (pid == TOK_PID_SETUP) { - dcd_event_setup_received(rhport, bd->addr, true); - KHCI->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK; - return; - } - - const unsigned bc = bd->bc; - const unsigned remaining = ep->remaining - bc; - if (remaining && bc == ep->max_packet_size) { - /* continue the transferring consecutive data */ - ep->remaining = remaining; - const int next_remaining = remaining - ep->max_packet_size; - if (next_remaining > 0) { - /* prepare to the after next transfer */ - bd->addr += ep->max_packet_size * 2; - bd->bc = next_remaining > ep->max_packet_size ? ep->max_packet_size: next_remaining; - __DSB(); - bd->own = 1; /* the own bit must set after addr */ - } - return; - } - const unsigned length = ep->length; - dcd_event_xfer_complete(rhport, - tu_edpt_addr(epnum, dir), - length - remaining, XFER_RESULT_SUCCESS, true); - if (0 == epnum && 0 == length) { - /* After completion a ZLP of control transfer, - * it prepares for the next steup transfer. */ - if (_dcd.addr) { - /* When the transfer was the SetAddress, - * the device address should be updated here. */ - KHCI->ADDR = _dcd.addr; - _dcd.addr = 0; - } - prepare_next_setup_packet(rhport); - } -} - -static void process_bus_reset(uint8_t rhport) -{ - KHCI->USBCTRL &= ~USB_USBCTRL_SUSP_MASK; - KHCI->CTL |= USB_CTL_ODDRST_MASK; - KHCI->ADDR = 0; - KHCI->INTEN = USB_INTEN_USBRSTEN_MASK | USB_INTEN_TOKDNEEN_MASK | USB_INTEN_SLEEPEN_MASK | - USB_INTEN_ERROREN_MASK | USB_INTEN_STALLEN_MASK; - - KHCI->ENDPOINT[0].ENDPT = USB_ENDPT_EPHSHK_MASK | USB_ENDPT_EPRXEN_MASK | USB_ENDPT_EPTXEN_MASK; - for (unsigned i = 1; i < 16; ++i) { - KHCI->ENDPOINT[i].ENDPT = 0; - } - buffer_descriptor_t *bd = _dcd.bdt[0][0]; - for (unsigned i = 0; i < sizeof(_dcd.bdt)/sizeof(*bd); ++i, ++bd) { - bd->head = 0; - } - const endpoint_state_t ep0 = { - .max_packet_size = CFG_TUD_ENDPOINT0_SIZE, - .odd = 0, - .length = 0, - .remaining = 0, - }; - _dcd.endpoint[0][0] = ep0; - _dcd.endpoint[0][1] = ep0; - tu_memclr(_dcd.endpoint[1], sizeof(_dcd.endpoint) - sizeof(_dcd.endpoint[0])); - _dcd.addr = 0; - prepare_next_setup_packet(rhport); - KHCI->CTL &= ~USB_CTL_ODDRST_MASK; - dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true); -} - -static void process_bus_sleep(uint8_t rhport) -{ - // Enable resume & disable suspend interrupt - const unsigned inten = KHCI->INTEN; - - KHCI->INTEN = (inten & ~USB_INTEN_SLEEPEN_MASK) | USB_INTEN_RESUMEEN_MASK; - KHCI->USBTRC0 |= USB_USBTRC0_USBRESMEN_MASK; - KHCI->USBCTRL |= USB_USBCTRL_SUSP_MASK; - - dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true); -} - -static void process_bus_resume(uint8_t rhport) -{ - // Enable suspend & disable resume interrupt - const unsigned inten = KHCI->INTEN; - - KHCI->USBCTRL &= ~USB_USBCTRL_SUSP_MASK; // will also clear USB_USBTRC0_USB_RESUME_INT_MASK - KHCI->USBTRC0 &= ~USB_USBTRC0_USBRESMEN_MASK; - KHCI->INTEN = (inten & ~USB_INTEN_RESUMEEN_MASK) | USB_INTEN_SLEEPEN_MASK; - - dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true); -} - -/*------------------------------------------------------------------*/ -/* Device API - *------------------------------------------------------------------*/ -bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { - (void) rhport; - (void) rh_init; - - // save crystal-less setting (if available) - #if defined(FSL_FEATURE_USB_KHCI_IRC48M_MODULE_CLOCK_ENABLED) && FSL_FEATURE_USB_KHCI_IRC48M_MODULE_CLOCK_ENABLED == 1 - uint32_t clk_recover_irc_en = KHCI->CLK_RECOVER_IRC_EN; - uint32_t clk_recover_ctrl = KHCI->CLK_RECOVER_CTRL; - #endif - - KHCI->USBTRC0 |= USB_USBTRC0_USBRESET_MASK; - while (KHCI->USBTRC0 & USB_USBTRC0_USBRESET_MASK); - - // restore crystal-less setting (if available) - #if defined(FSL_FEATURE_USB_KHCI_IRC48M_MODULE_CLOCK_ENABLED) && FSL_FEATURE_USB_KHCI_IRC48M_MODULE_CLOCK_ENABLED == 1 - KHCI->CLK_RECOVER_IRC_EN = clk_recover_irc_en; - KHCI->CLK_RECOVER_CTRL |= clk_recover_ctrl; - #endif - - tu_memclr(&_dcd, sizeof(_dcd)); - KHCI->USBTRC0 |= TU_BIT(6); /* software must set this bit to 1 */ - KHCI->BDTPAGE1 = (uint8_t)((uintptr_t)_dcd.bdt >> 8); - KHCI->BDTPAGE2 = (uint8_t)((uintptr_t)_dcd.bdt >> 16); - KHCI->BDTPAGE3 = (uint8_t)((uintptr_t)_dcd.bdt >> 24); - - KHCI->INTEN = USB_INTEN_USBRSTEN_MASK; - - dcd_connect(rhport); - NVIC_ClearPendingIRQ(USB0_IRQn); - - return true; -} - -void dcd_int_enable(uint8_t rhport) -{ - (void) rhport; - NVIC_EnableIRQ(USB0_IRQn); -} - -void dcd_int_disable(uint8_t rhport) -{ - (void) rhport; - NVIC_DisableIRQ(USB0_IRQn); -} - -void dcd_set_address(uint8_t rhport, uint8_t dev_addr) -{ - _dcd.addr = dev_addr & 0x7F; - /* Response with status first before changing device address */ - dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0, false); -} - -void dcd_remote_wakeup(uint8_t rhport) -{ - (void) rhport; - - KHCI->CTL |= USB_CTL_RESUME_MASK; - - unsigned cnt = SystemCoreClock / 1000; - while (cnt--) __NOP(); - - KHCI->CTL &= ~USB_CTL_RESUME_MASK; -} - -void dcd_connect(uint8_t rhport) -{ - (void) rhport; - KHCI->USBCTRL = 0; - KHCI->CONTROL |= USB_CONTROL_DPPULLUPNONOTG_MASK; - KHCI->CTL |= USB_CTL_USBENSOFEN_MASK; -} - -void dcd_disconnect(uint8_t rhport) -{ - (void) rhport; - KHCI->CTL = 0; - KHCI->CONTROL &= ~USB_CONTROL_DPPULLUPNONOTG_MASK; -} - -void dcd_sof_enable(uint8_t rhport, bool en) -{ - (void) rhport; - (void) en; - - // TODO implement later -} - -//--------------------------------------------------------------------+ -// Endpoint API -//--------------------------------------------------------------------+ -static bool edpt_open(uint8_t rhport, uint8_t ep_addr, uint16_t max_packet_size, tusb_xfer_type_t xfer) { - (void)rhport; - - const unsigned epn = tu_edpt_number(ep_addr); - const unsigned dir = tu_edpt_dir(ep_addr); - endpoint_state_t *ep = &_dcd.endpoint[epn][dir]; - const unsigned odd = ep->odd; - buffer_descriptor_t *bd = _dcd.bdt[epn][dir]; - - /* No support for control transfer */ - TU_ASSERT(epn && (xfer != TUSB_XFER_CONTROL)); - - ep->max_packet_size = max_packet_size; - unsigned val = USB_ENDPT_EPCTLDIS_MASK; - val |= (xfer != TUSB_XFER_ISOCHRONOUS) ? USB_ENDPT_EPHSHK_MASK : 0; - val |= dir ? USB_ENDPT_EPTXEN_MASK : USB_ENDPT_EPRXEN_MASK; - KHCI->ENDPOINT[epn].ENDPT |= val; - - if (xfer != TUSB_XFER_ISOCHRONOUS) { - bd[odd].dts = 1; - bd[odd].data = 0; - bd[odd ^ 1].dts = 1; - bd[odd ^ 1].data = 1; - } - - return true; -} - -bool dcd_edpt_open(uint8_t rhport, const tusb_desc_endpoint_t *ep_desc) { - return edpt_open(rhport, ep_desc->bEndpointAddress, tu_edpt_packet_size(ep_desc), ep_desc->bmAttributes.xfer); -} - -bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { - return edpt_open(rhport, ep_addr, largest_packet_size, TUSB_XFER_ISOCHRONOUS); -} - -bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *ep_desc) { - const unsigned epn = tu_edpt_number(ep_desc->bEndpointAddress); - const unsigned dir = tu_edpt_dir(ep_desc->bEndpointAddress); - endpoint_state_t *ep = &_dcd.endpoint[epn][dir]; - - dcd_int_disable(rhport); - ep->max_packet_size = tu_edpt_packet_size(ep_desc); - dcd_int_enable(rhport); - - return true; -} - -void dcd_edpt_close_all(uint8_t rhport) -{ - (void) rhport; - const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn); - NVIC_DisableIRQ(USB0_IRQn); - for (unsigned i = 1; i < 16; ++i) { - KHCI->ENDPOINT[i].ENDPT = 0; - } - if (ie) NVIC_EnableIRQ(USB0_IRQn); - buffer_descriptor_t *bd = _dcd.bdt[1][0]; - for (unsigned i = 2; i < sizeof(_dcd.bdt)/sizeof(*bd); ++i, ++bd) { - bd->head = 0; - } - endpoint_state_t *ep = &_dcd.endpoint[1][0]; - for (unsigned i = 2; i < sizeof(_dcd.endpoint)/sizeof(*ep); ++i, ++ep) { - /* Clear except the odd */ - ep->max_packet_size = 0; - ep->length = 0; - ep->remaining = 0; - } -} - -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) -{ - (void) rhport; - (void) is_isr; - const unsigned epn = tu_edpt_number(ep_addr); - const unsigned dir = tu_edpt_dir(ep_addr); - endpoint_state_t *ep = &_dcd.endpoint[epn][dir]; - buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][ep->odd]; - TU_ASSERT(0 == bd->own); - - const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn); - NVIC_DisableIRQ(USB0_IRQn); - - ep->length = total_bytes; - ep->remaining = total_bytes; - - const unsigned mps = ep->max_packet_size; - if (total_bytes > mps) { - buffer_descriptor_t *next = ep->odd ? bd - 1: bd + 1; - /* When total_bytes is greater than the max packet size, - * it prepares to the next transfer to avoid NAK in advance. */ - next->bc = total_bytes >= 2 * mps ? mps: total_bytes - mps; - next->addr = buffer + mps; - next->own = 1; - } - bd->bc = total_bytes >= mps ? mps: total_bytes; - bd->addr = buffer; - __DSB(); - bd->own = 1; /* This bit must be set last */ - - if (ie) NVIC_EnableIRQ(USB0_IRQn); - return true; -} - -void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) -{ - (void) rhport; - const unsigned epn = tu_edpt_number(ep_addr); - - if (0 == epn) { - KHCI->ENDPOINT[epn].ENDPT |= USB_ENDPT_EPSTALL_MASK; - } else { - const unsigned dir = tu_edpt_dir(ep_addr); - const unsigned odd = _dcd.endpoint[epn][dir].odd; - buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][odd]; - TU_ASSERT(0 == bd->own,); - - const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn); - NVIC_DisableIRQ(USB0_IRQn); - - bd->bdt_stall = 1; - __DSB(); - bd->own = 1; /* This bit must be set last */ - - if (ie) NVIC_EnableIRQ(USB0_IRQn); - } -} - -void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) -{ - (void) rhport; - const unsigned epn = tu_edpt_number(ep_addr); - TU_VERIFY(epn,); - const unsigned dir = tu_edpt_dir(ep_addr); - const unsigned odd = _dcd.endpoint[epn][dir].odd; - buffer_descriptor_t *bd = _dcd.bdt[epn][dir]; - TU_VERIFY(bd[odd].own,); - - const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn); - NVIC_DisableIRQ(USB0_IRQn); - - bd[odd].own = 0; - __DSB(); - - // clear stall - bd[odd].bdt_stall = 0; - - // Reset data toggle - bd[odd ].data = 0; - bd[odd ^ 1].data = 1; - - // We already cleared this in ISR, but just clear it here to be safe - const unsigned endpt = KHCI->ENDPOINT[epn].ENDPT; - if (endpt & USB_ENDPT_EPSTALL_MASK) { - KHCI->ENDPOINT[epn].ENDPT = endpt & ~USB_ENDPT_EPSTALL_MASK; - } - - if (ie) NVIC_EnableIRQ(USB0_IRQn); -} - -//--------------------------------------------------------------------+ -// ISR -//--------------------------------------------------------------------+ -void dcd_int_handler(uint8_t rhport) -{ - uint32_t is = KHCI->ISTAT; - uint32_t msk = KHCI->INTEN; - - // clear non-enabled interrupts - KHCI->ISTAT = is & ~msk; - is &= msk; - - if (is & USB_ISTAT_ERROR_MASK) { - /* TODO: */ - uint32_t es = KHCI->ERRSTAT; - KHCI->ERRSTAT = es; - KHCI->ISTAT = is; /* discard any pending events */ - } - - if (is & USB_ISTAT_USBRST_MASK) { - KHCI->ISTAT = is; /* discard any pending events */ - process_bus_reset(rhport); - } - - if (is & USB_ISTAT_SLEEP_MASK) { - // TU_LOG3("Suspend: "); TU_LOG2_HEX(is); - - // Note Host usually has extra delay after bus reset (without SOF), which could falsely - // detected as Sleep event. Though usbd has debouncing logic so we are good - KHCI->ISTAT = USB_ISTAT_SLEEP_MASK; - process_bus_sleep(rhport); - } - -#if 0 // ISTAT_RESUME never trigger, probably for host mode ? - if (is & USB_ISTAT_RESUME_MASK) { - // TU_LOG2("ISTAT Resume: "); TU_LOG2_HEX(is); - KHCI->ISTAT = USB_ISTAT_RESUME_MASK; - process_bus_resume(rhport); - } -#endif - - if (KHCI->USBTRC0 & USB_USBTRC0_USB_RESUME_INT_MASK) { - // TU_LOG2("USBTRC0 Resume: "); TU_LOG2_HEX(is); TU_LOG2_HEX(KHCI->USBTRC0); - process_bus_resume(rhport); - } - - if (is & USB_ISTAT_SOFTOK_MASK) { - KHCI->ISTAT = USB_ISTAT_SOFTOK_MASK; - dcd_event_sof(rhport, tu_u16(KHCI->FRMNUMH, KHCI->FRMNUML), true); - } - - if (is & USB_ISTAT_STALL_MASK) { - KHCI->ISTAT = USB_ISTAT_STALL_MASK; - process_stall(rhport); - } - - if (is & USB_ISTAT_TOKDNE_MASK) { - process_tokdne(rhport); - } -} -#endif diff --git a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c index 2840c6d5e..b577d0e9f 100644 --- a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c +++ b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -38,6 +19,12 @@ //--------------------------------------------------------------------+ #define DCD_ENDPOINT_MAX 32 +// The iso machinery (5th DD word + packet-size memory) costs USB RAM on every build; +// compile it only when a class that can open an iso endpoint is enabled. Keep this in +// sync with the classes that actually arm an iso endpoint: audio, video, BTH (voice), +// and vendor (its optional CFG_TUD_VENDOR_EP_ISO_* endpoints, exercised by usbtest). +#define DCD_ISO_ENABLED (CFG_TUD_AUDIO || CFG_TUD_VIDEO || CFG_TUD_VENDOR || CFG_TUD_BTH) + typedef struct TU_ATTR_ALIGNED(4) { //------------- Word 0 -------------// @@ -67,11 +54,37 @@ typedef struct TU_ATTR_ALIGNED(4) volatile uint16_t present_count; // For non-iso : The number of bytes transferred by the DMA engine // For iso : number of packets +#if DCD_ISO_ENABLED //------------- Word 4 -------------// - // uint32_t iso_packet_size_addr; // iso only, can be omitted for non-iso + volatile uint32_t iso_packet_size_addr; // iso only: pointer into iso packet-size memory, + // advanced by hardware after each packet +#endif }dma_desc_t; -TU_VERIFY_STATIC( sizeof(dma_desc_t) == 16, "size is not correct"); // TODO not support ISO for now +TU_VERIFY_STATIC( sizeof(dma_desc_t) == (DCD_ISO_ENABLED ? 20 : 16), "size is not correct"); + +// Hardware fixes endpoint type by number: 3, 6, 9, 12 are the iso-capable ones. +// Constant per ep_id (= 2*epnum + dir) — unlike dd->isochronous, which dcd_edpt_xfer +// transiently zeroes while rebuilding the DD, this is safe to dispatch on from the ISR. +// TU_ATTR_UNUSED: every caller is under #if DCD_ISO_ENABLED, so non-iso builds don't +// reference it and clang -Wunused-function (fatal) would otherwise reject the build. +TU_ATTR_UNUSED TU_ATTR_ALWAYS_INLINE static inline bool ep_id_is_iso(uint8_t ep_id) { + uint8_t const epnum = (uint8_t)(ep_id >> 1); + return (epnum % 3) == 0 && (epnum != 0) && (epnum != 15); +} + +#if DCD_ISO_ENABLED +// Isochronous packet-size memory (UM10562 12.15.6.3): one word per packet. +// IN : software fills Packet_length (bits 15:0), 0 = ZLP +// OUT: hardware writes Frame_number (31:17) | Packet_valid (16) | Packet_length (15:0) +// Iso-capable endpoint numbers are 3, 6, 9, 12 -> 8 slots (x2 directions). +// One packet moves per FRAME, so a deep queue only adds latency: 8 frames is plenty. +#define ISO_MAX_PACKETS 8 +#define ISO_SLOT_COUNT 8 +TU_ATTR_ALWAYS_INLINE static inline uint8_t iso_slot(uint8_t ep_id) { + return (uint8_t)(((ep_id / 6) - 1) * 2 + (ep_id & 1)); // ep_id = 2*epnum + dir, epnum in {3,6,9,12} +} +#endif typedef struct { @@ -85,11 +98,17 @@ typedef struct { uint8_t* out_buffer; uint8_t out_bytes; + volatile bool out_queued; // an OUT xfer is queued; out_buffer may legitimately be NULL (status ZLP) volatile bool out_received; // indicate if data is already received in endpoint uint8_t in_bytes; } control; +#if DCD_ISO_ENABLED + // iso packet-size memory, must be DMA-reachable like the DDs + volatile uint32_t iso_psize[ISO_SLOT_COUNT][ISO_MAX_PACKETS]; +#endif + } dcd_data_t; CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(128) static dcd_data_t _dcd; @@ -98,6 +117,29 @@ CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(128) static dcd_data_t _dcd; //--------------------------------------------------------------------+ // SIE Command //--------------------------------------------------------------------+ + +// The SIE command protocol (CmdCode + CCEMPTY/CDFULL handshake) and the +// slave-mode Ctrl/RxData/TxData registers are shared between thread-mode API +// calls and dcd_int_handler, and are not reentrant: an ISR preempting a +// thread-mode SIE sequence consumes its handshake flags and overwrites +// CmdCode (symptom: EP0 wedges/answers stale data right after SET_INTERFACE +// stall/clear-stall bursts overlapping bulk EOT interrupts). Mask only the +// USB interrupt around those sequences; safe to nest, including from the ISR. +static inline bool usb_irq_lock(void) +{ + bool const enabled = NVIC_GetEnableIRQ(USB_IRQn) != 0; + if (enabled) + { + NVIC_DisableIRQ(USB_IRQn); // CMSIS already ends this with DSB+ISB + } + return enabled; +} + +static inline void usb_irq_unlock(bool enabled) +{ + if (enabled) NVIC_EnableIRQ(USB_IRQn); +} + static void sie_cmd_code (sie_cmdphase_t phase, uint8_t code_data) { LPC_USB->DevIntClr = (DEV_INT_COMMAND_CODE_EMPTY_MASK | DEV_INT_COMMAND_DATA_FULL_MASK); @@ -111,19 +153,28 @@ static void sie_cmd_code (sie_cmdphase_t phase, uint8_t code_data) static void sie_write (uint8_t cmd_code, uint8_t data_len, uint8_t data) { + bool const lock = usb_irq_lock(); + sie_cmd_code(SIE_CMDPHASE_COMMAND, cmd_code); if (data_len) { sie_cmd_code(SIE_CMDPHASE_WRITE, data); } + + usb_irq_unlock(lock); } static uint8_t sie_read (uint8_t cmd_code) { + bool const lock = usb_irq_lock(); + sie_cmd_code(SIE_CMDPHASE_COMMAND , cmd_code); sie_cmd_code(SIE_CMDPHASE_READ , cmd_code); - return (uint8_t) LPC_USB->CmdData; + uint8_t const data = (uint8_t) LPC_USB->CmdData; + + usb_irq_unlock(lock); + return data; } //--------------------------------------------------------------------+ @@ -136,6 +187,11 @@ static inline uint8_t ep_addr2idx(uint8_t ep_addr) static void set_ep_size(uint8_t ep_id, uint16_t max_packet_size) { + // ReEp RMW + the EP_RLZED handshake share DevIntSt with the ISR: a bus reset + // from dcd_int_handler writes DevIntClr = 0xFFFFFFFF and would consume the + // flag this spin waits on, hanging it forever -> same lock as the SIE paths. + bool const lock = usb_irq_lock(); + // follows example in 11.10.4.2 LPC_USB->ReEp |= TU_BIT(ep_id); LPC_USB->EpInd = ep_id; // select index before setting packet size @@ -143,6 +199,8 @@ static void set_ep_size(uint8_t ep_id, uint16_t max_packet_size) while ((LPC_USB->DevIntSt & DEV_INT_ENDPOINT_REALIZED_MASK) == 0) {} LPC_USB->DevIntClr = DEV_INT_ENDPOINT_REALIZED_MASK; + + usb_irq_unlock(lock); } @@ -249,6 +307,7 @@ static inline uint8_t byte2dword(uint8_t bytes) static void control_ep_write(void const * buffer, uint8_t len) { uint32_t const * buf32 = (uint32_t const *) buffer; + bool const lock = usb_irq_lock(); // Ctrl/TxData + SIE sequence must not interleave with the ISR LPC_USB->Ctrl = USBCTRL_WRITE_ENABLE_MASK; // logical endpoint = 0 LPC_USB->TxPLen = (uint32_t) len; @@ -264,10 +323,14 @@ static void control_ep_write(void const * buffer, uint8_t len) // select control IN & validate the endpoint sie_write(SIE_CMDCODE_ENDPOINT_SELECT+1, 0, 0); sie_write(SIE_CMDCODE_BUFFER_VALIDATE , 0, 0); + + usb_irq_unlock(lock); } static uint8_t control_ep_read(void * buffer, uint8_t len) { + bool const lock = usb_irq_lock(); // Ctrl/RxData + SIE sequence must not interleave with the ISR + LPC_USB->Ctrl = USBCTRL_READ_ENABLE_MASK; // logical endpoint = 0 while ((LPC_USB->RxPLen & USBRXPLEN_PACKET_READY_MASK) == 0) {} // TODO blocking, should have timeout @@ -286,6 +349,7 @@ static uint8_t control_ep_read(void * buffer, uint8_t len) sie_write(SIE_CMDCODE_ENDPOINT_SELECT+0, 0, 0); sie_write(SIE_CMDCODE_BUFFER_CLEAR , 0, 0); + usb_irq_unlock(lock); return len; } @@ -300,8 +364,9 @@ 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 ep_id = ep_addr2idx(p_endpoint_desc->bEndpointAddress); - // Endpoint type is fixed to endpoint number - // 1: interrupt, 2: Bulk, 3: Iso and so on + // Endpoint type is fixed to endpoint number (1 interrupt, 2 bulk, 3 iso, ...). + // Iso endpoints are armed via dcd_edpt_iso_alloc/activate, never through here + // (TUP_DCD_EDPT_ISO_ALLOC is defined for this IP), so only bulk/interrupt land here. switch ( p_endpoint_desc->bmAttributes.xfer ) { case TUSB_XFER_INTERRUPT: @@ -312,10 +377,6 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) TU_ASSERT((epnum % 3) == 2 || (epnum == 15)); break; - case TUSB_XFER_ISOCHRONOUS: - TU_ASSERT((epnum % 3) == 0 && (epnum != 0) && (epnum != 15)); - break; - default: break; } @@ -326,9 +387,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) //------------- first DD prepare -------------// dma_desc_t* const dd = &_dcd.dd[ep_id]; - tu_memclr(dd, sizeof(dma_desc_t)); - - dd->isochronous = (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) ? 1 : 0; + tu_memclr(dd, sizeof(dma_desc_t)); // non-iso: isochronous stays 0 dd->max_packet_size = ep_size; dd->retired = 1; // invalid at first @@ -338,16 +397,54 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) } bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { +#if DCD_ISO_ENABLED (void)rhport; - (void)ep_addr; - (void)largest_packet_size; + uint8_t const ep_id = ep_addr2idx(ep_addr); + + // hardware fixes iso to endpoint numbers 3, 6, 9, 12 + TU_ASSERT(ep_id_is_iso(ep_id)); + TU_ASSERT(largest_packet_size > 0); + + set_ep_size(ep_id, largest_packet_size); + + dma_desc_t* const dd = &_dcd.dd[ep_id]; + tu_memclr(dd, sizeof(dma_desc_t)); + dd->isochronous = 1; + dd->max_packet_size = largest_packet_size; + dd->retired = 1; // invalid at first + + sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS + ep_id, 1, 0); + return true; +#else + (void)rhport; (void)ep_addr; (void)largest_packet_size; return false; +#endif } bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { +#if DCD_ISO_ENABLED (void)rhport; - (void)desc_ep; + uint8_t const ep_id = ep_addr2idx(desc_ep->bEndpointAddress); + dma_desc_t* const dd = &_dcd.dd[ep_id]; + + // same fixed-number rule as alloc: without it a rejected-but-ignored alloc (classes + // discard that return) would set isochronous on a non-iso ep_id and underflow iso_slot() + TU_ASSERT(ep_id_is_iso(ep_id)); + + // kill any armed transfer from a previous alternate setting + LPC_USB->EpDMADis = TU_BIT(ep_id); + _dcd.udca[ep_id] = NULL; + + dd->isochronous = 1; + dd->max_packet_size = tu_edpt_packet_size(desc_ep); + dd->retired = 1; + + sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS + ep_id, 1, 0); + return true; +#else + (void)rhport; (void)desc_ep; return false; +#endif } void dcd_edpt_close_all (uint8_t rhport) @@ -388,19 +485,28 @@ static bool control_xact(uint8_t rhport, uint8_t dir, uint8_t * buffer, uint8_t control_ep_write(buffer, len); }else { + // guard the out_received/out_buffer handshake against the EP0 OUT ISR + bool const lock = usb_irq_lock(); + if ( _dcd.control.out_received ) { // Already received the DATA OUT packet _dcd.control.out_received = false; - _dcd.control.out_buffer = NULL; - _dcd.control.out_bytes = 0; uint8_t received = control_ep_read(buffer, len); + // event queued with in_isr=true, which skips the queue's own locking: keep the + // USB IRQ masked across it, or a real ISR completion could interleave the write dcd_event_xfer_complete(0, 0, received, XFER_RESULT_SUCCESS, true); + usb_irq_unlock(lock); }else { + // buffer is NULL for a status-stage ZLP: signal the pending xfer explicitly, + // NOT via out_buffer != NULL — a NULL-buffer queue mistaken for "nothing queued" + // leaves out_received stale and poisons the next control OUT data stage. _dcd.control.out_buffer = buffer; _dcd.control.out_bytes = len; + _dcd.control.out_queued = true; + usb_irq_unlock(lock); } } @@ -425,26 +531,68 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t uint16_t const ep_size = dd->max_packet_size; uint8_t is_iso = dd->isochronous; - tu_memclr(dd, sizeof(dma_desc_t)); - dd->isochronous = is_iso; - dd->max_packet_size = ep_size; - dd->buffer = (uint32_t) buffer; - dd->buflen = total_bytes; +#if DCD_ISO_ENABLED + if ( is_iso ) + { + // iso: buflen counts packets; per-packet sizes live in the packet-size memory. + // One packet moves per frame (UM10562 12.15.6: DMA request is raised for + // DMA-enabled iso endpoints on every FRAME interrupt, both directions). + // Validate BEFORE touching the DD: bailing out mid-rebuild would leave a + // zeroed (retired=0 -> serviceable) descriptor armed for the frame engine. + TU_ASSERT(ep_size > 0); + uint16_t const packets = (total_bytes > 0) ? (uint16_t) tu_div_ceil(total_bytes, ep_size) : 1; + TU_ASSERT(packets <= ISO_MAX_PACKETS); - _dcd.udca[ep_id] = dd; + uint8_t const slot = iso_slot(ep_id); + uint16_t remain = total_bytes; + for ( uint16_t i = 0; i < packets; i++ ) + { + uint16_t const pkt_len = tu_min16(remain, ep_size); + // IN: length to send (0 = ZLP). OUT: hardware writes back + // Frame_number|Packet_valid|Packet_length -- prefill 0 so a frame the + // hardware never wrote (missed/invalid) cannot read back as data. + _dcd.iso_psize[slot][i] = (ep_id & 1) ? pkt_len : 0; + remain = (uint16_t)(remain - pkt_len); + } - if ( ep_id % 2 ) - { - // Clear EP interrupt before Enable DMA - LPC_USB->EpIntEn &= ~TU_BIT(ep_id); - LPC_USB->EpDMAEn = TU_BIT(ep_id); + tu_memclr(dd, sizeof(dma_desc_t)); + dd->isochronous = 1; + dd->max_packet_size = ep_size; + dd->buffer = (uint32_t) buffer; + dd->buflen = packets; + dd->iso_packet_size_addr = (uint32_t) &_dcd.iso_psize[slot][0]; - // endpoint IN need to actively raise DMA request - LPC_USB->DMARSet = TU_BIT(ep_id); - }else + _dcd.udca[ep_id] = dd; + LPC_USB->EpDMAEn = TU_BIT(ep_id); // frame-triggered: no DMARSet, no EpIntEn + } + else +#else + (void) is_iso; +#endif { - // Enable DMA - LPC_USB->EpDMAEn = TU_BIT(ep_id); + tu_memclr(dd, sizeof(dma_desc_t)); + dd->max_packet_size = ep_size; + dd->buffer = (uint32_t) buffer; + dd->buflen = total_bytes; + + _dcd.udca[ep_id] = dd; + + if ( ep_id % 2 ) + { + // Clear EP interrupt before Enable DMA + // EpIntEn read-modify-write races the ISR's own RMWs -> lock + bool const lock = usb_irq_lock(); + LPC_USB->EpIntEn &= ~TU_BIT(ep_id); + LPC_USB->EpDMAEn = TU_BIT(ep_id); + usb_irq_unlock(lock); + + // endpoint IN need to actively raise DMA request + LPC_USB->DMARSet = TU_BIT(ep_id); + }else + { + // Enable DMA + LPC_USB->EpDMAEn = TU_BIT(ep_id); + } } return true; @@ -470,13 +618,20 @@ static void control_xfer_isr(uint8_t rhport, uint32_t ep_int_status) uint8_t setup_packet[8]; control_ep_read(setup_packet, 8); // TODO read before clear setup above + // a new SETUP voids any half-finished control state + _dcd.control.out_queued = false; + _dcd.control.out_received = false; + _dcd.control.out_buffer = NULL; + _dcd.control.out_bytes = 0; + dcd_event_setup_received(rhport, setup_packet, true); } - else if ( _dcd.control.out_buffer ) + else if ( _dcd.control.out_queued ) { - // software queued transfer previously + // software queued transfer previously (out_buffer NULL = status ZLP) uint8_t received = control_ep_read(_dcd.control.out_buffer, _dcd.control.out_bytes); + _dcd.control.out_queued = false; _dcd.control.out_buffer = NULL; _dcd.control.out_bytes = 0; @@ -532,7 +687,32 @@ static void dd_complete_isr(uint8_t rhport, uint8_t ep_id) uint8_t result = (dd->status == DD_STATUS_NORMAL || dd->status == DD_STATUS_DATA_UNDERUN) ? XFER_RESULT_SUCCESS : XFER_RESULT_FAILED; uint8_t const ep_addr = (ep_id / 2) | ((ep_id & 0x01) ? TUSB_DIR_IN_MASK : 0); - dcd_event_xfer_complete(rhport, ep_addr, dd->present_count, result, true); + uint32_t xferred_bytes; +#if DCD_ISO_ENABLED + if ( ep_id_is_iso(ep_id) ) + { + // present_count is in packets; actual byte counts are in the packet-size memory + // (IN: as programmed by us, OUT: Packet_length written back by hardware, + // guarded by Packet_valid -- a frame with no packet must count as 0) + uint8_t const slot = iso_slot(ep_id); + uint16_t const packets = tu_min16(dd->present_count, ISO_MAX_PACKETS); + xferred_bytes = 0; + for (uint16_t i = 0; i < packets; i++) + { + uint32_t const psize = _dcd.iso_psize[slot][i]; + if ( (ep_id & 1) || (psize & TU_BIT(16)) ) + { + xferred_bytes += (psize & 0xFFFFu); + } + } + } + else +#endif + { + xferred_bytes = dd->present_count; + } + + dcd_event_xfer_complete(rhport, ep_addr, (uint16_t) xferred_bytes, result, true); } // main USB IRQ handler @@ -588,6 +768,16 @@ void dcd_int_handler(uint8_t rhport) { if ( tu_bit_test(eot, ep_id) ) { + // dispatch on the hardware's fixed ep-number/type map, NOT dd->isochronous: + // thread-mode dcd_edpt_xfer transiently zeroes the DD while rebuilding it +#if DCD_ISO_ENABLED + if ( ep_id_is_iso(ep_id) ) + { + // iso: last packet already left with its frame; complete both directions here + dd_complete_isr(rhport, ep_id); + } + else +#endif if ( ep_id & 0x01 ) { // IN enable EpInt for end of usb transfer diff --git a/src/portable/nxp/lpc17_40/dcd_lpc17_40.h b/src/portable/nxp/lpc17_40/dcd_lpc17_40.h index 25c9f9985..da7f726d4 100644 --- a/src/portable/nxp/lpc17_40/dcd_lpc17_40.h +++ b/src/portable/nxp/lpc17_40/dcd_lpc17_40.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c index 8adf0f840..42f6750b1 100644 --- a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c +++ b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -106,6 +87,10 @@ enum { DEVCMDSTAT_SUSPEND_CHANGE_MASK = TU_BIT(25), DEVCMDSTAT_RESET_CHANGE_MASK = TU_BIT(26), DEVCMDSTAT_VBUS_DEBOUNCED_MASK = TU_BIT(28), + + // write-1-to-clear latches + DEVCMDSTAT_W1C_MASK = DEVCMDSTAT_SETUP_RECEIVED_MASK | DEVCMDSTAT_CONNECT_CHANGE_MASK | + DEVCMDSTAT_SUSPEND_CHANGE_MASK | DEVCMDSTAT_RESET_CHANGE_MASK, }; enum { @@ -177,6 +162,10 @@ typedef struct // - 55 usb0 (FS) has 5x2 endpoints, usb1 (HS) has 6x2 endpoints #define MAX_EP_PAIRS 6 +// Bounded spin waiting for hardware to clear an EPSKIP bit when retiring a still-armed endpoint on +// reopen (dcd_edpt_open). Hardware clears it within a (micro)frame; the guard only avoids a hang. +#define IP3511_EPSKIP_SPIN 100000u + // NOTE data will be transferred as soon as dcd get request by dcd_pipe(_queue)_xfer using double buffering. // current_td is used to keep track of number of remaining & xferred bytes of the current request. typedef struct @@ -186,7 +175,9 @@ typedef struct ep_cmd_sts_t ep[2*MAX_EP_PAIRS][2]; xfer_dma_t dma[2*MAX_EP_PAIRS]; - TU_ATTR_ALIGNED(64) uint8_t setup_packet[8]; + // volatile: the controller DMAs a new setup packet into this buffer as soon as the SETUP + // latch is cleared, so reads of it must stay ordered against the register accesses around them + TU_ATTR_ALIGNED(64) volatile uint8_t setup_packet[8]; }dcd_data_t; // EP list must be 256-byte aligned @@ -195,8 +186,12 @@ typedef struct // Use CFG_TUD_MEM_SECTION to place it accordingly. CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(256) static dcd_data_t _dcd; -// Dummy buffer to fix ZLPs overwriting the buffer (probably an USB/DMA controller bug) -// TODO find way to save memory +// Dummy buffer to fix ZLPs overwriting the buffer: Errata LPC55S6x USB.5 / LPC55S2x USB.4 - the +// HS device controller always DMA-writes OUT data in 8-byte units, so up to 7 bytes land past the +// received length. This redirects the ZLP case; the general short-OUT case is unhandled here +// (TinyUSB's own endpoint buffers are sized/aligned so the spill stays inside them, but a tight +// caller buffer can be overrun by up to 7 bytes - the SDK's documented workaround is a bounce +// buffer). TODO find way to save memory CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(64) static uint8_t dummy[8]; //--------------------------------------------------------------------+ @@ -236,7 +231,7 @@ static const dcd_controller_t _dcd_controller[] = { // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ -TU_ATTR_ALWAYS_INLINE static inline uint16_t get_buf_offset(void const * buffer) { +TU_ATTR_ALWAYS_INLINE static inline uint16_t get_buf_offset(void const volatile * buffer) { uint32_t addr = (uint32_t) buffer; TU_ASSERT( (addr & 0x3f) == 0, 0 ); return ( (addr >> 6) & 0xFFFFUL ) ; @@ -262,6 +257,16 @@ TU_ATTR_ALWAYS_INLINE static inline bool rhport_is_highspeed(uint8_t rhport) { return _dcd_controller[rhport].is_highspeed; } + +// DEVCMDSTAT mixes RW fields with write-1-to-clear latches (SETUP + the 3 change bits): a blind +// RMW writes a pending latch back as 1 and silently clears it (a SETUP eaten this way strands +// EP0). Mask the latches on every update; pass one in set_mask only to clear it. +TU_ATTR_ALWAYS_INLINE static inline void devcmdstat_update(dcd_registers_t* dcd_reg, + uint32_t clear_mask, uint32_t set_mask) { + const uint32_t v = dcd_reg->DEVCMDSTAT & ~(DEVCMDSTAT_W1C_MASK | clear_mask); + dcd_reg->DEVCMDSTAT = v | set_mask; +} + //--------------------------------------------------------------------+ // CONTROLLER API //--------------------------------------------------------------------+ @@ -299,8 +304,10 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { dcd_reg->DATABUFSTART = tu_align((uint32_t) &_dcd, TU_BIT(22)); // 22-bit alignment dcd_reg->INTSTAT = dcd_reg->INTSTAT; // clear all pending interrupt dcd_reg->INTEN = INT_DEVICE_STATUS_MASK; - dcd_reg->DEVCMDSTAT |= DEVCMDSTAT_DEVICE_ENABLE_MASK | DEVCMDSTAT_DEVICE_CONNECT_MASK | - DEVCMDSTAT_RESET_CHANGE_MASK | DEVCMDSTAT_CONNECT_CHANGE_MASK | DEVCMDSTAT_SUSPEND_CHANGE_MASK; + // deliberately clear every latch (incl. a SETUP left by a bootloader/warm start) for a + // deterministic init state + devcmdstat_update(dcd_reg, 0, DEVCMDSTAT_DEVICE_ENABLE_MASK | DEVCMDSTAT_DEVICE_CONNECT_MASK | + DEVCMDSTAT_W1C_MASK); NVIC_ClearPendingIRQ(_dcd_controller[rhport].irqnum); @@ -324,8 +331,7 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) // Response with status first before changing device address dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0, false); - dcd_reg->DEVCMDSTAT &= ~DEVCMDSTAT_DEVICE_ADDR_MASK; - dcd_reg->DEVCMDSTAT |= dev_addr; + devcmdstat_update(dcd_reg, DEVCMDSTAT_DEVICE_ADDR_MASK, dev_addr); } void dcd_remote_wakeup(uint8_t rhport) @@ -336,13 +342,13 @@ void dcd_remote_wakeup(uint8_t rhport) void dcd_connect(uint8_t rhport) { dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; - dcd_reg->DEVCMDSTAT |= DEVCMDSTAT_DEVICE_CONNECT_MASK; + devcmdstat_update(dcd_reg, 0, DEVCMDSTAT_DEVICE_CONNECT_MASK); } void dcd_disconnect(uint8_t rhport) { dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; - dcd_reg->DEVCMDSTAT &= ~DEVCMDSTAT_DEVICE_CONNECT_MASK; + devcmdstat_update(dcd_reg, DEVCMDSTAT_DEVICE_CONNECT_MASK, 0); } void dcd_sof_enable(uint8_t rhport, bool en) @@ -356,13 +362,37 @@ void dcd_sof_enable(uint8_t rhport, bool en) //--------------------------------------------------------------------+ // DCD Endpoint Port //--------------------------------------------------------------------+ +// Retire a still-armed (Active) endpoint before reconfiguring it (reopen across SET_INTERFACE). +// UM11126 §41.7.6/§41.8.3: write EPSKIP and wait for hardware to clear the bit, then Active is +// safe to clear. EPSKIP raises the endpoint interrupt as it clears Active, delivered as a +// (partial) transfer completion. Here that is sanctioned — usbd_edpt_close() documents "in +// progress transfers may be delivered after this call", and that completion is what clears the +// stale usbd busy flag (ISO_ALLOC close is a no-op) so the class can re-arm the reopened +// endpoint. NOT for the stall/iso-activate paths: there the class re-arms from the completion +// callback and the endpoint ends up Active+Stall, which never sends a STALL handshake (usbtest +// case 13 regression on LPC11u37) — those paths must clear Active directly instead. +// Bounded: hardware clears EPSKIP within a (micro)frame. +static void edpt_skip_active(uint8_t rhport, uint8_t ep_id) { + ep_cmd_sts_t* ep_cs = get_ep_cs(ep_id); + if ( ep_cs[0].cmd_sts.active || ep_cs[1].cmd_sts.active ) { + dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; + dcd_reg->EPSKIP |= TU_BIT(ep_id); + uint32_t guard = IP3511_EPSKIP_SPIN; + while ( (dcd_reg->EPSKIP & TU_BIT(ep_id)) && guard-- ) {} + } + ep_cs[0].cmd_sts.active = ep_cs[1].cmd_sts.active = 0; +} + void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { (void) rhport; - // TODO cannot able to STALL Control OUT endpoint !!!!! FIXME try some walk-around uint8_t const ep_id = ep_addr2id(ep_addr); - _dcd.ep[ep_id][0].cmd_sts.stall = 1; + // Clear Active directly before setting Stall (no EPSKIP — see edpt_skip_active): the hardware + // services an armed buffer instead of returning STALL, so a halt requested while a transfer is + // queued would not actually stall the endpoint (usbtest case 13). + _dcd.ep[ep_id][0].cmd_sts.active = 0; + _dcd.ep[ep_id][0].cmd_sts.stall = 1; } void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) @@ -371,9 +401,17 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) uint8_t const ep_id = ep_addr2id(ep_addr); + // Preserve rf_tv: for non-control endpoints it is a TYPE bit, not the toggle value (UM11126: + // T=1 + RF 1/0 = interrupt/iso). Zeroing it here turned HS periodic interrupt endpoints into + // isochronous - no handshake on OUT, dead IN (usbtest cases 25/26 on lpc55 HS port). + // TODO implement the Errata LPC546xx USB.13 work-around (same semantics in UM11126): with RF/TV preserved at 1, TR + // loads the toggle from TV, so an HS interrupt endpoint restarts on DATA1 after clear-halt and + // the host discards one packet as a retransmission. The documented workaround needs an + // interrupt-on-NAK state machine (park as generic TR=1/TV=0, wait for a NAKed token to latch + // toggle 0 via EPTOGGLE, restore the type) - deferred; one lost packet beats the fully broken + // endpoint the old rf_tv clear caused. _dcd.ep[ep_id][0].cmd_sts.stall = 0; _dcd.ep[ep_id][0].cmd_sts.toggle_reset = 1; - _dcd.ep[ep_id][0].cmd_sts.rf_tv = 0; } bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) @@ -381,9 +419,15 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) //------------- Prepare Queue Head -------------// uint8_t ep_id = ep_addr2id(p_endpoint_desc->bEndpointAddress); ep_cmd_sts_t* ep_cs = get_ep_cs(ep_id); + dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; - // Check if endpoint is available - TU_ASSERT( ep_cs[0].cmd_sts.disable && ep_cs[1].cmd_sts.disable ); + // usbd_edpt_close() is a no-op on ISO_ALLOC ports, so an endpoint a class closed then reopened + // across SET_INTERFACE (e.g. the video notification or audio streaming endpoint) is still armed + // here rather than disabled. Retire it (edpt_skip_active) before reconfiguring. + if ( !(ep_cs[0].cmd_sts.disable && ep_cs[1].cmd_sts.disable) ) { + edpt_skip_active(rhport, ep_id); + ep_cs[0].cmd_sts.disable = ep_cs[1].cmd_sts.disable = 1; + } edpt_reset(rhport, ep_id); @@ -408,7 +452,6 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) } // Enable EP interrupt - dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; dcd_reg->INTEN |= TU_BIT(ep_id); return true; @@ -418,34 +461,40 @@ void dcd_edpt_close_all (uint8_t rhport) { for (uint8_t ep_id = 0; ep_id < 2*_dcd_controller[rhport].ep_pairs; ++ep_id) { - _dcd.ep[ep_id][0].cmd_sts.active = _dcd.ep[ep_id][0].cmd_sts.active = 0; // TODO proper way is to EPSKIP then wait ep[][].active then write ep[][].disable (see table 778 in LPC55S69 Use Manual) + _dcd.ep[ep_id][0].cmd_sts.active = _dcd.ep[ep_id][1].cmd_sts.active = 0; // TODO proper way is to EPSKIP then wait ep[][].active then write ep[][].disable (see table 778 in LPC55S69 Use Manual) _dcd.ep[ep_id][0].cmd_sts.disable = _dcd.ep[ep_id][1].cmd_sts.disable = 1; } } -void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) -{ - (void) rhport; - +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { + (void) largest_packet_size; + // Reserve the endpoint command/status entry once (persists across altsetting changes); the + // buffer pointer is filled per-transfer, so nothing to pre-allocate. Mirrors the ISO branch of + // dcd_edpt_open(). uint8_t ep_id = ep_addr2id(ep_addr); - _dcd.ep[ep_id][0].cmd_sts.active = _dcd.ep[ep_id][0].cmd_sts.active = 0; // TODO proper way is to EPSKIP then wait ep[][].active then write ep[][].disable (see table 778 in LPC55S69 Use Manual) - _dcd.ep[ep_id][0].cmd_sts.disable = _dcd.ep[ep_id][1].cmd_sts.disable = 1; -} + ep_cmd_sts_t* ep_cs = get_ep_cs(ep_id); + TU_ASSERT( ep_cs[0].cmd_sts.disable && ep_cs[1].cmd_sts.disable ); -#if 0 -bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { - (void)rhport; - (void)ep_addr; - (void)largest_packet_size; - return false; + edpt_reset(rhport, ep_id); + ep_cs[0].cmd_sts.type = 1; // ISO + + dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; + dcd_reg->INTEN |= TU_BIT(ep_id); + return true; } bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { - (void)rhport; - (void)desc_ep; - return false; + // (Re)activate on altsetting selection: abort a transfer still armed from the previous + // altsetting (the hardware keeps servicing an Active buffer across SET_INTERFACE, fighting the + // fresh transfer the class queues), clear stall and reset the data toggle. Direct Active=0, not + // EPSKIP (see edpt_skip_active). The class re-arms via dcd_edpt_xfer(). + uint8_t ep_id = ep_addr2id(desc_ep->bEndpointAddress); + ep_cmd_sts_t* ep_cs = get_ep_cs(ep_id); + ep_cs[0].cmd_sts.active = 0; + ep_cs[1].cmd_sts.active = 0; + dcd_edpt_clear_stall(rhport, desc_ep->bEndpointAddress); + return true; } -#endif static void prepare_ep_xfer(uint8_t rhport, uint8_t ep_id, uint16_t buf_offset, uint16_t total_bytes) { uint16_t nbytes; @@ -518,7 +567,7 @@ static void bus_reset(uint8_t rhport) dcd_reg->EPSKIP = 0xFFFFFFFF; dcd_reg->INTSTAT = dcd_reg->INTSTAT; // clear all pending interrupt - dcd_reg->DEVCMDSTAT |= DEVCMDSTAT_SETUP_RECEIVED_MASK; // clear setup received interrupt + devcmdstat_update(dcd_reg, 0, DEVCMDSTAT_SETUP_RECEIVED_MASK); // clear setup received interrupt dcd_reg->INTEN = INT_DEVICE_STATUS_MASK | TU_BIT(0) | TU_BIT(1); // enable device status & control endpoints } @@ -577,18 +626,25 @@ void dcd_int_handler(uint8_t rhport) { dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; - uint32_t const cmd_stat = dcd_reg->DEVCMDSTAT; - uint32_t int_status = dcd_reg->INTSTAT; - int_status &= dcd_reg->INTEN; + int_status &= dcd_reg->INTEN; dcd_reg->INTSTAT = int_status; // Acknowledge handled interrupt if (int_status == 0) return; + // Snapshot after the INTSTAT ack: latch bits persist (RWC) so nothing is lost, while the reverse + // order could consume INTSTAT bit0 for a SETUP not yet visible in the snapshot - stranding the + // SETUP (INTSTAT is edge-latched) and feeding bit0 to process_xfer_isr as a bogus completion. + uint32_t const cmd_stat = dcd_reg->DEVCMDSTAT; + //------------- Device Status -------------// if ( int_status & INT_DEVICE_STATUS_MASK ) { - dcd_reg->DEVCMDSTAT |= DEVCMDSTAT_RESET_CHANGE_MASK | DEVCMDSTAT_CONNECT_CHANGE_MASK | DEVCMDSTAT_SUSPEND_CHANGE_MASK; + // clear only the change latches observed in the snapshot: one latched by hardware between the + // snapshot and this write would be acknowledged unseen (its DEV_INT re-latches and dispatches + // next pass instead) + devcmdstat_update(dcd_reg, 0, cmd_stat & + (DEVCMDSTAT_RESET_CHANGE_MASK | DEVCMDSTAT_CONNECT_CHANGE_MASK | DEVCMDSTAT_SUSPEND_CHANGE_MASK)); if ( cmd_stat & DEVCMDSTAT_RESET_CHANGE_MASK) // bus reset { @@ -633,15 +689,43 @@ void dcd_int_handler(uint8_t rhport) _dcd.ep[0][0].cmd_sts.active = _dcd.ep[1][0].cmd_sts.active = 0; _dcd.ep[0][0].cmd_sts.stall = _dcd.ep[1][0].cmd_sts.stall = 0; - dcd_reg->DEVCMDSTAT |= DEVCMDSTAT_SETUP_RECEIVED_MASK; + // UM flow: ack the latch FIRST, then read the payload. This IP has no setup lockout, so a + // back-to-back SETUP can overwrite _dcd.setup_packet at any time - but with the latch already + // released, any such overwrite re-latches SETUP_RECEIVED and is redelivered (worst case a + // superseded duplicate, absorbed by usbd's queued-setup counter). The reverse order can + // consume the newer SETUP's latch unseen and lose it. + devcmdstat_update(dcd_reg, 0, DEVCMDSTAT_SETUP_RECEIVED_MASK); + + // UM11126 Fig 163 (control EP0 flowchart) requires clearing the EP0IN interrupt here: a + // control IN completion latched before this SETUP must not reach usbd after it, where it + // would be applied to the new request and arm its status stage early. EP0OUT goes with it - + // bit0 is set by SETUP reception too, and left set it would replay next pass as a phantom + // completion. Neither can discard live work: the SETUP latch NAKs all EP0 traffic until the + // update above, and both EP0 Active bits were cleared a few lines up. + dcd_reg->INTSTAT = TU_BIT(0) | TU_BIT(1); - dcd_event_setup_received(rhport, _dcd.setup_packet, true); + // Copied a byte at a time rather than with memcpy: C orders volatile accesses only against + // each other, so a non-volatile copy of this buffer may be sunk below the guard read that + // follows - gcc does exactly that at -O2 and -O3, leaving only -Os correct. + uint8_t setup_copy[8]; + for (uint8_t i = 0; i < sizeof(setup_copy); i++) { + setup_copy[i] = _dcd.setup_packet[i]; + } + + // a SETUP that raced in after the acks (its bit0 consumed above) makes this copy suspect: + // its latch is visible again, so re-raise the endpoint interrupt and let the next pass + // deliver the newer payload rather than passing up bytes that may be torn between the two + if (dcd_reg->DEVCMDSTAT & DEVCMDSTAT_SETUP_RECEIVED_MASK) { + dcd_reg->INTSETSTAT = TU_BIT(0); + } else { + dcd_event_setup_received(rhport, setup_copy, true); + } // keep waiting for next setup prepare_setup_packet(rhport); - // clear bit0 - int_status = tu_bit_clear(int_status, 0); + // drop both EP0 bits: acked above, and neither belongs to the request this SETUP starts + int_status &= ~(TU_BIT(0) | TU_BIT(1)); } // Endpoint transfer complete interrupt diff --git a/src/portable/nxp/lpc_ip3516/hcd_lpc_ip3516.c b/src/portable/nxp/lpc_ip3516/hcd_lpc_ip3516.c index c9810f51c..b9ad172c5 100644 --- a/src/portable/nxp/lpc_ip3516/hcd_lpc_ip3516.c +++ b/src/portable/nxp/lpc_ip3516/hcd_lpc_ip3516.c @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2025 HiFiPhile (Zixun LI) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2025 HiFiPhile (Zixun LI) + * SPDX-FileCopyrightText: Copyright (c) 2025 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/nxp/lpc_ip3516/hcd_lpc_ip3516.h b/src/portable/nxp/lpc_ip3516/hcd_lpc_ip3516.h index 5214c18ae..2b8758a9e 100644 --- a/src/portable/nxp/lpc_ip3516/hcd_lpc_ip3516.h +++ b/src/portable/nxp/lpc_ip3516/hcd_lpc_ip3516.h @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2025 HiFiPhile (Zixun LI) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2025 HiFiPhile (Zixun LI) + * SPDX-FileCopyrightText: Copyright (c) 2025 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c index 4b248d9e6..2a174e46c 100644 --- a/src/portable/ohci/ohci.c +++ b/src/portable/ohci/ohci.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -397,7 +378,7 @@ static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr) { ohci_ed_t* p_prev = p_head; while (p_prev->next) { - ohci_ed_t* ed = (ohci_ed_t*)_virt_addr((void*)p_prev->next); + ohci_ed_t* ed = hcd_dcache_uncached((ohci_ed_t*)_virt_addr((void*)p_prev->next)); if (ed->w0.dev_addr == dev_addr) { // Prevent Host Controller from processing this ED while we remove it @@ -406,12 +387,28 @@ static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr) { // unlink ed, will also move up p_prev p_prev->next = ed->next; - // point the removed ED's next pointer to list head to make sure HC can always safely move away from this ED - ed->next = (uint32_t)_phys_addr(p_head); - ed->w0.used = 0; - ed->w0.skip = 0; + // Control endpoints (EP number 0) are statically allocated with the device which are only reused + // after connection of another device long after HC has finished with them now, these can be freed immediately. + if (ed->w0.ep_number != 0) { + // Wait until the next frame before reclaiming the ED and its TDs. Set the deadline before + // publishing is_reclaiming so a pending SOF IRQ cannot use an older deadline for this ED. + ohci_data.reclaim_frame = (uint16_t)(OHCI_REG->frame_number + 1); + ed->w0.is_reclaiming = 1; + + // 5.2.7.1.2 Removing. Disable list processing for bulk + if (p_head == p_ed_head[TUSB_XFER_BULK]) { + OHCI_REG->control &= ~OHCI_CONTROL_LIST_BULK_ENABLE_MASK; + } + + // Temporarily enable SOF IRQ. Clear any pending SOF first to wait for the next frame. + OHCI_REG->interrupt_status = OHCI_INT_SOF_MASK; + OHCI_REG->interrupt_enable = OHCI_INT_SOF_MASK; + } else { + ed->w0.used = 0; + ed->w0.skip = 0; + } } else { - p_prev = (ohci_ed_t*)_virt_addr((void*)p_prev->next); + p_prev = ed; } } } @@ -419,6 +416,7 @@ static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr) { static ohci_gtd_t* gtd_find_free(void) { for (uint8_t i = 0; i < GTD_MAX; i++) { if (!ohci_data.gtd_pool[i].used) { + ohci_data.gtd_pool[i].used = 1; return &ohci_data.gtd_pool[i]; } } @@ -671,6 +669,60 @@ void hcd_int_handler(uint8_t hostid, bool in_isr) { // Disable MIE as per OHCI spec 5.3 OHCI_REG->interrupt_disable = OHCI_INT_MASTER_ENABLE_MASK; + // Start of frame (SOF). Signed subtraction handles frame number rollover and delayed interrupts. + if ((int_status & OHCI_INT_SOF_MASK) && + ((int16_t)((uint16_t)OHCI_REG->frame_number - ohci_data.reclaim_frame) >= 0)) { + OHCI_REG->interrupt_disable = OHCI_INT_SOF_MASK; + + bool re_enable_lists = false; + + for (size_t i = 0; i < ED_MAX; i++) { + ohci_ed_t* ed = hcd_dcache_uncached(&ohci_data.ed_pool[i]); + if (ed->w0.used && ed->w0.is_reclaiming) { + TU_ASSERT(ed->w0.skip == 1, ); + TU_ASSERT(ed->w0.ep_number != 0, ); + + // Reclaim orphaned TDs + uint32_t td_addr = ed->td_head.address & ~0x0F; + while (td_addr) { + if (!ed->w0.is_iso) { + ohci_gtd_t *gtd = (ohci_gtd_t*)_virt_addr((void*)(uintptr_t)td_addr); + gtd->used = 0; + } else { + // TODO: Free ITD once implemented + } + + if (td_addr == ed->td_tail) { + break; + } + td_addr = ((ohci_td_item_t*)_virt_addr((void*)(uintptr_t)td_addr))->next; + } + + ed->w0.is_reclaiming = 0; + ed->w0.used = 0; + ed->w0.skip = 0; + + re_enable_lists = true; + } + } + + if (re_enable_lists) { + // 5.2.7.1.2 Removing + // Reset current ED pointers and re-enable lists + // Once the next frame has started, the HcControlCurrentED or HcBulkCurrentED register should be adjusted so + // that it does not point to the Endpoint Descriptor being removed (for simplicity you may just write + // a zero to the register); + if (!(OHCI_REG->control & OHCI_CONTROL_LIST_CONTROL_ENABLE_MASK)) { + OHCI_REG->control_current_ed = 0; + OHCI_REG->control |= OHCI_CONTROL_LIST_CONTROL_ENABLE_MASK; + } + if (!(OHCI_REG->control & OHCI_CONTROL_LIST_BULK_ENABLE_MASK)) { + OHCI_REG->bulk_current_ed = 0; + OHCI_REG->control |= OHCI_CONTROL_LIST_BULK_ENABLE_MASK; + } + } + } + // Frame number overflow if (int_status & OHCI_INT_FRAME_OVERFLOW_MASK) { ohci_data.frame_number_hi++; diff --git a/src/portable/ohci/ohci.h b/src/portable/ohci/ohci.h index d9ebe1d54..e28c6404f 100644 --- a/src/portable/ohci/ohci.h +++ b/src/portable/ohci/ohci.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -126,7 +107,8 @@ typedef union { // HCD: make use of 5 reserved bits uint32_t used : 1; uint32_t is_interrupt_xfer : 1; - uint32_t : 3; + uint32_t is_reclaiming : 1; + uint32_t : 2; }; uint32_t value; } ohci_ed_word0_t; @@ -201,6 +183,7 @@ typedef struct TU_ATTR_ALIGNED(256) { gtd_extra_data_t gtd_extra[GTD_MAX]; volatile uint16_t frame_number_hi; + volatile uint16_t reclaim_frame; } ohci_data_t; //--------------------------------------------------------------------+ diff --git a/src/portable/ohci/ohci_nxp.h b/src/portable/ohci/ohci_nxp.h index 9cba05e95..de06e4569 100644 --- a/src/portable/ohci/ohci_nxp.h +++ b/src/portable/ohci/ohci_nxp.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2025 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2025 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c b/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c index 78df2b6a6..2830c0f63 100644 --- a/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c +++ b/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2018, hathach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2018, Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c b/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c index 90eb920e0..8a7722fb0 100644 --- a/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c +++ b/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c index 2b6bbc43b..564ded535 100644 --- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * SPDX-FileCopyrightText: Copyright (c) 2020 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -405,6 +387,9 @@ bool dcd_deinit(uint8_t rhport) { reset_block(RESETS_RESET_USBCTRL_BITS); unreset_block_wait(RESETS_RESET_USBCTRL_BITS); + // Release allocated resources + rp2usb_deinit(); + return true; } @@ -568,9 +553,46 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { if (epnum != 0) { struct hw_endpoint* ep = hw_endpoint_get(epnum, dir); - ep->next_pid = 0; // reset data toggle - io_rw_32 *buf_reg = get_buf_ctrl(epnum, dir); - *buf_reg = 0; + + if (ep->state == EPSTATE_ACTIVE) { + // Clear-halt on an endpoint with an in-flight transfer is used as a data-toggle reset + // (e.g. usbtest case 29) rather than to recover from a real stall (a stall aborts the + // transfer, leaving the endpoint IDLE). Abort and re-issue the transfer with the toggle + // reset to DATA0 so it still completes and releases the usbd claim, instead of silently + // dropping it and starving the endpoint. Save the buffer/length before the abort clears them. + uint8_t* user_buf = ep->user_buf; + uint16_t remaining = ep->remaining_len; + const uint16_t xferred = ep->xferred_len; // bytes already moved on this submission + io_rw_32 *ep_reg = get_ep_ctrl(epnum, dir); + io_rw_32 *buf_reg = get_buf_ctrl(epnum, dir); + // bufctrl_prepare16() subtracts each armed buffer's length from remaining_len when arming, + // for BOTH directions, before the host has drained (IN) or filled (OUT) it. The abort below + // discards those still-armed buffers, so rewind remaining_len by their lengths or the re-issue + // is short by 1-2 packets. IN additionally advances user_buf as packets are copied into DPRAM, + // so its pointer must rewind too; OUT copies out only on completion, so its pointer is intact. + const uint32_t bc = *buf_reg; + uint16_t staged = 0; + if (bc & USB_BUF_CTRL_AVAIL) { + staged = (uint16_t)(bc & USB_BUF_CTRL_LEN_MASK); + } + if ((bc >> 16) & USB_BUF_CTRL_AVAIL) { + staged = (uint16_t)(staged + ((bc >> 16) & USB_BUF_CTRL_LEN_MASK)); + } + remaining = (uint16_t)(remaining + staged); + if (dir == TUSB_DIR_IN) { + user_buf -= staged; + } + hw_endpoint_abort_xfer(ep); // safe abort (handles RP2040-E2), resets ep transfer state + ep->next_pid = 0; // DATA0 + rp2usb_xfer_start(ep, ep_reg, buf_reg, user_buf, NULL, remaining); + // rp2usb_xfer_start() zeroes xferred_len; add back what the aborted transfer already moved so + // the eventual completion reports the full length, not just the post-clear-halt remainder. + ep->xferred_len += xferred; + } else { + ep->next_pid = 0; // reset data toggle + io_rw_32 *buf_reg = get_buf_ctrl(epnum, dir); + *buf_reg = 0; // clear the stall response + } } } diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c index 064834efb..a04890835 100644 --- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c @@ -1,27 +1,7 @@ - /* - * The MIT License (MIT) - * - * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. - * Copyright (c) 2021 Ha Thach (tinyusb.org) for Double Buffered - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * SPDX-FileCopyrightText: Copyright (c) 2021 Ha Thach (tinyusb.org) for Double Buffered + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -447,6 +427,10 @@ bool hcd_deinit(uint8_t rhport) { irq_remove_handler(USBCTRL_IRQ, hcd_rp2040_irq); reset_block(RESETS_RESET_USBCTRL_BITS); unreset_block_wait(RESETS_RESET_USBCTRL_BITS); + + // Release allocated resources + rp2usb_deinit(); + return true; } diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c index 83ac48ec2..96b335bd3 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.c +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c @@ -1,26 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. - * Copyright (c) 2021 Ha Thach (tinyusb.org) for Double Buffered - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * SPDX-FileCopyrightText: Copyright (c) 2021 Ha Thach (tinyusb.org) for Double Buffered + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -104,6 +85,10 @@ void rp2usb_init(void) { critical_section_init(&rp2usb_lock); } +void rp2usb_deinit(void) { + critical_section_deinit(&rp2usb_lock); +} + void __tusb_irq_path_func(rp2usb_reset_transfer)(hw_endpoint_t *ep) { ep->state = EPSTATE_IDLE; ep->remaining_len = 0; @@ -195,10 +180,15 @@ void __tusb_irq_path_func(rp2usb_buffer_start)(hw_endpoint_t *ep, io_rw_32 *ep_r // Note: device EP0 does not have an endpoint control register if (ep_reg != NULL) { uint32_t ep_ctrl = *ep_reg; + // Isochronous endpoints get a single DPRAM buffer (hw_endpoint_open only double-sizes BULK), so + // they must never be double-buffered here even when a transfer spans multiple packets, or buffer + // 1 (at dpram_buf+64) would spill into the next endpoint's DPRAM. (Never true for BULK, so the + // double-buffered bulk path is unaffected.) + const bool is_iso = (((ep_ctrl >> EP_CTRL_BUFFER_TYPE_LSB) & 0x3u) == TUSB_XFER_ISOCHRONOUS); #if CFG_TUH_ENABLED - const bool force_single = (rp2usb_is_host_mode() && ep->interrupt_num > 0); + const bool force_single = is_iso || (rp2usb_is_host_mode() && ep->interrupt_num > 0); #else - const bool force_single = false; + const bool force_single = is_iso; #endif if (ep->remaining_len && !force_single) { diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.h b/src/portable/raspberrypi/rp2040/rp2040_usb.h index 8ebc3e3fc..e5a54007c 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.h +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.h @@ -1,3 +1,11 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * SPDX-FileCopyrightText: Copyright (c) 2020 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT + * + * This file is part of the TinyUSB stack. + */ + #ifndef RP2040_COMMON_H_ #define RP2040_COMMON_H_ @@ -139,6 +147,7 @@ extern volatile uint32_t e15_last_sof; #endif void rp2usb_init(void); +void rp2usb_deinit(void); // if usb hardware is in host mode TU_ATTR_ALWAYS_INLINE static inline bool rp2usb_is_host_mode(void) { diff --git a/src/portable/renesas/rusb2/dcd_rusb2.c b/src/portable/renesas/rusb2/dcd_rusb2.c index adbb53787..c93bab05e 100644 --- a/src/portable/renesas/rusb2/dcd_rusb2.c +++ b/src/portable/renesas/rusb2/dcd_rusb2.c @@ -1,26 +1,8 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2020 Koji Kitayama - * Portions copyrighted (c) 2021 Roland Winistoerfer - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2020 Koji Kitayama + * SPDX-FileCopyrightText: Portions copyrighted (c) 2021 Roland Winistoerfer + * SPDX-FileCopyrightText: Copyright (c) 2020 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -46,6 +28,9 @@ typedef struct { uint8_t ep; /* an assigned endpoint address */ uint8_t ff; /* `buf` is TU_FUFO or POD */ + bool queued; /* a transfer is submitted and not yet completed (independent of `buf`, which is + NULL for a zero-length read) -- used to decide clear-stall re-arm */ + bool zlp_pending; /* a zero-length IN packet couldn't be queued at submit (FIFO full); retry on BRDY */ } pipe_state_t; typedef struct @@ -58,6 +43,7 @@ typedef struct static dcd_data_t _dcd; + //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ @@ -139,9 +125,19 @@ static uint16_t edpt_max_packet_size(rusb2_reg_t *rusb, unsigned num) { return rusb->PIPEMAXP; } -static inline void pipe_wait_for_ready(rusb2_reg_t * rusb, unsigned num) { - while ( rusb->D0FIFOSEL_b.CURPIPE != num ) {} - while ( !rusb->D0FIFOCTR_b.FRDY ) {} +// Select the D0FIFO for `num` and wait until its buffer is ready for CPU access. Both flags +// normally settle within a few cycles (the pipe was just armed, or a BRDY freed a plane). But an +// IN pipe whose double buffer is already full stalls FRDY until the host drains it, and a +// no-handshake iso IN endpoint the host has stopped polling never drains at all — so FRDY would +// hang forever. This runs with the USB IRQ masked, so a naked spin freezes the whole stack; bound +// it and let the caller abort the FIFO access. Returns false on timeout. +#define RUSB2_FIFO_READY_SPIN 100000u +static inline bool pipe_wait_for_ready(rusb2_reg_t *rusb, unsigned num) { + uint32_t spin = RUSB2_FIFO_READY_SPIN; + while ( rusb->D0FIFOSEL_b.CURPIPE != num ) { if (!spin--) return false; } + spin = RUSB2_FIFO_READY_SPIN; + while ( !rusb->D0FIFOCTR_b.FRDY ) { if (!spin--) return false; } + return true; } //--------------------------------------------------------------------+ @@ -195,6 +191,15 @@ static bool pipe0_xfer_out(rusb2_reg_t *rusb) { pipe_state_t *pipe = &_dcd.pipe[0]; const unsigned rem = pipe->remaining; + // BRDY with no armed transfer: a back-to-back data-stage packet beat the PID=NAK below (the + // host has already ACKed it). Park it in the DCP buffer — an unread buffer NAKs further OUTs — + // and let process_pipe0_xfer deliver it when usbd arms the next chunk. BCLR here would silently + // drop the packet and shift every later chunk by one (usbtest ctrl_out corruption at ra4m1). + if (pipe->buf == NULL && rem == 0) { + rusb->DCPCTR = RUSB2_PIPE_CTR_PID_NAK; + return false; + } + const uint16_t mps = edpt0_max_packet_size(rusb); const uint16_t vld = rusb->CFIFOCTR_b.DTLN; const uint16_t len = tu_min16(tu_min16(rem, mps), vld); @@ -219,6 +224,12 @@ static bool pipe0_xfer_out(rusb2_reg_t *rusb) { pipe->remaining = rem - len; if ((len < mps) || (rem == len)) { pipe->buf = NULL; + // Flow-control the single-buffer control pipe: NAK further OUT until usbd arms the next + // data-stage chunk. usbd receives a multi-packet control-OUT one CFG_TUD_ENDPOINT0_SIZE + // packet per submit; without this the DCP auto-accepts the next back-to-back packet into the + // just-emptied buffer and the following BRDY (remaining==0) BCLR-discards it, dropping 64 + // bytes mid-transfer (e.g. usbtest ctrl_out 512B). RA4M1 UM R01UH0887 DCPCTR.PID. + rusb->DCPCTR = RUSB2_PIPE_CTR_PID_NAK; return true; } @@ -244,7 +255,12 @@ static bool pipe_xfer_in(rusb2_reg_t* rusb, unsigned num) } const uint16_t mps = edpt_max_packet_size(rusb, num); - pipe_wait_for_ready(rusb, num); + if (!pipe_wait_for_ready(rusb, num)) { + // Buffer never came ready (double-buffered IN pipe full, host not draining). Drop this load; + // the transfer stays pending and is retried when a BRDY frees a plane or the pipe is re-armed. + rusb->D0FIFOSEL = 0; + return false; + } uint16_t len = tu_min16(rem, mps); void *buf = pipe->buf; @@ -285,7 +301,10 @@ static bool pipe_xfer_out(rusb2_reg_t* rusb, unsigned num) rusb->D0FIFOSEL = fifo_sel; const uint16_t mps = edpt_max_packet_size(rusb, num); - pipe_wait_for_ready(rusb, num); + if (!pipe_wait_for_ready(rusb, num)) { + rusb->D0FIFOSEL = 0; + return false; // FIFO not ready; leave the receive pending (BRDY re-enters when data arrives) + } const uint16_t vld = (uint16_t)rusb->D0FIFOCTR_b.DTLN; const uint16_t len = tu_min16(tu_min16(rem, mps), vld); @@ -351,7 +370,16 @@ static void process_status_completion(uint8_t rhport) dcd_event_xfer_complete(rhport, ep_addr, 0, XFER_RESULT_SUCCESS, true); } -static bool process_pipe0_xfer(rusb2_reg_t *rusb, int buffer_type, uint8_t ep_addr, void *buffer, +// Report a completed transfer on `num` and reset its bookkeeping. Single completion path for the +// BRDY handler and the EP0 parked-packet drain, so they can't diverge (e.g. on clearing `queued`). +static void pipe_xfer_complete(uint8_t rhport, unsigned num, bool in_isr) { + pipe_state_t *pipe = &_dcd.pipe[num]; + pipe->queued = false; + dcd_event_xfer_complete(rhport, pipe->ep, pipe->length - pipe->remaining, + XFER_RESULT_SUCCESS, in_isr); +} + +static bool process_pipe0_xfer(uint8_t rhport, rusb2_reg_t *rusb, int buffer_type, uint8_t ep_addr, void *buffer, uint16_t total_bytes) { uint16_t fifo_sel = (rusb2_is_highspeed_reg(rusb) ? RUSB2_FIFOSEL_MBW_32BIT : RUSB2_FIFOSEL_MBW_16BIT) | FIFOSEL_BIGEND; @@ -377,6 +405,15 @@ static bool process_pipe0_xfer(rusb2_reg_t *rusb, int buffer_type, uint8_t ep_ad /* IN */ TU_ASSERT(rusb->DCPCTR_b.BSTS && (rusb->USBREQ & 0x80)); pipe0_xfer_in(rusb); + } else if (rusb->CFIFOCTR_b.DTLN > 0) { + /* OUT: a back-to-back packet parked by pipe0_xfer_out already sits in the DCP buffer (its + BRDY has fired and been cleared) — deliver it into this chunk now; no new BRDY will come + for it. Runs with the USB IRQ masked (dcd_edpt_xfer). Detected via the hardware DTLN + rather than a driver flag: the BCLR at SETUP/bus-reset then self-heals any parked state. */ + if (pipe0_xfer_out(rusb)) { + pipe_xfer_complete(rhport, 0, false); + return true; // PID stays NAK (set by pipe0_xfer_out) until the next chunk is armed + } } rusb->DCPCTR = RUSB2_PIPE_CTR_PID_BUF; } else { @@ -388,6 +425,24 @@ static bool process_pipe0_xfer(rusb2_reg_t *rusb, int buffer_type, uint8_t ep_ad return true; } +// Queue a zero-length IN packet. Returns false if the FIFO buffer wasn't free (double-buffered pipe +// full, host not draining) so BVAL couldn't be written -- the caller retries on the next BRDY. +static bool pipe_zlp_in(rusb2_reg_t *rusb, unsigned num) { + rusb->D0FIFOSEL = (uint16_t) num; + const bool ready = pipe_wait_for_ready(rusb, num); + if (ready) { + rusb->D0FIFOCTR = RUSB2_CFIFOCTR_BVAL_Msk; + } + rusb->D0FIFOSEL = 0; + // deselect completes within a few bus cycles (not host-dependent), but bound it anyway: this + // runs with the USB IRQ masked, where any stuck spin freezes the whole stack + uint32_t spin = RUSB2_FIFO_READY_SPIN; + while (rusb->D0FIFOSEL_b.CURPIPE) { + if (!spin--) { break; } + } + return ready; +} + static bool process_pipe_xfer(rusb2_reg_t* rusb, int buffer_type, uint8_t ep_addr, void* buffer, uint16_t total_bytes) { const unsigned epn = tu_edpt_number(ep_addr); @@ -397,23 +452,20 @@ static bool process_pipe_xfer(rusb2_reg_t* rusb, int buffer_type, uint8_t ep_add TU_ASSERT(num); pipe_state_t *pipe = &_dcd.pipe[num]; - pipe->ff = buffer_type; - pipe->buf = buffer; - pipe->length = total_bytes; - pipe->remaining = total_bytes; + pipe->ff = buffer_type; + pipe->buf = buffer; + pipe->length = total_bytes; + pipe->remaining = total_bytes; + pipe->queued = true; + pipe->zlp_pending = false; if (dir) { /* IN */ if (total_bytes) { pipe_xfer_in(rusb, num); } else { - /* ZLP */ - rusb->D0FIFOSEL = num; - pipe_wait_for_ready(rusb, num); - rusb->D0FIFOCTR = RUSB2_CFIFOCTR_BVAL_Msk; - rusb->D0FIFOSEL = 0; - /* if CURPIPE bits changes, check written value */ - while (rusb->D0FIFOSEL_b.CURPIPE) {} + /* ZLP: if the FIFO buffer isn't free yet, defer the queue to the next BRDY (see process_pipe_brdy) */ + pipe->zlp_pending = !pipe_zlp_in(rusb, num); } } else { // OUT @@ -436,11 +488,11 @@ static bool process_pipe_xfer(rusb2_reg_t* rusb, int buffer_type, uint8_t ep_add return true; } -static bool process_edpt_xfer(rusb2_reg_t* rusb, int buffer_type, uint8_t ep_addr, void* buffer, uint16_t total_bytes) +static bool process_edpt_xfer(uint8_t rhport, rusb2_reg_t* rusb, int buffer_type, uint8_t ep_addr, void* buffer, uint16_t total_bytes) { const unsigned epn = tu_edpt_number(ep_addr); if (0 == epn) { - return process_pipe0_xfer(rusb, buffer_type, ep_addr, buffer, total_bytes); + return process_pipe0_xfer(rhport, rusb, buffer_type, ep_addr, buffer, total_bytes); } else { return process_pipe_xfer(rusb, buffer_type, ep_addr, buffer, total_bytes); } @@ -466,7 +518,15 @@ static void process_pipe_brdy(uint8_t rhport, unsigned num) if (dir) { /* IN */ - completed = pipe_xfer_in(rusb, num); + if (pipe->zlp_pending) { + // The submit-time ZLP couldn't be queued (FIFO full); a freed buffer plane lets us queue it + // now. Don't report completion until the ZLP is actually queued (and then sent, next BRDY), + // otherwise a spurious BRDY would complete a zero-length IN the host never received. + pipe->zlp_pending = !pipe_zlp_in(rusb, num); + completed = false; + } else { + completed = pipe_xfer_in(rusb, num); + } } else { // OUT if (num) { @@ -476,9 +536,7 @@ static void process_pipe_brdy(uint8_t rhport, unsigned num) } } if (completed) { - dcd_event_xfer_complete(rhport, pipe->ep, - pipe->length - pipe->remaining, - XFER_RESULT_SUCCESS, true); + pipe_xfer_complete(rhport, num, true); // TU_LOG1("C %d %d\r\n", num, pipe->length - pipe->remaining); } } @@ -603,19 +661,8 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { #ifdef RUSB2_SUPPORT_HIGHSPEED if ( rusb2_is_highspeed_rhport(rhport) ) { - rusb->SYSCFG_b.HSE = 1; - - // leave CLKSEL as default (0x11) 24Mhz - - // Power and reset UTMI Phy - uint16_t physet = (rusb->PHYSET | RUSB2_PHYSET_PLLRESET_Msk) & ~RUSB2_PHYSET_DIRPD_Msk; - rusb->PHYSET = physet; - R_BSP_SoftwareDelay((uint32_t) 1, BSP_DELAY_UNITS_MILLISECONDS); - rusb->PHYSET_b.PLLRESET = 0; - - // set UTMI to operating mode and wait for PLL lock confirmation - rusb->LPSTS_b.SUSPENDM = 1; - while (!rusb->PLLSTA_b.PLLLOCK) {} + rusb->SYSCFG_b.HSE = TUD_OPT_HIGH_SPEED ? 1 : 0; // FS-only build: no HS chirp + rusb2_utmi_phy_powerup(rusb); rusb->SYSCFG_b.DRPD = 0; rusb->SYSCFG_b.USBE = 1; @@ -720,10 +767,20 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) if ( !rusb2_is_highspeed_rhport(rhport) && mps > 256) { return false; } + } else if (xfer == TUSB_XFER_INTERRUPT) { + // Interrupt pipes (6-9) have a fixed 64-byte buffer even in high speed (RA6M5 UM 29.1); + // a larger PIPEMAXP would enumerate, then silently truncate every transfer + TU_ASSERT(mps <= 64); } - const unsigned num = find_pipe(xfer); - TU_ASSERT(num); + // Re-opening an endpoint must reuse its pipe: usbd_edpt_close() is a no-op on ISO_ALLOC ports, + // so a class's close/open across SET_INTERFACE (e.g. video's notification endpoint) would + // otherwise allocate a second pipe with the same EPNUM and leak pipes until exhaustion. + unsigned num = _dcd.ep[dir][epn]; + if (num == 0) { + num = find_pipe(xfer); + TU_ASSERT(num); + } _dcd.pipe[num].ep = ep_addr; _dcd.ep[dir][epn] = num; @@ -731,13 +788,12 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) /* setup pipe */ dcd_int_disable(rhport); + rusb->PIPESEL = num; if ( rusb2_is_highspeed_rhport(rhport) ) { - // FIXME shouldn't be after pipe selection and config, also the BUFNMB should be changed - // depending on the allocation scheme + // PIPEBUF is PIPESEL-windowed (RA6M5 UM 29.2.35): write it after selecting the pipe. + // FIXME BUFNMB is a fixed 0x08 for every pipe; a real per-pipe allocation scheme is needed. rusb->PIPEBUF = 0x7C08; } - - rusb->PIPESEL = num; rusb->PIPEMAXP = mps; volatile uint16_t *ctr = get_pipectr(rusb, num); *ctr = RUSB2_PIPE_CTR_ACLRM_Msk | RUSB2_PIPE_CTR_SQCLR_Msk; @@ -766,6 +822,8 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) return true; } +static void edpt_close(uint8_t rhport, uint8_t ep_addr); + void dcd_edpt_close_all(uint8_t rhport) { unsigned i = TU_ARRAY_SIZE(_dcd.pipe); @@ -775,12 +833,14 @@ void dcd_edpt_close_all(uint8_t rhport) if (!ep_addr) { continue; } - dcd_edpt_close(rhport, (uint8_t)ep_addr); + edpt_close(rhport, (uint8_t)ep_addr); } dcd_int_enable(rhport); } -void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) +// Internal helper: on this (ISO_ALLOC) IP the stack no longer calls dcd_edpt_close(); only +// dcd_edpt_close_all() uses it to tear down each pipe. +static void edpt_close(uint8_t rhport, uint8_t ep_addr) { rusb2_reg_t * rusb = RUSB2_REG(rhport); const unsigned epn = tu_edpt_number(ep_addr); @@ -792,24 +852,73 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) *ctr = 0; rusb->PIPESEL = (uint16_t)num; rusb->PIPECFG = 0; - _dcd.pipe[num].ep = 0; + _dcd.pipe[num].ep = 0; + _dcd.pipe[num].queued = false; + _dcd.pipe[num].zlp_pending = false; _dcd.ep[dir][epn] = 0; } -#if 0 bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { - (void)rhport; - (void)ep_addr; - (void)largest_packet_size; - return false; + rusb2_reg_t * rusb = RUSB2_REG(rhport); + const unsigned epn = tu_edpt_number(ep_addr); + const unsigned dir = tu_edpt_dir(ep_addr); + + // Fullspeed ISO is limited to 256 bytes + if (!rusb2_is_highspeed_rhport(rhport) && largest_packet_size > 256) { + return false; + } + + // Reserve an ISO-capable pipe (1 or 2) once; it persists across altsetting changes so + // dcd_edpt_iso_activate() only has to re-arm it in place (no pipe free/realloc, which on this + // shared-register IP would churn PIPESEL/PIPECFG and disturb the other pipes). + const unsigned num = find_pipe(TUSB_XFER_ISOCHRONOUS); + TU_ASSERT(num); + _dcd.pipe[num].ep = ep_addr; + _dcd.ep[dir][epn] = num; + + dcd_int_disable(rhport); + rusb->PIPESEL = (uint16_t) num; + if (rusb2_is_highspeed_rhport(rhport)) { + // PIPEBUF is PIPESEL-windowed (RA6M5 UM 29.2.35): write it after selecting the pipe. + // FIXME (as in dcd_edpt_open): BUFNMB is a fixed 0x08 for every pipe; a real allocator is needed. + rusb->PIPEBUF = 0x7C08; + } + rusb->PIPEMAXP = largest_packet_size; + volatile uint16_t *ctr = get_pipectr(rusb, num); + *ctr = RUSB2_PIPE_CTR_ACLRM_Msk | RUSB2_PIPE_CTR_SQCLR_Msk; + *ctr = 0; // leave the pipe NAKing until activated + rusb->PIPECFG = (uint16_t) ((dir << 4) | epn | RUSB2_PIPECFG_TYPE_ISO | RUSB2_PIPECFG_DBLB_Msk); + rusb->BRDYSTS = (uint16_t) (0x3FFu ^ TU_BIT(num)); + rusb->BRDYENB |= TU_BIT(num); + dcd_int_enable(rhport); + return true; } bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { - (void)rhport; - (void)desc_ep; - return false; + rusb2_reg_t * rusb = RUSB2_REG(rhport); + const uint8_t ep_addr = desc_ep->bEndpointAddress; + const unsigned epn = tu_edpt_number(ep_addr); + const unsigned dir = tu_edpt_dir(ep_addr); + const unsigned num = _dcd.ep[dir][epn]; + TU_ASSERT(num); // must have been iso-alloc'd + + dcd_int_disable(rhport); + rusb->PIPESEL = (uint16_t) num; + rusb->PIPEMAXP = tu_edpt_packet_size(desc_ep); + volatile uint16_t *ctr = get_pipectr(rusb, num); + *ctr = RUSB2_PIPE_CTR_ACLRM_Msk | RUSB2_PIPE_CTR_SQCLR_Msk; // abort in-flight + reset data toggle + *ctr = 0; + // a transfer armed before SET_INTERFACE survives to here (no dcd close on this port): drop the + // stale bookkeeping so a BRDY firing before the class re-arms can't replay it + pipe_state_t *pipe = &_dcd.pipe[num]; + pipe->buf = NULL; + pipe->remaining = 0; + pipe->queued = false; + pipe->zlp_pending = false; + *ctr = RUSB2_PIPE_CTR_PID_BUF; // enable + dcd_int_enable(rhport); + return true; } -#endif bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { @@ -817,7 +926,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t rusb2_reg_t* rusb = RUSB2_REG(rhport); dcd_int_disable(rhport); - bool r = process_edpt_xfer(rusb, 0, ep_addr, buffer, total_bytes); + bool r = process_edpt_xfer(rhport, rusb, 0, ep_addr, buffer, total_bytes); dcd_int_enable(rhport); return r; @@ -830,7 +939,7 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_ rusb2_reg_t* rusb = RUSB2_REG(rhport); dcd_int_disable(rhport); - bool r = process_edpt_xfer(rusb, 1, ep_addr, ff, total_bytes); + bool r = process_edpt_xfer(rhport, rusb, 1, ep_addr, ff, total_bytes); dcd_int_enable(rhport); return r; @@ -865,7 +974,19 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) } else { const unsigned num = _dcd.ep[0][tu_edpt_number(ep_addr)]; rusb->PIPESEL = (uint16_t)num; - if (rusb->PIPECFG_b.TYPE != 1) { + // Drop any packet parked in the buffer while halted: a data-OUT packet the host sent before + // aborting its transfer would otherwise be delivered into the next read after recovery + // (BOT reset + clear-halt re-arms a 31-byte CBW read which then receives stale WRITE data, + // "SCSI CBW is not valid" -> stall -> reset loop; ra6m5 msc write wedge). + *ctr = RUSB2_PIPE_CTR_ACLRM_Msk; + *ctr = 0; + // Non-bulk OUT re-enables straight away. Bulk OUT is normally armed together with its transaction + // counter (TRE) by process_pipe_xfer(), so we don't blindly re-enable it here — but if a receive + // was already armed (still queued), SQCLR above just left it NAKing. Re-assert BUF so it keeps + // receiving; the class driver still considers that read submitted and never re-arms it, so + // otherwise the endpoint NAKs forever (usbtest toggle test 29 clears the halt on an armed pipe). + // `queued` (not `buf`) is the armed test: a zero-length OUT read has buf==NULL yet is armed. + if (rusb->PIPECFG_b.TYPE != 1 || _dcd.pipe[num].queued) { *ctr = RUSB2_PIPE_CTR_PID_BUF; } } diff --git a/src/portable/renesas/rusb2/hcd_rusb2.c b/src/portable/renesas/rusb2/hcd_rusb2.c index 4c3315044..489162e54 100644 --- a/src/portable/renesas/rusb2/hcd_rusb2.c +++ b/src/portable/renesas/rusb2/hcd_rusb2.c @@ -1,26 +1,8 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021 Koji Kitayama - * Portions copyrighted (c) 2021 Roland Winistoerfer - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021 Koji Kitayama + * SPDX-FileCopyrightText: Portions copyrighted (c) 2021 Roland Winistoerfer + * SPDX-FileCopyrightText: Copyright (c) 2021 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -472,11 +454,9 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { if (rusb2_is_highspeed_rhport(rhport) ) { rusb->SYSCFG_b.HSE = 1; rusb->PHYSET_b.HSEB = 0; - rusb->PHYSET_b.DIRPD = 0; - R_BSP_SoftwareDelay((uint32_t) 1, BSP_DELAY_UNITS_MILLISECONDS); - rusb->PHYSET_b.PLLRESET = 0; - rusb->LPSTS_b.SUSPENDM = 1; - while ( !rusb->PLLSTA_b.PLLLOCK ); + // same PHY reference-clock + power-up requirements as dcd_init: without CLKSEL matching the + // board XTAL the PLL never locks and the wait below would spin forever (e.g. EK-RA8M1, 20 MHz) + rusb2_utmi_phy_powerup(rusb); rusb->SYSCFG_b.DRPD = 1; rusb->SYSCFG_b.DCFM = 1; rusb->SYSCFG_b.DPRPU = 0; diff --git a/src/portable/renesas/rusb2/rusb2_common.c b/src/portable/renesas/rusb2/rusb2_common.c index 8addbe4c6..c13b47c2b 100644 --- a/src/portable/renesas/rusb2/rusb2_common.c +++ b/src/portable/renesas/rusb2/rusb2_common.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2023 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2023 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/renesas/rusb2/rusb2_common.h b/src/portable/renesas/rusb2/rusb2_common.h index 6b8c3d7f2..90abdf4b9 100644 --- a/src/portable/renesas/rusb2/rusb2_common.h +++ b/src/portable/renesas/rusb2/rusb2_common.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2025 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2025 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/renesas/rusb2/rusb2_ra.h b/src/portable/renesas/rusb2/rusb2_ra.h index 4774d2e2c..0954d0d25 100644 --- a/src/portable/renesas/rusb2/rusb2_ra.h +++ b/src/portable/renesas/rusb2/rusb2_ra.h @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2022 Rafael Silva (@perigoso) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2022 Rafael Silva (@perigoso) + * SPDX-FileCopyrightText: Copyright (c) 2022 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -67,6 +49,23 @@ typedef struct { #define rusb2_is_highspeed_rhport(_p) (_p == 1) #define rusb2_is_highspeed_reg(_reg) (_reg == RUSB2_REG(1)) + + // UTMI PHY reference clock is the main oscillator: PHYSET.CLKSEL must match the board XTAL + // before the PHY PLL is released (RA6M5 UM R01UH0891 29.2.17: 00=12 MHz, 10=20 MHz, + // 11=24 MHz reset default). EK-RA6M5 runs 24 MHz (default works); EK-RA8M1 runs 20 MHz and + // never locks/chirps on the default. A board with a non-standard USB clocking scheme can + // pre-define RUSB2_PHYSET_CLKSEL_VALUE to override this selection. + #ifndef RUSB2_PHYSET_CLKSEL_VALUE + #if BSP_CFG_XTAL_HZ == 12000000 + #define RUSB2_PHYSET_CLKSEL_VALUE 0u + #elif BSP_CFG_XTAL_HZ == 20000000 + #define RUSB2_PHYSET_CLKSEL_VALUE 2u + #elif BSP_CFG_XTAL_HZ == 24000000 + #define RUSB2_PHYSET_CLKSEL_VALUE 3u + #else + #error "USBHS UTMI PHY: no PHYSET.CLKSEL encoding for this BSP_CFG_XTAL_HZ; define RUSB2_PHYSET_CLKSEL_VALUE" + #endif + #endif #else #define RUSB2_CONTROLLER_COUNT 1 @@ -102,6 +101,31 @@ TU_ATTR_ALWAYS_INLINE static inline void rusb2_int_disable(uint8_t rhport) { TU_ATTR_ALWAYS_INLINE static inline void rusb2_phy_init(void) { } +#ifdef RUSB2_SUPPORT_HIGHSPEED +// UTMI PHY power-up per the FSP reference sequence (r_usb_preg_access.c), shared by dcd_init and +// hcd_init: program CLKSEL to the board XTAL while the PHY is powered down (DIRPD=1), 1 us, +// release DIRPD, 1 ms, release PLLRESET, then wait for PLL lock. Changing CLKSEL as the PHY +// powers up gets mis-sampled (EK-RA8M1, 20 MHz). +static inline void rusb2_utmi_phy_powerup(rusb2_reg_t* rusb) { + uint16_t physet = rusb->PHYSET | RUSB2_PHYSET_DIRPD_Msk; + rusb->PHYSET = physet; + #ifdef RUSB2_PHYSET_CLKSEL_VALUE + physet = (uint16_t) ((physet & ~RUSB2_PHYSET_CLKSEL_Msk) | + (RUSB2_PHYSET_CLKSEL_VALUE << RUSB2_PHYSET_CLKSEL_Pos)); + rusb->PHYSET = physet; + #endif + R_BSP_SoftwareDelay((uint32_t) 1, BSP_DELAY_UNITS_MICROSECONDS); + physet &= (uint16_t) ~RUSB2_PHYSET_DIRPD_Msk; + rusb->PHYSET = physet; + R_BSP_SoftwareDelay((uint32_t) 1, BSP_DELAY_UNITS_MILLISECONDS); + rusb->PHYSET_b.PLLRESET = 0; + + // set UTMI to operating mode and wait for PLL lock confirmation + rusb->LPSTS_b.SUSPENDM = 1; + while (!rusb->PLLSTA_b.PLLLOCK) {} +} +#endif + #ifdef __cplusplus } #endif diff --git a/src/portable/renesas/rusb2/rusb2_rx.h b/src/portable/renesas/rusb2/rusb2_rx.h index 7bf4be47e..fba51f550 100644 --- a/src/portable/renesas/rusb2/rusb2_rx.h +++ b/src/portable/renesas/rusb2/rusb2_rx.h @@ -1,27 +1,9 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2020 Koji Kitayama - * Portions copyrighted (c) 2021 Roland Winistoerfer - * Copyright (c) 2022 Rafael Silva (@perigoso) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2020 Koji Kitayama + * SPDX-FileCopyrightText: Portions copyrighted (c) 2021 Roland Winistoerfer + * SPDX-FileCopyrightText: Copyright (c) 2022 Rafael Silva (@perigoso) + * SPDX-FileCopyrightText: Copyright (c) 2020 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/renesas/rusb2/rusb2_type.h b/src/portable/renesas/rusb2/rusb2_type.h index 21f116857..511a898b6 100644 --- a/src/portable/renesas/rusb2/rusb2_type.h +++ b/src/portable/renesas/rusb2/rusb2_type.h @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2022 Rafael Silva (@perigoso) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2022 Rafael Silva (@perigoso) + * SPDX-FileCopyrightText: Copyright (c) 2022 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/sony/cxd56/dcd_cxd56.c b/src/portable/sony/cxd56/dcd_cxd56.c index be694edfa..f70ae826d 100644 --- a/src/portable/sony/cxd56/dcd_cxd56.c +++ b/src/portable/sony/cxd56/dcd_cxd56.c @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright 2019 Sony Semiconductor Solutions Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright 2019 Sony Semiconductor Solutions Corporation + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index f5a8beb65..ba05818b6 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -1,30 +1,9 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Nathan Conrad - * - * Portions: - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * Copyright (c) 2022 Simon Küppers (skuep) - * Copyright (c) 2022 HiFiPhile - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Nathan Conrad + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-FileCopyrightText: Copyright (c) 2022 Simon Küppers (skuep) + * SPDX-FileCopyrightText: Copyright (c) 2022 HiFiPhile (Zixun LI) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -856,7 +835,17 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { ep_reg &= U_EPREG_MASK | EP_STAT_MASK(dir) | EP_DTOG_MASK(dir); if (!ep_is_iso(ep_reg)) { - ep_change_status(&ep_reg, dir, EP_STAT_NAK); + // Only knock a genuinely STALLED endpoint down to NAK (the class then re-arms it). If the + // endpoint is armed (VALID) - e.g. a clear-halt used purely to reset the data toggle, as in + // usbtest case 29 - leave STAT untouched so the in-flight transfer isn't disarmed with no + // completion, which would leak the usbd claim and starve the endpoint. Masking the STAT bits + // to 0 writes no toggle, so an armed/idle endpoint keeps its current status. + const uint8_t stat_pos = (uint8_t) (U_EPTX_STAT_Pos + (dir == TUSB_DIR_IN ? 0u : 8u)); + if (((ep_reg >> stat_pos) & 0x3u) == EP_STAT_STALL) { + ep_change_status(&ep_reg, dir, EP_STAT_NAK); + } else { + ep_reg &= ~EP_STAT_MASK(dir); + } } ep_change_dtog(&ep_reg, dir, 0); // Reset to DATA0 ep_write(ep_idx, ep_reg, true); diff --git a/src/portable/st/stm32_fsdev/fsdev_apm32.h b/src/portable/st/stm32_fsdev/fsdev_apm32.h new file mode 100644 index 000000000..5031445e8 --- /dev/null +++ b/src/portable/st/stm32_fsdev/fsdev_apm32.h @@ -0,0 +1,77 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024, hathach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef TUSB_FSDEV_APM32_H +#define TUSB_FSDEV_APM32_H + +#include "common/tusb_compiler.h" + +#if CFG_TUSB_MCU == OPT_MCU_APM32F0XX + #include "apm32f0xx.h" +#endif + +#define FSDEV_USE_SBUF_ISO 0 +#define FSDEV_REG_BASE ((uint32_t)(USBD_BASE)) +#define FSDEV_PMA_BASE ((uint32_t)(USBD_BASE + 0x400UL)) + +#ifndef CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP + #define CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP 0 +#endif + +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ + +static const IRQn_Type fsdev_irq[] = { + USBD_IRQn +}; +enum { FSDEV_IRQ_NUM = TU_ARRAY_SIZE(fsdev_irq) }; + +TU_ATTR_ALWAYS_INLINE static inline void fsdev_int_enable(uint8_t rhport) { + (void)rhport; + for (uint8_t i = 0; i < FSDEV_IRQ_NUM; i++) { + NVIC_EnableIRQ(fsdev_irq[i]); + } +} + +TU_ATTR_ALWAYS_INLINE static inline void fsdev_int_disable(uint8_t rhport) { + (void)rhport; + for (uint8_t i = 0; i < FSDEV_IRQ_NUM; i++) { + NVIC_DisableIRQ(fsdev_irq[i]); + } +} + +TU_ATTR_ALWAYS_INLINE static inline void fsdev_disconnect(uint8_t rhport) { + (void) rhport; + FSDEV_REG->CNTR |= U_CNTR_PDWN; + FSDEV_REG->BCDR &= ~U_BCDR_DPPU; +} + +TU_ATTR_ALWAYS_INLINE static inline void fsdev_connect(uint8_t rhport) { + (void) rhport; + FSDEV_REG->CNTR &= ~U_CNTR_PDWN; + FSDEV_REG->BCDR |= U_BCDR_DPPU; +} + +#endif diff --git a/src/portable/st/stm32_fsdev/fsdev_at32.h b/src/portable/st/stm32_fsdev/fsdev_at32.h index 107884370..9138dc101 100644 --- a/src/portable/st/stm32_fsdev/fsdev_at32.h +++ b/src/portable/st/stm32_fsdev/fsdev_at32.h @@ -1,26 +1,6 @@ /* -* The MIT License (MIT) - * - * Copyright (c) 2024, hathach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * + * SPDX-FileCopyrightText: Copyright (c) 2024, Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT */ #ifndef TUSB_FSDEV_AT32_H #define TUSB_FSDEV_AT32_H @@ -37,7 +17,7 @@ #define FSDEV_USE_SBUF_ISO 0 #define FSDEV_REG_BASE (APB1PERIPH_BASE + 0x00005C00UL) -#define FSDEV_PMA_BASE (APB1PERIPH_BASE + 0x00006000UL) +#define FSDEV_PMA_BASE (APB1PERIPH_BASE + 0x00007800UL) #ifndef CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP #define CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP 0 diff --git a/src/portable/st/stm32_fsdev/fsdev_ch32.h b/src/portable/st/stm32_fsdev/fsdev_ch32.h index b92bf3f58..2c13554d4 100644 --- a/src/portable/st/stm32_fsdev/fsdev_ch32.h +++ b/src/portable/st/stm32_fsdev/fsdev_ch32.h @@ -1,26 +1,6 @@ /* -* The MIT License (MIT) - * - * Copyright (c) 2024, hathach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * + * SPDX-FileCopyrightText: Copyright (c) 2024, Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT */ /** <h2><center>© Copyright (c) 2016 STMicroelectronics. * All rights reserved.</center></h2> diff --git a/src/portable/st/stm32_fsdev/fsdev_common.c b/src/portable/st/stm32_fsdev/fsdev_common.c index 7c4572a1e..9c9233d12 100644 --- a/src/portable/st/stm32_fsdev/fsdev_common.c +++ b/src/portable/st/stm32_fsdev/fsdev_common.c @@ -1,26 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2024 Ha Thach (tinyusb.org) - * Copyright (c) 2025, HiFiPhile (Zixun LI) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2024 Ha Thach (tinyusb.org) + * SPDX-FileCopyrightText: Copyright (c) 2025, HiFiPhile (Zixun LI) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -52,6 +33,11 @@ void fsdev_core_reset(void) { // Clear pending interrupts FSDEV_REG->ISTR = 0; + + #if (CFG_TUSB_MCU == OPT_MCU_AT32F403A_407) || (CFG_TUSB_MCU == OPT_MCU_AT32F413) + // Enable larger PMA area + CRM->misc1_bit.usbbufs = 1; + #endif } // De-initialize the USB Core diff --git a/src/portable/st/stm32_fsdev/fsdev_common.h b/src/portable/st/stm32_fsdev/fsdev_common.h index af84b8b97..00d9b513a 100644 --- a/src/portable/st/stm32_fsdev/fsdev_common.h +++ b/src/portable/st/stm32_fsdev/fsdev_common.h @@ -1,27 +1,8 @@ /* - * The MIT License (MIT) - * - * Copyright (c) N Conrad - * Copyright (c) 2024, hathach (tinyusb.org) - * Copyright (c) 2025, HiFiPhile (Zixun LI) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Nathan Conrad + * SPDX-FileCopyrightText: Copyright (c) 2024, Ha Thach (tinyusb.org) + * SPDX-FileCopyrightText: Copyright (c) 2025, HiFiPhile (Zixun LI) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -303,6 +284,8 @@ typedef struct { #include "fsdev_ch32.h" #elif defined(TUP_USBIP_FSDEV_AT32) #include "fsdev_at32.h" +#elif defined(TUP_USBIP_FSDEV_APM32) + #include "fsdev_apm32.h" #else #error "Unknown USB IP" #endif diff --git a/src/portable/st/stm32_fsdev/fsdev_stm32.h b/src/portable/st/stm32_fsdev/fsdev_stm32.h index 93cdac808..23e24752b 100644 --- a/src/portable/st/stm32_fsdev/fsdev_stm32.h +++ b/src/portable/st/stm32_fsdev/fsdev_stm32.h @@ -1,30 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright(c) N Conrad - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Nathan Conrad + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c index f9201651a..1e84ed283 100644 --- a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2025 HiFiPhile (Zixun LI) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2025 HiFiPhile (Zixun LI) + * SPDX-FileCopyrightText: Copyright (c) 2025 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/st/typec/typec_stm32.c b/src/portable/st/typec/typec_stm32.c index b4288968f..8ac9f148c 100644 --- a/src/portable/st/typec/typec_stm32.c +++ b/src/portable/st/typec/typec_stm32.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2023 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2023 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT */ #include "tusb_option.h" diff --git a/src/portable/sunxi/dcd_sunxi_musb.c b/src/portable/sunxi/dcd_sunxi_musb.c index 9fac0bc1c..c74ee68a0 100644 --- a/src/portable/sunxi/dcd_sunxi_musb.c +++ b/src/portable/sunxi/dcd_sunxi_musb.c @@ -1,27 +1,8 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021 Koji KITAYAMA - * Copyright (c) 2021 Tian Yunhao (t123yh) - * Copyright (c) 2021 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021 Koji Kitayama + * SPDX-FileCopyrightText: Copyright (c) 2021 Tian Yunhao (t123yh) + * SPDX-FileCopyrightText: Copyright (c) 2021 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/sunxi/musb_def.h b/src/portable/sunxi/musb_def.h index ce9b89d55..638f3c93d 100644 --- a/src/portable/sunxi/musb_def.h +++ b/src/portable/sunxi/musb_def.h @@ -1,27 +1,8 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021 Koji KITAYAMA - * Copyright (c) 2021 Tian Yunhao (t123yh) - * Copyright (c) 2021 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021 Koji Kitayama + * SPDX-FileCopyrightText: Copyright (c) 2021 Tian Yunhao (t123yh) + * SPDX-FileCopyrightText: Copyright (c) 2021 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index e1a2f6cf2..b2f1a93a4 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -1,28 +1,9 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 William D. Jones - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * Copyright (c) 2020 Jan Duempelmann - * Copyright (c) 2020 Reinhard Panhuber - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 William D. Jones + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-FileCopyrightText: Copyright (c) 2020 Jan Duempelmann + * SPDX-FileCopyrightText: Copyright (c) 2020 Reinhard Panhuber + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -412,10 +393,6 @@ static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uin } dep->diepdma = (uintptr_t) xfer->buffer; dep->diepctl = depctl.value; // enable endpoint - // Advance buffer pointer for EP0 - if (epnum == 0) { - xfer->buffer += total_bytes; - } } else #endif { @@ -751,6 +728,8 @@ static void handle_bus_reset(uint8_t rhport) { tu_memclr(xfer_status, sizeof(xfer_status)); + _dcd_data.ep0_pending[TUSB_DIR_OUT] = 0; + _dcd_data.ep0_pending[TUSB_DIR_IN] = 0; _dcd_data.sof_en = false; _dcd_data.allocated_epin_count = 0; @@ -1028,6 +1007,10 @@ static void handle_epout_dma(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepi if (edpt_is_enabled(epin0)) { edpt_disable(rhport, 0x80, false); } + // a new SETUP aborts any in-progress control transfer: drop leftover EP0 chunking state so a + // stale latched completion cannot re-arm from it + _dcd_data.ep0_pending[TUSB_DIR_OUT] = 0; + _dcd_data.ep0_pending[TUSB_DIR_IN] = 0; dcd_dcache_invalidate(_dcd_usbbuf.setup_buffer, sizeof(_dcd_usbbuf.setup_buffer)); @@ -1048,24 +1031,37 @@ static void handle_epout_dma(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepi // only handle data skip if it is setup or status related // Normal OUT transfer complete if (!doepint_bm.status_phase_rx && !doepint_bm.setup_packet_rx) { + xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); if ((epnum == 0) && _dcd_data.ep0_pending[TUSB_DIR_OUT]) { - // EP0 can only handle one packet Schedule another packet to be received. + // EP0 can only handle one packet: invalidate and advance past the received bytes, then + // schedule the next. + if (xfer->buffer != NULL) { + dcd_dcache_invalidate(xfer->buffer, CFG_TUD_ENDPOINT0_SIZE); + xfer->buffer += CFG_TUD_ENDPOINT0_SIZE; + } edpt_schedule_packets(rhport, epnum, TUSB_DIR_OUT); } else { dwc2_dep_t* epout = &dwc2->epout[epnum]; - xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); // determine actual received bytes const dwc2_ep_tsize_t tsiz = {.value = epout->tsiz}; const uint16_t remain = tsiz.xfer_size; xfer->total_len -= remain; + // EP0 invalidates only this (final) chunk's DMA-written bytes: DOEPDMA "is incremented on + // every AHB transaction" (databook 7.1.83), i.e. it points past the last word written. + // Read it before dma_setup_prepare() re-targets it at the setup buffer + uint16_t inval_len = xfer->total_len; + if (epnum == 0) { + inval_len = (uint16_t)(epout->doepdma - (uintptr_t)xfer->buffer); + } + // prepare EP0 for next setup if(epnum == 0) { dma_setup_prepare(rhport); } - dcd_dcache_invalidate(xfer->buffer, xfer->total_len); + dcd_dcache_invalidate(xfer->buffer, inval_len); dcd_event_xfer_complete(rhport, epnum, xfer->total_len, XFER_RESULT_SUCCESS, true); } } @@ -1077,7 +1073,10 @@ static void handle_epin_dma(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diepin if (diepint_bm.xfer_complete) { if ((epnum == 0) && _dcd_data.ep0_pending[TUSB_DIR_IN]) { - // EP0 can only handle one packet. Schedule another packet to be transmitted. + // EP0 can only handle one packet: advance past the sent bytes, then schedule the next. + if (xfer->buffer != NULL) { + xfer->buffer += CFG_TUD_ENDPOINT0_SIZE; + } edpt_schedule_packets(rhport, epnum, TUSB_DIR_IN); } else { dcd_event_xfer_complete(rhport, epnum | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true); @@ -1144,7 +1143,12 @@ static void handle_incomplete_iso_in(uint8_t rhport) { xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, TUSB_DIR_IN); if (xfer->iso_retry > 0) { xfer->iso_retry--; - // Restart ISO transfe: re-write TSIZ and CTL + // Restart ISO transfer: re-write DMA address, TSIZ, and CTL + #if CFG_TUD_DWC2_DMA_ENABLE + if (dma_device_enabled(dwc2)) { + epin->diepdma = (uintptr_t) xfer->buffer; + } + #endif dwc2_ep_tsize_t deptsiz = {.value = 0}; deptsiz.xfer_size = xfer->total_len; deptsiz.packet_count = tu_div_ceil(xfer->total_len, xfer->max_size); diff --git a/src/portable/synopsys/dwc2/dwc2_at32.h b/src/portable/synopsys/dwc2/dwc2_at32.h index 85fa9b20b..828af3055 100644 --- a/src/portable/synopsys/dwc2/dwc2_at32.h +++ b/src/portable/synopsys/dwc2/dwc2_at32.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021, Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021, Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/synopsys/dwc2/dwc2_bcm.h b/src/portable/synopsys/dwc2/dwc2_bcm.h index 91cae821e..8119d9139 100644 --- a/src/portable/synopsys/dwc2/dwc2_bcm.h +++ b/src/portable/synopsys/dwc2/dwc2_bcm.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021, Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021, Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/synopsys/dwc2/dwc2_common.c b/src/portable/synopsys/dwc2/dwc2_common.c index 33eabaeab..0e38218e3 100644 --- a/src/portable/synopsys/dwc2/dwc2_common.c +++ b/src/portable/synopsys/dwc2/dwc2_common.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2024-2025 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2024 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/synopsys/dwc2/dwc2_common.h b/src/portable/synopsys/dwc2/dwc2_common.h index 5c4798d21..22a04c464 100644 --- a/src/portable/synopsys/dwc2/dwc2_common.h +++ b/src/portable/synopsys/dwc2/dwc2_common.h @@ -1,25 +1,6 @@ /* -* The MIT License (MIT) - * - * Copyright (c) 2024 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2024 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/synopsys/dwc2/dwc2_efm32.h b/src/portable/synopsys/dwc2/dwc2_efm32.h index 063360873..8b2922cc9 100644 --- a/src/portable/synopsys/dwc2/dwc2_efm32.h +++ b/src/portable/synopsys/dwc2/dwc2_efm32.h @@ -1,26 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021 Rafael Silva (@perigoso) - * Copyright (c) 2021, Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021 Rafael Silva (@perigoso) + * SPDX-FileCopyrightText: Copyright (c) 2021, Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/synopsys/dwc2/dwc2_esp32.h b/src/portable/synopsys/dwc2/dwc2_esp32.h index 436f8dc30..c7a7d7d25 100644 --- a/src/portable/synopsys/dwc2/dwc2_esp32.h +++ b/src/portable/synopsys/dwc2/dwc2_esp32.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021, Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021, Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/synopsys/dwc2/dwc2_gd32.h b/src/portable/synopsys/dwc2/dwc2_gd32.h index 28c3fde5e..2520972fe 100644 --- a/src/portable/synopsys/dwc2/dwc2_gd32.h +++ b/src/portable/synopsys/dwc2/dwc2_gd32.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021, Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021, Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/synopsys/dwc2/dwc2_nrf.h b/src/portable/synopsys/dwc2/dwc2_nrf.h index a1bf692f8..c5f50043d 100644 --- a/src/portable/synopsys/dwc2/dwc2_nrf.h +++ b/src/portable/synopsys/dwc2/dwc2_nrf.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2025 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2025 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. * diff --git a/src/portable/synopsys/dwc2/dwc2_stm32.h b/src/portable/synopsys/dwc2/dwc2_stm32.h index 126632fec..0c9b534d4 100644 --- a/src/portable/synopsys/dwc2/dwc2_stm32.h +++ b/src/portable/synopsys/dwc2/dwc2_stm32.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021, Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021, Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h index 7c03a4a91..18e8dd02f 100644 --- a/src/portable/synopsys/dwc2/dwc2_type.h +++ b/src/portable/synopsys/dwc2/dwc2_type.h @@ -1,26 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2024, hathach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * + * SPDX-FileCopyrightText: Copyright (c) 2024, Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT */ /** <h2><center>© Copyright (c) 2019 STMicroelectronics. * All rights reserved.</center></h2> diff --git a/src/portable/synopsys/dwc2/dwc2_xmc.h b/src/portable/synopsys/dwc2/dwc2_xmc.h index 85b2a2633..16f051103 100644 --- a/src/portable/synopsys/dwc2/dwc2_xmc.h +++ b/src/portable/synopsys/dwc2/dwc2_xmc.h @@ -1,26 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2021 Rafael Silva (@perigoso) - * Copyright (c) 2021, Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2021 Rafael Silva (@perigoso) + * SPDX-FileCopyrightText: Copyright (c) 2021, Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index a536b1e36..5a171f80e 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2024 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2024 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -45,6 +26,12 @@ #endif #define DWC2_CHANNEL_COUNT_MAX 16u // absolute max channel count + + // Conservative time budget for enabling a slave-mode periodic OUT channel and writing its first packet before the + // current (micro)frame ends. HFNUM.FrRem is measured in PHY clocks; 1024 clocks are 17.1 us at 60 MHz, 21.3 us at + // 48 MHz, or 34.1 us at 30 MHz. Defer to SOF when less time remains. + #define DWC2_PERIODIC_OUT_MIN_FRREM 1024u + TU_VERIFY_STATIC(CFG_TUH_DWC2_ENDPOINT_MAX <= 255, "currently only use 8-bit for index"); enum { @@ -56,7 +43,9 @@ enum { }; enum { - HCD_XFER_PERIOD_SPLIT_NYET_MAX = 3 + HCD_XFER_PERIOD_SPLIT_NYET_MAX = 3, + HCD_FRAME_NUMBER_MASK = 0x3fff, + HCD_FRAME_COUNT = HCD_FRAME_NUMBER_MASK + 1 }; //-------------------------------------------------------------------- @@ -75,18 +64,22 @@ typedef struct { }; struct TU_ATTR_PACKED { - uint32_t uframe_interval : 18; // micro-frame interval + uint32_t uframe_interval : 19; // micro-frame interval uint32_t speed : 2; uint32_t next_pid : 2; // PID for next transfer uint32_t next_do_ping : 1; // Do PING for next transfer if possible (highspeed OUT) uint32_t closing : 1; // endpoint is closing - // uint32_t : 8; + uint32_t aborting : 1; // periodic DMA channel is waiting for its automatic halt + uint32_t periodic_phase : 1; // periodic transfer phase is established + uint32_t xfer_pending : 1; // periodic transfer waiting for its service interval + // uint32_t : 4; }; - uint32_t uframe_countdown; // micro-frame count down to transfer for periodic, only need 18-bit + uint32_t uframe_countdown; // micro-frame count down to transfer for periodic, only need 19-bit uint8_t* buffer; uint16_t buflen; + uint16_t periodic_frame; // frame/microframe number of the last scheduled periodic transaction } hcd_endpoint_t; // Additional info for each channel when it is active @@ -105,6 +98,7 @@ typedef struct { // be composed of multiple channel_xfer_start() (retry with NAK/NYET) uint16_t fifo_bytes; // bytes written/read from/to FIFO (may not be transferred on USB bus). uint8_t retry_disabled; // 1: channel was disabled to throttle a split retry (NAK in / XactErr out); re-arm on its halt + volatile bool aborting; // periodic DMA abort waiting for the channel's automatic halt } hcd_xfer_t; typedef struct { @@ -206,7 +200,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool channel_disable(const dwc2_regs_t* dwc2 // the worst case), the controller generates a channel halted and disables the channel automatically. // - For split enabled channels (both non-periodic and periodic), channel disable must not be programmed randomly. // However, channel disable can be programmed for specific scenarios such as NAK and FrmOvrn. - if (is_period && (channel->hcsplt & HCSPLT_SPLITEN)) { + if (is_period) { return true; } } else { @@ -219,13 +213,86 @@ TU_ATTR_ALWAYS_INLINE static inline bool channel_disable(const dwc2_regs_t* dwc2 return true; } -// attempt to send IN token to receive data -TU_ATTR_ALWAYS_INLINE static inline bool channel_send_in_token(const dwc2_regs_t* dwc2, dwc2_channel_t* channel) { +// Retire all active host channels on root-port disconnect without waiting for +// Channel Halted interrupts. +// stop new channel/FIFO interrupts, flush queued slave requests, request a +// halt for enabled channels, then clear their interrupt and software state. +static void channel_cleanup_on_disconnect(dwc2_regs_t *dwc2) { + const uint32_t xfer_ints = GINTSTS_NPTX_FIFO_EMPTY | GINTSTS_PTX_FIFO_EMPTY | GINTSTS_HCINT; + dwc2->gintmsk &= ~xfer_ints; + dwc2->gintsts = xfer_ints; + dwc2->haintmsk = 0; + + const uint8_t max_channel = dwc2_channel_count(dwc2); + #if CFG_TUH_DWC2_SLAVE_ENABLE + if (!dma_host_enabled(dwc2)) { + // With CHENA clear, CHDIS flushes a posted request without consuming + // request-queue space. Clear EPDIR as required for this flush operation. + for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) { + if (_hcd_data.xfer[ch_id].allocated) { + dwc2_channel_t *channel = &dwc2->channel[ch_id]; + const uint32_t hcchar = channel->hcchar; + if (hcchar & HCCHAR_CHENA) { + channel->hcchar = (hcchar & ~(HCCHAR_CHENA | HCCHAR_EPDIR)) | HCCHAR_CHDIS; + } + } + } + } + #endif + + for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) { + if (_hcd_data.xfer[ch_id].allocated) { + dwc2_channel_t *channel = &dwc2->channel[ch_id]; + const uint32_t hcchar = channel->hcchar; + if (hcchar & HCCHAR_CHENA) { + channel->hcchar = hcchar | HCCHAR_CHDIS; + } + channel->hcintmsk = 0; + channel->hcint = 0xFFFFFFFFU; + } + } + + tu_memclr(_hcd_data.xfer, sizeof(_hcd_data.xfer)); + for (uint8_t ep_id = 0; ep_id < CFG_TUH_DWC2_ENDPOINT_MAX; ep_id++) { + hcd_endpoint_t *edpt = &_hcd_data.edpt[ep_id]; + if (edpt->hcchar_bm.enable) { + edpt->closing = 1; + edpt->xfer_pending = 0; + } + } +} + +// Enable a channel, selecting the following frame for a new periodic transfer. +// Return that frame from the same HFNUM sample used for ODDFRM selection. +// Clear CHDIS explicitly: a halted channel may retain it in HCCHAR. +TU_ATTR_ALWAYS_INLINE static inline uint16_t channel_enable(dwc2_regs_t* dwc2, dwc2_channel_t* channel, + bool next_periodic_frame) { + uint32_t hcchar = channel->hcchar & ~HCCHAR_CHDIS; + uint16_t periodic_frame = 0; + if (next_periodic_frame) { + // Prevent the USB interrupt from consuming the selected frame before + // HCCHAR.CHENA is written. Queue-space waits happen before this helper. + const uint32_t gahbcfg = dwc2->gahbcfg; + dwc2->gahbcfg = gahbcfg & ~GAHBCFG_GINT; + const uint32_t hfnum = dwc2->hfnum; + hcchar = (hcchar & ~HCCHAR_ODDFRM) | (((hfnum & 1u) ^ 1u) << HCCHAR_ODDFRM_Pos); + channel->hcchar = hcchar | HCCHAR_CHENA; + periodic_frame = (uint16_t) ((hfnum + 1u) & HCD_FRAME_NUMBER_MASK); + dwc2->gahbcfg = gahbcfg; + } else { + channel->hcchar = hcchar | HCCHAR_CHENA; + } + return periodic_frame; +} + +// Attempt to send an IN token to receive data. For a new periodic transfer, +// select its frame only after request-queue space is available. +TU_ATTR_ALWAYS_INLINE static inline uint16_t channel_send_in_token(dwc2_regs_t* dwc2, dwc2_channel_t* channel, + bool next_periodic_frame) { while (0 == req_queue_avail(dwc2, channel_is_periodic(channel->hcchar))) { // blocking wait for request queue available } - channel->hcchar |= HCCHAR_CHENA; - return true; + return channel_enable(dwc2, channel, next_periodic_frame); } // Find currently enabled channel. Note: EP0 is bidirectional @@ -281,11 +348,13 @@ static void edpt_close(dwc2_regs_t *dwc2, uint8_t ep_id) { // Find an endpoint that is opened previously with hcd_edpt_open() // Note: EP0 is bidirectional -TU_ATTR_ALWAYS_INLINE static inline uint8_t edpt_find_opened(uint8_t dev_addr, uint8_t ep_num, uint8_t ep_dir) { +TU_ATTR_ALWAYS_INLINE static inline uint8_t edpt_find_opened(uint8_t dev_addr, uint8_t ep_num, uint8_t ep_dir, + bool include_closing) { for (uint8_t i = 0; i < (uint8_t)CFG_TUH_DWC2_ENDPOINT_MAX; i++) { const hcd_endpoint_t *edpt = &_hcd_data.edpt[i]; const dwc2_channel_char_t hcchar_bm = edpt->hcchar_bm; - if (hcchar_bm.enable && hcchar_bm.dev_addr == dev_addr && hcchar_bm.ep_num == ep_num && + if (hcchar_bm.enable && (include_closing || !edpt->closing) && hcchar_bm.dev_addr == dev_addr && + hcchar_bm.ep_num == ep_num && (ep_num == 0 || hcchar_bm.ep_dir == ep_dir)) { return i; } @@ -355,13 +424,13 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t cal_next_pid(uint8_t pid, uint8_t pa static void dfifo_host_init(uint8_t rhport, bool is_hs_phy) { const dwc2_controller_t* dwc2_controller = &_dwc2_controller[rhport]; dwc2_regs_t* dwc2 = DWC2_REG(rhport); - const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2}; + const uint8_t channel_count = dwc2_channel_count(dwc2); // Scatter/Gather DMA mode is not yet supported. Buffer DMA only need 1 words per channel const bool is_dma = dma_host_enabled(dwc2); uint16_t dfifo_top = dwc2_controller->otg_dfifo_depth; if (is_dma) { - dfifo_top -= ghwcfg2.num_host_ch; + dfifo_top -= channel_count; } // fixed allocation for now, improve later: @@ -377,13 +446,12 @@ static void dfifo_host_init(uint8_t rhport, bool is_hs_phy) { } uint16_t nptxfsiz = 2 * nptx_largest; - uint16_t rxfsiz = 2 * (ptx_largest + 2) + ghwcfg2.num_host_ch; + uint16_t rxfsiz = 2 * (ptx_largest + 2) + channel_count; TU_ASSERT(dfifo_top >= (nptxfsiz + rxfsiz),); uint16_t ptxfsiz = dfifo_top - (nptxfsiz + rxfsiz); dwc2->gdfifocfg = (dfifo_top << GDFIFOCFG_EPINFOBASE_SHIFT) | dfifo_top; - dfifo_top -= rxfsiz; dwc2->grxfsiz = rxfsiz; dfifo_top -= nptxfsiz; @@ -567,7 +635,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t* edpt->next_pid = HCTSIZ_PID_DATA0; switch (desc_ep->bmAttributes.xfer) { case TUSB_XFER_ISOCHRONOUS: - edpt->uframe_interval = 1 << (desc_ep->bInterval - 1); + edpt->uframe_interval = 1u << (desc_ep->bInterval - 1); if (bus_info.speed == TUSB_SPEED_FULL) { edpt->uframe_interval <<= 3; } @@ -575,7 +643,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t* case TUSB_XFER_INTERRUPT: if (bus_info.speed == TUSB_SPEED_HIGH) { - edpt->uframe_interval = 1 << (desc_ep->bInterval - 1); + edpt->uframe_interval = 1u << (desc_ep->bInterval - 1); } else { edpt->uframe_interval = desc_ep->bInterval << 3; } @@ -585,6 +653,13 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t* break; } + if (channel_is_periodic(edpt->hcchar)) { + // HFNUM cannot distinguish elapsed periods longer than one counter cycle. USB permits the host to provide a + // shorter period, so bound the selected period to the history available from HFNUM. + const uint32_t ucount = (rh_speed == TUSB_SPEED_HIGH) ? 1u : 8u; + edpt->uframe_interval = tu_min32(edpt->uframe_interval, HCD_FRAME_COUNT * ucount); + } + return true; } @@ -592,7 +667,7 @@ bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) { dwc2_regs_t *dwc2 = DWC2_REG(rhport); const uint8_t ep_num = tu_edpt_number(ep_addr); const uint8_t ep_dir = tu_edpt_dir(ep_addr); - const uint8_t ep_id = edpt_find_opened(daddr, ep_num, ep_dir); + const uint8_t ep_id = edpt_find_opened(daddr, ep_num, ep_dir, true); TU_ASSERT(ep_id < CFG_TUH_DWC2_ENDPOINT_MAX); edpt_close(dwc2, ep_id); @@ -607,7 +682,10 @@ static void channel_xfer_out_wrapup(dwc2_regs_t* dwc2, uint8_t ch_id) { hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz}; - edpt->next_pid = hctsiz.pid; // save PID + const dwc2_channel_char_t hcchar = {.value = channel->hcchar}; + if (hcchar.ep_type != HCCHAR_EPTYPE_ISOCHRONOUS) { + edpt->next_pid = hctsiz.pid; // save PID + } /* Since hctsiz.xfersize field reflects the number of bytes transferred via the AHB, not the USB) * For IN: we can use hctsiz.xfersize as remaining bytes. @@ -616,7 +694,6 @@ static void channel_xfer_out_wrapup(dwc2_regs_t* dwc2, uint8_t ch_id) { * transfer was halted before its normal completion. */ const uint16_t remain_packets = hctsiz.packet_count; - const dwc2_channel_char_t hcchar = {.value = channel->hcchar}; const uint16_t total_packets = cal_packet_count(edpt->buflen, hcchar.ep_size); const uint16_t actual_bytes = (total_packets - remain_packets) * hcchar.ep_size; @@ -626,20 +703,26 @@ static void channel_xfer_out_wrapup(dwc2_regs_t* dwc2, uint8_t ch_id) { edpt->buflen -= actual_bytes; } -static bool channel_xfer_start(dwc2_regs_t* dwc2, uint8_t ch_id) { +#if CFG_TUH_DWC2_SLAVE_ENABLE +static bool channel_txfifo_write(dwc2_regs_t* dwc2, uint8_t ch_id, bool is_periodic); +#endif +static void periodic_xfer_defer(dwc2_regs_t* dwc2, hcd_endpoint_t* edpt, uint32_t uframe_countdown); + +static bool channel_xfer_start(dwc2_regs_t* dwc2, uint8_t ch_id, bool defer_periodic_out) { hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; dwc2_channel_char_t* hcchar_bm = &edpt->hcchar_bm; dwc2_channel_t* channel = &dwc2->channel[ch_id]; bool const is_period = channel_is_periodic(edpt->hcchar); - +#if CFG_TUH_DWC2_SLAVE_ENABLE + const uint8_t saved_pid = edpt->next_pid; + const uint8_t saved_do_ping = edpt->next_do_ping; +#endif + uint16_t periodic_frame = 0; // clear previous state xfer->fifo_bytes = 0; // hchar: restore but don't enable yet - if (is_period) { - hcchar_bm->odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame - } channel->hcchar = (edpt->hcchar & ~HCCHAR_CHENA); // hctsiz: zero length packet still count as 1 @@ -655,15 +738,17 @@ static bool channel_xfer_start(dwc2_regs_t* dwc2, uint8_t ch_id) { channel->hctsiz = hctsiz.value; edpt->next_do_ping = 0; - // pre-calculate next PID based on packet count, adjusted in transfer complete interrupt if short packet + // Single-transaction isochronous endpoints always use DATA0. Pre-calculate the next PID for other endpoints, + // adjusted in the transfer-complete interrupt if a short packet is received. if (hcchar_bm->ep_num == 0) { edpt->next_pid = HCTSIZ_PID_DATA1; // control data and status stage always start with DATA1 - } else { + } else if (hcchar_bm->ep_type != HCCHAR_EPTYPE_ISOCHRONOUS) { edpt->next_pid = cal_next_pid(edpt->next_pid, packet_count); } channel->hcsplt = edpt->hcsplt; channel->hcint = 0xFFFFFFFFU; // clear all channel interrupts + dwc2->gintmsk |= GINTSTS_HCINT; if (dma_host_enabled(dwc2)) { channel->hcintmsk = HCINT_HALTED; @@ -672,13 +757,19 @@ static bool channel_xfer_start(dwc2_regs_t* dwc2, uint8_t ch_id) { channel->hcdma = (uint32_t) edpt->buffer; if (hcchar_bm->ep_dir == TUSB_DIR_IN) { - channel_send_in_token(dwc2, channel); + periodic_frame = channel_send_in_token(dwc2, channel, is_period); } else { hcd_dcache_clean(edpt->buffer, edpt->buflen); - channel->hcchar |= HCCHAR_CHENA; + periodic_frame = channel_enable(dwc2, channel, is_period); + } + } +#if CFG_TUH_DWC2_SLAVE_ENABLE + else { + uint32_t hcintmsk = HCINT_NAK | HCINT_XACT_ERR | HCINT_STALL | + HCINT_XFER_COMPLETE | HCINT_DATATOGGLE_ERR; + if (is_period) { + hcintmsk |= HCINT_FARME_OVERRUN; } - } else { - uint32_t hcintmsk = HCINT_NAK | HCINT_XACT_ERR | HCINT_STALL | HCINT_XFER_COMPLETE | HCINT_DATATOGGLE_ERR; if (hcchar_bm->ep_dir == TUSB_DIR_IN) { hcintmsk |= HCINT_BABBLE_ERR | HCINT_DATATOGGLE_ERR | HCINT_ACK; } else { @@ -696,16 +787,36 @@ static bool channel_xfer_start(dwc2_regs_t* dwc2, uint8_t ch_id) { // IN Token. If we got NAK, we have to re-enable the channel again in the interrupt. Due to the way usbh stack only // call hcd_edpt_xfer() once, we will need to manage de-allocate/re-allocate IN channel dynamically. if (hcchar_bm->ep_dir == TUSB_DIR_IN) { - channel_send_in_token(dwc2, channel); + periodic_frame = channel_send_in_token(dwc2, channel, is_period); } else { - channel->hcchar |= HCCHAR_CHENA; - if (edpt->buflen > 0) { - // To prevent conflict with other channel, we will enable periodic/non-periodic FIFO empty interrupt accordingly - // And write packet in the interrupt handler + // The final FIFO word creates the OUT request. Keep CHENA and that write + // atomic with respect to this controller's ISR. + // This region never waits for FIFO or queue space. + const uint32_t gahbcfg = dwc2->gahbcfg; + dwc2->gahbcfg = gahbcfg & ~GAHBCFG_GINT; + if (defer_periodic_out && is_period) { + const dwc2_hfnum_t hfnum = {.value = dwc2->hfnum}; + if (hfnum.remainning < DWC2_PERIODIC_OUT_MIN_FRREM) { + edpt->next_pid = saved_pid; + edpt->next_do_ping = saved_do_ping; + dwc2->gahbcfg = gahbcfg; + return false; + } + } + periodic_frame = channel_enable(dwc2, channel, is_period); + if (edpt->buflen > 0 && channel_txfifo_write(dwc2, ch_id, is_period)) { + // The FIFO-empty interrupt handles only work that did not fit in the + // initial synchronous write. dwc2->gintmsk |= (is_period ? GINTSTS_PTX_FIFO_EMPTY : GINTSTS_NPTX_FIFO_EMPTY); } + dwc2->gahbcfg = gahbcfg; } } +#endif + + if (is_period && defer_periodic_out) { + edpt->periodic_frame = periodic_frame; + } return true; } @@ -717,8 +828,48 @@ static bool edpt_xfer_kickoff(dwc2_regs_t* dwc2, uint8_t ep_id) { hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; xfer->ep_id = ep_id; xfer->result = XFER_RESULT_INVALID; + hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id]; + const bool result = channel_xfer_start(dwc2, ch_id, true); + if (!result) { + channel_dealloc(dwc2, ch_id); + periodic_xfer_defer(dwc2, edpt, 0); + return true; + } + if (channel_is_periodic(_hcd_data.edpt[ep_id].hcchar)) { + edpt->periodic_phase = 1; + edpt->xfer_pending = 0; + } + return result; +} + +static uint32_t periodic_xfer_countdown(dwc2_regs_t* dwc2, hcd_endpoint_t const* edpt) { + const uint32_t ucount = (hprt_speed_get(dwc2) == TUSB_SPEED_HIGH) ? 1u : 8u; + const uint16_t frame = (uint16_t) (dwc2->hfnum & HCD_FRAME_NUMBER_MASK); + const uint16_t elapsed_frames = (uint16_t) (frame - edpt->periodic_frame) & HCD_FRAME_NUMBER_MASK; + const uint32_t elapsed_uframes = (uint32_t) elapsed_frames * ucount; - return channel_xfer_start(dwc2, ch_id); + if (elapsed_uframes < edpt->uframe_interval) { + return edpt->uframe_interval - elapsed_uframes - ucount; + } + + // The service opportunity was missed. Keep the established phase and use + // the next interval rather than starting a new interval from this request. + return edpt->uframe_interval - (elapsed_uframes % edpt->uframe_interval) - ucount; +} + +static void periodic_xfer_defer(dwc2_regs_t* dwc2, hcd_endpoint_t* edpt, uint32_t uframe_countdown) { + const uint32_t gahbcfg = dwc2->gahbcfg; + dwc2->gahbcfg = gahbcfg & ~GAHBCFG_GINT; + + edpt->uframe_countdown = uframe_countdown; + edpt->xfer_pending = 1; + + if (0 == (dwc2->gintmsk & GINTMSK_SOFM)) { + dwc2->gintsts = GINTSTS_SOF; + dwc2->gintmsk |= GINTMSK_SOFM; + } + + dwc2->gahbcfg = gahbcfg; } bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) { @@ -726,10 +877,10 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * const uint8_t ep_num = tu_edpt_number(ep_addr); const uint8_t ep_dir = tu_edpt_dir(ep_addr); - uint8_t ep_id = edpt_find_opened(dev_addr, ep_num, ep_dir); - TU_ASSERT(ep_id < CFG_TUH_DWC2_ENDPOINT_MAX); + uint8_t ep_id = edpt_find_opened(dev_addr, ep_num, ep_dir, false); + TU_VERIFY(ep_id < CFG_TUH_DWC2_ENDPOINT_MAX); hcd_endpoint_t *edpt = &_hcd_data.edpt[ep_id]; - TU_VERIFY(edpt->closing == 0); // skip if endpoint is closing + TU_VERIFY(edpt->closing == 0 && edpt->aborting == 0); // skip if endpoint is closing or aborting edpt->buffer = buffer; edpt->buflen = buflen; @@ -739,6 +890,26 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * edpt->hcchar_bm.ep_dir = ep_dir; } + if (channel_is_periodic(edpt->hcchar)) { + const uint32_t ucount = (hprt_speed_get(dwc2) == TUSB_SPEED_HIGH) ? 1u : 8u; +#if CFG_TUH_DWC2_SLAVE_ENABLE + // Establish a slower slave-mode OUT schedule from SOF. bInterval=1 must be queued immediately to avoid + // losing every other service opportunity. + if (!dma_host_enabled(dwc2) && ep_dir == TUSB_DIR_OUT && !edpt->periodic_phase && + edpt->uframe_interval > ucount) { + periodic_xfer_defer(dwc2, edpt, 0); + return true; + } +#endif + if (edpt->periodic_phase && edpt->uframe_interval > ucount) { + const uint32_t countdown = periodic_xfer_countdown(dwc2, edpt); + if (countdown > 0) { + periodic_xfer_defer(dwc2, edpt, countdown); + return true; + } + } + } + return edpt_xfer_kickoff(dwc2, ep_id); } @@ -748,11 +919,39 @@ bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); const uint8_t ep_num = tu_edpt_number(ep_addr); const uint8_t ep_dir = tu_edpt_dir(ep_addr); - const uint8_t ep_id = edpt_find_opened(dev_addr, ep_num, ep_dir); + const uint8_t ep_id = edpt_find_opened(dev_addr, ep_num, ep_dir, false); TU_VERIFY(ep_id < CFG_TUH_DWC2_ENDPOINT_MAX); + hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id]; + + hcd_int_disable(rhport); + + const bool xfer_pending = edpt->xfer_pending; + if (xfer_pending) { + edpt->xfer_pending = 0; + edpt->uframe_countdown = 0; + } + + if (xfer_pending) { + hcd_int_enable(rhport); + return true; + } + + // A periodic DMA channel must halt naturally at the next service boundary. Prevent a replacement transfer until the + // halt ISR retires the channel, and suppress completion for the aborted transfer. + if (dma_host_enabled(dwc2) && channel_is_periodic(edpt->hcchar)) { + const uint8_t ch_id = channel_find_enabled(dwc2, dev_addr, ep_num, ep_dir); + if (ch_id < 16) { + hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; + edpt->aborting = 1; + xfer->aborting = true; + hcd_int_enable(rhport); + return true; + } + } - // hcd_int_disable(rhport); + hcd_int_enable(rhport); + // Channel disable may wait for request-queue space in slave mode. // Find enabled channeled and disable it, channel will be de-allocated in the interrupt handler const uint8_t ch_id = channel_find_enabled(dwc2, dev_addr, ep_num, ep_dir); if (ch_id < 16) { @@ -760,15 +959,13 @@ bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { channel_disable(dwc2, channel); } - // hcd_int_enable(rhport); - return true; } // Submit a special transfer to send 8-byte Setup Packet, when complete hcd_event_xfer_complete() must be invoked bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, const uint8_t setup_packet[8]) { - uint8_t ep_id = edpt_find_opened(dev_addr, 0, TUSB_DIR_OUT); - TU_ASSERT(ep_id < CFG_TUH_DWC2_ENDPOINT_MAX); // no opened endpoint + uint8_t ep_id = edpt_find_opened(dev_addr, 0, TUSB_DIR_OUT, false); + TU_VERIFY(ep_id < CFG_TUH_DWC2_ENDPOINT_MAX); // endpoint can close asynchronously on disconnect hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id]; edpt->next_pid = HCTSIZ_PID_SETUP; @@ -780,7 +977,7 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { (void) rhport; const uint8_t ep_num = tu_edpt_number(ep_addr); const uint8_t ep_dir = tu_edpt_dir(ep_addr); - const uint8_t ep_id = edpt_find_opened(dev_addr, ep_num, ep_dir); + const uint8_t ep_id = edpt_find_opened(dev_addr, ep_num, ep_dir, false); TU_VERIFY(ep_id < CFG_TUH_DWC2_ENDPOINT_MAX); hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id]; @@ -809,7 +1006,7 @@ static void channel_xfer_in_retry(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci if (xfer->period_split_nyet_count < HCD_XFER_PERIOD_SPLIT_NYET_MAX) { hcchar.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame channel->hcchar = hcchar.value; - channel_send_in_token(dwc2, channel); + channel_send_in_token(dwc2, channel, false); return; } else { // too many NYET, de-allocate channel with below code @@ -822,23 +1019,20 @@ static void channel_xfer_in_retry(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci // retry on next frame if bInterval is 1 hcchar.odd_frame = 1 - (dwc2->hfnum & 1); channel->hcchar = hcchar.value; - channel_send_in_token(dwc2, channel); + channel_send_in_token(dwc2, channel, false); } else { // otherwise, de-allocate channel, enable SOF set frame counter for later transfer const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz}; - edpt->next_pid = hctsiz.pid; // save PID - edpt->uframe_countdown = edpt->uframe_interval - ucount; - // enable SOF interrupt if not already enabled - if (0 == (dwc2->gintmsk & GINTMSK_SOFM)) { - dwc2->gintsts = GINTSTS_SOF; - dwc2->gintmsk |= GINTMSK_SOFM; + if (hcchar.ep_type != HCCHAR_EPTYPE_ISOCHRONOUS) { + edpt->next_pid = hctsiz.pid; // save PID } + periodic_xfer_defer(dwc2, edpt, periodic_xfer_countdown(dwc2, edpt)); // already halted, de-allocate channel (called from DMA isr) channel_dealloc(dwc2, ch_id); } } else { // for control/bulk: retry immediately - channel_send_in_token(dwc2, channel); + channel_send_in_token(dwc2, channel, false); } } @@ -873,6 +1067,13 @@ static void handle_rxflvl_irq(uint8_t rhport) { // In packet received, pop this entry --> ACK interrupt const uint16_t byte_count = grxstsp.byte_count; hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; + if (!xfer->allocated) { + // Discard data for a channel retired by disconnect. + for (uint16_t count = 0; count < byte_count; count += sizeof(uint32_t)) { + (void) dwc2->fifo[0][0]; + } + break; + } TU_ASSERT(xfer->ep_id < CFG_TUH_DWC2_ENDPOINT_MAX,); hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; @@ -902,38 +1103,50 @@ static void handle_rxflvl_irq(uint8_t rhport) { } } -// return true if there is still pending data and need more ISR +// Return true if data remains for a later FIFO-empty interrupt. +static bool channel_txfifo_write(dwc2_regs_t* dwc2, uint8_t ch_id, bool is_periodic) { + hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; + dwc2_channel_t* channel = &dwc2->channel[ch_id]; + const dwc2_channel_char_t hcchar = {.value = channel->hcchar}; + TU_ASSERT(xfer->ep_id < CFG_TUH_DWC2_ENDPOINT_MAX); + hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; + const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz}; + const uint16_t remain_packets = hctsiz.packet_count; + + for (uint16_t i = 0; i < remain_packets; i++) { + const uint16_t remain_bytes = edpt->buflen - xfer->fifo_bytes; + const uint16_t xact_bytes = tu_min16(remain_bytes, hcchar.ep_size); + + // The packet's last FIFO word creates its request-queue entry. + // HNPTXSTS differs by one request-queue bit, which is outside these fields. + const dwc2_hptxsts_t txsts = {.value = (is_periodic ? dwc2->hptxsts : dwc2->hnptxsts)}; + if ((xact_bytes > (txsts.fifo_available << 2)) || (txsts.req_queue_available == 0)) { + return true; + } + + tu_hwfifo_write(dwc2->fifo[ch_id], edpt->buffer + xfer->fifo_bytes, xact_bytes, NULL); + xfer->fifo_bytes += xact_bytes; + } + + return false; +} + +// Return true if at least one matching channel needs another interrupt. static bool handle_txfifo_empty(dwc2_regs_t* dwc2, bool is_periodic) { const uint8_t max_channel = dwc2_channel_count(dwc2); for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) { + hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; dwc2_channel_t* channel = &dwc2->channel[ch_id]; const dwc2_channel_char_t hcchar = {.value = channel->hcchar}; - // skip writing to FIFO if channel is expecting halted. - if (0 == (channel->hcintmsk & HCINT_HALTED) && (hcchar.ep_dir == TUSB_DIR_OUT)) { - hcd_xfer_t *xfer = &_hcd_data.xfer[ch_id]; - TU_ASSERT(xfer->ep_id < CFG_TUH_DWC2_ENDPOINT_MAX); - hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; - const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz}; - const uint16_t remain_packets = hctsiz.packet_count; - for (uint16_t i = 0; i < remain_packets; i++) { - const uint16_t remain_bytes = edpt->buflen - xfer->fifo_bytes; - const uint16_t xact_bytes = tu_min16(remain_bytes, hcchar.ep_size); - - // skip if there is not enough space in FIFO and RequestQueue. - // Packet's last word written to FIFO will trigger a request queue - // Use period txsts for both p/np to get request queue space available (1-bit difference, it is small enough) - const dwc2_hptxsts_t txsts = {.value = (is_periodic ? dwc2->hptxsts : dwc2->hnptxsts)}; - if ((xact_bytes > (txsts.fifo_available << 2)) || (txsts.req_queue_available == 0)) { - return true; - } - - tu_hwfifo_write(dwc2->fifo[ch_id], edpt->buffer + xfer->fifo_bytes, xact_bytes, NULL); - xfer->fifo_bytes += xact_bytes; + if (xfer->allocated && channel_is_periodic(hcchar.value) == is_periodic && + 0 == (channel->hcintmsk & HCINT_HALTED) && hcchar.ep_dir == TUSB_DIR_OUT) { + if (channel_txfifo_write(dwc2, ch_id, is_periodic)) { + return true; } } } - return false; // no channel has pending data + return false; } static bool handle_channel_in_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hcint) { @@ -951,7 +1164,8 @@ static bool handle_channel_in_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t h // } if (hcint & HCINT_XFER_COMPLETE) { - if (edpt->hcchar_bm.ep_num != 0) { + if (edpt->hcchar_bm.ep_num != 0 && + edpt->hcchar_bm.ep_type != HCCHAR_EPTYPE_ISOCHRONOUS) { edpt->next_pid = hctsiz.pid; // save pid (already toggled) } @@ -964,6 +1178,17 @@ static bool handle_channel_in_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t h xfer->result = XFER_RESULT_SUCCESS; } + if (channel_is_periodic(channel->hcchar) && remain_packets == 0) { + // The core has already halted a completed periodic IN channel. Complete + // it now so the next interval can be submitted without another halt IRQ. + is_done = true; + } else { + channel_disable(dwc2, channel); + } + } else if (hcint & HCINT_FARME_OVERRUN) { + if (edpt->hcchar_bm.ep_type == HCCHAR_EPTYPE_ISOCHRONOUS) { + xfer->result = XFER_RESULT_FAILED; + } channel_disable(dwc2, channel); } else if (hcint & (HCINT_XACT_ERR | HCINT_BABBLE_ERR | HCINT_STALL)) { if (hcint & HCINT_STALL) { @@ -1001,7 +1226,7 @@ static bool handle_channel_in_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t h channel->hcintmsk |= HCINT_NYET; hcsplt.split_compl = 1; channel->hcsplt = hcsplt.value; - channel_send_in_token(dwc2, channel); + channel_send_in_token(dwc2, channel, false); } else { // do nothing for complete split with DATA, this will trigger XferComplete and handled there } @@ -1012,7 +1237,7 @@ static bool handle_channel_in_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t h // still more packet to receive, also reset to start split hcsplt.split_compl = 0; channel->hcsplt = hcsplt.value; - channel_send_in_token(dwc2, channel); + channel_send_in_token(dwc2, channel, false); } } } else if (hcint & HCINT_HALTED) { @@ -1058,6 +1283,12 @@ static bool handle_channel_out_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t } else if (hcint & HCINT_STALL) { xfer->result = XFER_RESULT_STALLED; channel_disable(dwc2, channel); + } else if (hcint & HCINT_FARME_OVERRUN) { + channel_xfer_out_wrapup(dwc2, ch_id); + if (edpt->hcchar_bm.ep_type == HCCHAR_EPTYPE_ISOCHRONOUS) { + xfer->result = XFER_RESULT_FAILED; + } + channel_disable(dwc2, channel); } else if (hcint & HCINT_NYET) { xfer->err_count = 0; if (hcsplt.split_en == 1u) { @@ -1093,7 +1324,7 @@ static bool handle_channel_out_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t is_done = true; } else { // Got here due to NAK or NYET - TU_ASSERT(channel_xfer_start(dwc2, ch_id)); + TU_ASSERT(channel_xfer_start(dwc2, ch_id, false)); } } else if (hcint & HCINT_ACK) { xfer->err_count = 0; @@ -1145,9 +1376,13 @@ static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci if (xfer->closing) { is_done = true; } else { - channel_send_in_token(dwc2, channel); + channel_send_in_token(dwc2, channel, false); } } else if (hcint & (HCINT_XFER_COMPLETE | HCINT_STALL | HCINT_BABBLE_ERR)) { + if (edpt->hcchar_bm.ep_num != 0 && (hcint & HCINT_XFER_COMPLETE)) { + edpt->next_pid = hctsiz.pid; // save pid (already toggled) + } + const uint16_t remain_bytes = (uint16_t) hctsiz.xfer_size; const uint16_t remain_packets = hctsiz.packet_count; const uint16_t actual_len = edpt->buflen - remain_bytes; @@ -1206,7 +1441,7 @@ static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci hcchar.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame channel->hcchar = hcchar.value; } - channel_send_in_token(dwc2, channel); + channel_send_in_token(dwc2, channel, false); } } else if (hcint & (HCINT_NAK | HCINT_DATATOGGLE_ERR)) { xfer->err_count = 0; @@ -1223,8 +1458,12 @@ static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci channel_xfer_in_retry(dwc2, ch_id, hcint); } } else if (hcint & HCINT_FARME_OVERRUN) { - // retry start-split in next binterval - channel_xfer_in_retry(dwc2, ch_id, hcint); + if (hcchar.ep_type == HCCHAR_EPTYPE_ISOCHRONOUS) { + xfer->result = XFER_RESULT_FAILED; + is_done = true; + } else { + channel_xfer_in_retry(dwc2, ch_id, hcint); + } } if (xfer->closing == 1) { @@ -1253,7 +1492,7 @@ static bool handle_channel_out_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hc if (xfer->closing) { is_done = true; } else { - channel_xfer_start(dwc2, ch_id); + channel_xfer_start(dwc2, ch_id, false); } } else if (hcint & (HCINT_XFER_COMPLETE | HCINT_STALL)) { is_done = true; @@ -1267,30 +1506,38 @@ static bool handle_channel_out_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hc } channel->hcintmsk &= ~HCINT_ACK; } else if (hcint & HCINT_XACT_ERR) { - if (hcint & (HCINT_NAK | HCINT_NYET | HCINT_ACK)) { - xfer->err_count = 0; - // clean up transfer so far and start again - channel_xfer_out_wrapup(dwc2, ch_id); - channel_xfer_start(dwc2, ch_id); - } else { - xfer->err_count++; - if (xfer->err_count >= HCD_XFER_ERROR_MAX) { - xfer->result = XFER_RESULT_FAILED; - is_done = true; - } else { - // Rewind, then retry the start-split. Non-periodic SPLIT throttles via channel_disable + re-arm on - // the halt (immediate re-fire exhausts the retry budget; the disable gives the hub TT a recovery - // gap, like slave). Periodic split is excluded: channel_disable() is a no-op for it, so the halt - // never fires and the channel would wedge. Non-split re-inits immediately (Programming Guide 5.1.2.3). - channel_xfer_out_wrapup(dwc2, ch_id); - if (hcsplt.split_en && !channel_is_periodic(channel->hcchar)) { - xfer->retry_disabled = 1; - channel_disable(dwc2, channel); - } else { - channel_xfer_start(dwc2, ch_id); - } - } - } + if (hcint & (HCINT_NAK | HCINT_NYET | HCINT_ACK)) { + xfer->err_count = 0; + // clean up transfer so far and start again + channel_xfer_out_wrapup(dwc2, ch_id); + channel_xfer_start(dwc2, ch_id, false); + } else { + xfer->err_count++; + if (xfer->err_count >= HCD_XFER_ERROR_MAX) { + xfer->result = XFER_RESULT_FAILED; + is_done = true; + } else { + // Rewind, then retry the start-split. Non-periodic SPLIT throttles via channel_disable + re-arm on + // the halt (immediate re-fire exhausts the retry budget; the disable gives the hub TT a recovery + // gap, like slave). Periodic split is excluded: channel_disable() is a no-op for it, so the halt + // never fires and the channel would wedge. Non-split re-inits immediately (Programming Guide 5.1.2.3). + channel_xfer_out_wrapup(dwc2, ch_id); + if (hcsplt.split_en && !channel_is_periodic(channel->hcchar)) { + xfer->retry_disabled = 1; + channel_disable(dwc2, channel); + } else { + channel_xfer_start(dwc2, ch_id, false); + } + } + } + } else if (hcint & HCINT_FARME_OVERRUN) { + channel_xfer_out_wrapup(dwc2, ch_id); + if (edpt->hcchar_bm.ep_type == HCCHAR_EPTYPE_ISOCHRONOUS) { + xfer->result = XFER_RESULT_FAILED; + is_done = true; + } else { + channel_xfer_start(dwc2, ch_id, false); + } } else if (hcint & HCINT_NYET) { if (hcsplt.split_en && hcsplt.split_compl) { // split not yet mean hub has no data, retry complete split @@ -1311,7 +1558,7 @@ static bool handle_channel_out_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hc // Non-split OUT NAK is core-handled (5.1.2.2), so this is split-only. xfer->err_count = 0; channel_xfer_out_wrapup(dwc2, ch_id); - channel_xfer_start(dwc2, ch_id); + channel_xfer_start(dwc2, ch_id, false); } if (xfer->closing == 1) { @@ -1339,7 +1586,29 @@ static void handle_channel_irq(uint8_t rhport, bool in_isr) { dwc2_channel_char_t hcchar = {.value = channel->hcchar}; const uint32_t hcint = channel->hcint; - channel->hcint = hcint; // clear interrupt + // Slave handlers process one cause per pass. If ChHltd arrived with + // another cause, leave it pending so the next pass retires the halt. + const uint32_t hcint_clear = (!is_dma && (hcint & ~HCINT_HALTED)) ? (hcint & ~HCINT_HALTED) : hcint; + channel->hcint = hcint_clear; + + if (is_dma && xfer->aborting && (hcint & HCINT_HALTED)) { + hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; + const bool closing = xfer->closing; + // channel_xfer_start() predicts the PID after all requested packets; + // an aborted transfer may have completed fewer. + if (hcchar.ep_type != HCCHAR_EPTYPE_ISOCHRONOUS) { + const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz}; + edpt->next_pid = hctsiz.pid; + } + xfer->aborting = false; + channel_dealloc(dwc2, ch_id); + if (closing) { + edpt_dealloc(edpt); + } else { + edpt->aborting = 0; + } + continue; + } bool is_done = false; if (is_dma) { @@ -1392,15 +1661,17 @@ static bool handle_sof_irq(uint8_t rhport, bool in_isr) { for(uint8_t ep_id = 0; ep_id < CFG_TUH_DWC2_ENDPOINT_MAX; ep_id++) { hcd_endpoint_t *edpt = &_hcd_data.edpt[ep_id]; if (edpt->closing == 0) { - if (edpt->hcchar_bm.enable && channel_is_periodic(edpt->hcchar) && edpt->uframe_countdown > 0) { - edpt->uframe_countdown -= tu_min32(ucount, edpt->uframe_countdown); + if (edpt->hcchar_bm.enable && channel_is_periodic(edpt->hcchar) && edpt->xfer_pending) { + if (edpt->uframe_countdown > 0) { + edpt->uframe_countdown -= tu_min32(ucount, edpt->uframe_countdown); + } if (edpt->uframe_countdown == 0) { if (!edpt_xfer_kickoff(dwc2, ep_id)) { edpt->uframe_countdown = ucount; // failed to start, try again next frame } } - more_isr = true; + more_isr = more_isr || edpt->xfer_pending; } } } @@ -1520,25 +1791,23 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) { } } - if (gintsts & GINTSTS_HPRTINT) { - // Host port interrupt: source is cleared in HPRT register - // TU_LOG1_HEX(dwc2->hprt); - handle_hprt_irq(rhport, in_isr); - } - - if (gintsts & GINTSTS_HCINT) { - // Host Channel interrupt: source is cleared in HCINT register - // must be handled after TX FIFO empty - handle_channel_irq(rhport, in_isr); - } - if (gintsts & GINTSTS_DISCINT) { - // Device disconnected dwc2->gintsts = GINTSTS_DISCINT; + channel_cleanup_on_disconnect(dwc2); + hcd_event_device_remove(rhport, in_isr); - if (0 == (dwc2->hprt & HPRT_CONN_STATUS)) { - hcd_event_device_remove(rhport, in_isr); + // A fast replug can be visible without a pending connect-detect interrupt. + const uint32_t hprt = dwc2->hprt; + if (!(hprt & HPRT_CONN_DETECT) && (hprt & HPRT_CONN_STATUS)) { + hcd_event_device_attach(rhport, in_isr); } + return; + } + + if (gintsts & GINTSTS_HPRTINT) { + // Host port interrupt: source is cleared in HPRT register + // TU_LOG1_HEX(dwc2->hprt); + handle_hprt_irq(rhport, in_isr); } #if CFG_TUH_DWC2_SLAVE_ENABLE @@ -1572,6 +1841,13 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) { } } #endif + + // Draining the RxFIFO completion status can assert HCINT.XferCompl. Read + // the live status here so the completion is handled in this ISR invocation. + if ((dwc2->gintsts & dwc2->gintmsk) & GINTSTS_HCINT) { + handle_channel_irq(rhport, in_isr); + } + } #endif diff --git a/src/portable/template/dcd_template.c b/src/portable/template/dcd_template.c index 90c672d19..71be2024c 100644 --- a/src/portable/template/dcd_template.c +++ b/src/portable/template/dcd_template.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2018, hathach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2018, Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/template/hcd_template.c b/src/portable/template/hcd_template.c index d2f304407..658db7fd9 100644 --- a/src/portable/template/hcd_template.c +++ b/src/portable/template/hcd_template.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2023 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2023 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c index 5f4b139d8..a734adb7d 100644 --- a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c +++ b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c @@ -1,26 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019-2020 William D. Jones - * Copyright (c) 2019-2020 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 William D. Jones + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/valentyusb/eptri/dcd_eptri.c b/src/portable/valentyusb/eptri/dcd_eptri.c index 1b555b3b7..68a993574 100644 --- a/src/portable/valentyusb/eptri/dcd_eptri.c +++ b/src/portable/valentyusb/eptri/dcd_eptri.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/valentyusb/eptri/dcd_eptri.h b/src/portable/valentyusb/eptri/dcd_eptri.h index 2fe74a712..fef8836c2 100644 --- a/src/portable/valentyusb/eptri/dcd_eptri.h +++ b/src/portable/valentyusb/eptri/dcd_eptri.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/wch/ch32_usbfs_reg.h b/src/portable/wch/ch32_usbfs_reg.h index 415a015dc..5b037281f 100644 --- a/src/portable/wch/ch32_usbfs_reg.h +++ b/src/portable/wch/ch32_usbfs_reg.h @@ -1,26 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2024 Matthew Tran - * Copyright (c) 2024 hathach - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2024 Matthew Tran + * SPDX-FileCopyrightText: Copyright (c) 2024 Ha Thach + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -198,6 +179,14 @@ #endif #endif +// CH32V20x/V30x/F20x USBFS gives endpoint 3 a 1023-byte isochronous packet (CH32FV2x_V3xRM ch23: +// every endpoint is 64 B except EP3 = 1023 B, from EP3's 10-bit R16_UEP3_T_LEN field plus a single +// contiguous >=1023 B DMA buffer — NOT double-buffering, which only yields 2x64 B). +// CH32V103/X035/CH58x cap every endpoint at 64 B. dcd_ch32_usbfs.c reads this to size EP3's buffer. +#if CFG_TUSB_MCU == OPT_MCU_CH32V20X || CFG_TUSB_MCU == OPT_MCU_CH32V307 || CFG_TUSB_MCU == OPT_MCU_CH32F20X + #define CH32_USBFS_EP3_1023_BUFSIZE 1 +#endif + #ifdef __GNUC__ #pragma GCC diagnostic pop #endif diff --git a/src/portable/wch/ch32_usbhs_reg.h b/src/portable/wch/ch32_usbhs_reg.h index 87300b497..d176f0950 100644 --- a/src/portable/wch/ch32_usbhs_reg.h +++ b/src/portable/wch/ch32_usbhs_reg.h @@ -1,26 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2024 Matthew Tran - * Copyright (c) 2024 hathach - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2024 Matthew Tran + * SPDX-FileCopyrightText: Copyright (c) 2024 Ha Thach + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index ece9cde07..ec521224e 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -1,26 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2024 Matthew Tran - * Copyright (c) 2024 hathach - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2024 Matthew Tran + * SPDX-FileCopyrightText: Copyright (c) 2024 Ha Thach + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -35,6 +16,17 @@ /* private defines */ #define EP_MAX (8) + // EP3 IN buffer size. CH32V20x/V30x/F20x USBFS support full-speed iso packets up to 1023 B on + // endpoint 3 (every other endpoint is 64 B); those parts set CH32_USBFS_EP3_1023_BUFSIZE in + // ch32_usbfs_reg.h. V103/X035/CH58x cap every endpoint at 64 B. Overridable per project. + #ifndef CFG_TUD_WCH_USBFS_EP3_BUFSIZE + #ifdef CH32_USBFS_EP3_1023_BUFSIZE + #define CFG_TUD_WCH_USBFS_EP3_BUFSIZE 1023 + #else + #define CFG_TUD_WCH_USBFS_EP3_BUFSIZE 64 + #endif + #endif + // Struct-based EP register access (uniform layout). CH58X has a different register map and // defines EP_DMA/EP_TX_LEN/EP_CTRL itself in ch32_usbfs_reg.h. #if CFG_TUSB_MCU == OPT_MCU_CH583 @@ -126,7 +118,7 @@ struct usb_xfer { static struct { bool ep0_tog; - bool isochronous[EP_MAX]; + bool isochronous[EP_MAX][2]; // per [ep][dir]: an ep number may be iso in one direction struct usb_xfer xfer[EP_MAX][2]; #ifdef CH32_USBFS_EP4_SHARES_EP0 // CH58X buffers laid out by hand so EP0/EP4 don't burn two unused buffer[] slots. EP0 and EP4 @@ -142,21 +134,23 @@ static struct { TU_ATTR_ALIGNED(4) uint8_t ep6_buffer[2][64]; TU_ATTR_ALIGNED(4) uint8_t ep7_buffer[2][64]; #else + // Every endpoint gets a 64-byte OUT + 64-byte IN buffer. TU_ATTR_ALIGNED(4) uint8_t buffer[EP_MAX][2][64]; - // EP3 IN gets an enlarged buffer for full-speed isochronous (packets up to 1023 B). + #if CFG_TUD_WCH_USBFS_EP3_BUFSIZE > 64 + // ...except EP3, which supports full-speed iso packets up to 1023 B on CH32V20x/V30x/F20x, so its + // IN buffer is enlarged (OUT stays 64 B; an OUT transfer >64 B on EP3 would overwrite queued IN). TU_ATTR_ALIGNED(4) struct { - // OUT transfers >64 bytes will overwrite queued IN data! uint8_t out[64]; - uint8_t in[1023]; + uint8_t in[CFG_TUD_WCH_USBFS_EP3_BUFSIZE]; uint8_t pad; } ep3_buffer; + #endif #endif } data; // DMA / copy buffer pointers per endpoint. The WCH USBFS buffer holds OUT (RX) at offset 0 and -// IN (TX) at +64; EP0 is half-duplex and reuses its OUT chunk for IN; EP3 has an enlarged IN -// buffer for throughput. On CH58X, EP0/EP4 share ep0_ep4_buffer and the regular endpoints use -// their own named buffer (see the struct above). +// IN (TX) at +64; EP0 is half-duplex and reuses its OUT chunk for IN. On CH58X, EP0/EP4 share +// ep0_ep4_buffer and the regular endpoints use their own named buffer (see the struct above). #ifdef CH32_USBFS_EP4_SHARES_EP0 // OUT base of the regular CH58X endpoints (EP1/2/3/5/6/7; EP0/EP4 share ep0_ep4_buffer). static inline uint8_t* ch58x_ep_buffer(uint8_t ep) { @@ -176,7 +170,9 @@ static inline uint32_t ep_dma_addr(uint8_t ep) { if (ep == 0 || ep == 4) { return (uint32_t) &data.ep0_ep4_buffer[0]; } // EP4 shares EP0's DMA return (uint32_t) ch58x_ep_buffer(ep); #else - if (ep == 3) { return (uint32_t) &data.ep3_buffer.out[0]; } + #if CFG_TUD_WCH_USBFS_EP3_BUFSIZE > 64 + if (ep == 3) { return (uint32_t) &data.ep3_buffer.out[0]; } // EP3 has an enlarged IN buffer + #endif return (uint32_t) &data.buffer[ep][0]; #endif } @@ -187,7 +183,9 @@ static inline uint8_t* ep_out_buf(uint8_t ep) { if (ep == 4) { return &data.ep0_ep4_buffer[64]; } return ch58x_ep_buffer(ep); #else + #if CFG_TUD_WCH_USBFS_EP3_BUFSIZE > 64 if (ep == 3) { return data.ep3_buffer.out; } + #endif return data.buffer[ep][TUSB_DIR_OUT]; #endif } @@ -199,7 +197,9 @@ static inline uint8_t* ep_in_buf(uint8_t ep) { return ch58x_ep_buffer(ep) + 64; // IN at +64 within the endpoint's 128-byte buffer #else if (ep == 0) { return data.buffer[0][TUSB_DIR_OUT]; } // EP0 half-duplex: IN reuses OUT chunk - if (ep == 3) { return data.ep3_buffer.in; } + #if CFG_TUD_WCH_USBFS_EP3_BUFSIZE > 64 + if (ep == 3) { return data.ep3_buffer.in; } // enlarged IN buffer for full-speed iso + #endif return data.buffer[ep][TUSB_DIR_IN]; #endif } @@ -221,9 +221,8 @@ static void update_in(uint8_t rhport, uint8_t ep, bool force) { if (force || xfer->len) { size_t len = TU_MIN(xfer->max_size, xfer->len); #if CFG_TUSB_MCU == OPT_MCU_CH583 - // Every CH58x endpoint buffer is 64 bytes. Isochronous (which would push max_size up to 1023) - // is refused in dcd_edpt_iso_alloc(), but some classes (e.g. video) ignore that result, so cap - // the copy here to guarantee we never write past the buffer into a neighbouring endpoint's. + // Every CH58x endpoint buffer is 64 bytes; cap the copy so an iso mps a class mistakenly set + // larger can't write past the buffer into a neighbouring endpoint's. len = TU_MIN(len, 64u); #endif memcpy(ep_in_buf(ep), xfer->buffer, len); @@ -235,7 +234,7 @@ static void update_in(uint8_t rhport, uint8_t ep, bool force) { if (ep == 0) { ep_tx_ctrl_set(0, USBFS_EP_T_RES_ACK | (data.ep0_tog ? USBFS_EP_T_TOG : 0)); data.ep0_tog = !data.ep0_tog; - } else if (data.isochronous[ep]) { + } else if (data.isochronous[ep][TUSB_DIR_IN]) { ep_tx_set_response(ep, USBFS_EP_T_RES_NYET); } else { ep_tx_set_response(ep, USBFS_EP_T_RES_ACK); @@ -244,7 +243,7 @@ static void update_in(uint8_t rhport, uint8_t ep, bool force) { xfer->valid = false; if (ep == 0) { ep_tx_ctrl_set(0, USBFS_EP_T_RES_NAK | (data.ep0_tog ? USBFS_EP_T_TOG : 0)); - } else if (!data.isochronous[ep]) { + } else if (!data.isochronous[ep][TUSB_DIR_IN]) { ep_tx_set_response(ep, USBFS_EP_T_RES_NAK); } dcd_event_xfer_complete(rhport, ep | TUSB_DIR_IN_MASK, xfer->processed_len, XFER_RESULT_SUCCESS, true); @@ -273,7 +272,7 @@ static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { ep_rx_set_response(0, USBFS_EP_R_RES_NAK); } else { uint8_t rx_res = - data.isochronous[ep] ? USBFS_EP_R_RES_NYET : (xfer->valid ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK); + data.isochronous[ep][TUSB_DIR_OUT] ? USBFS_EP_R_RES_NYET : (xfer->valid ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK); ep_rx_set_response(ep, rx_res); } } @@ -338,12 +337,14 @@ void dcd_int_handler(uint8_t rhport) { // Drop an OUT packet whose data toggle doesn't match what we expect -- a host retransmit // after a lost ACK, or a host that doesn't alternate DATA0/DATA1. The hardware auto-toggle // does not reject these on its own, so the check is needed on every variant. EP0 keeps its - // own toggle via the SETUP/status flow and is exempt. - if (ep != 0 && !(int_st & USBFS_INT_ST_TOG_OK)) { break; } + // own toggle via the SETUP/status flow and is exempt; isochronous is DATA0-only (no toggle), + // so its packets must not be toggle-checked. + if (ep != 0 && !data.isochronous[ep][TUSB_DIR_OUT] && !(int_st & USBFS_INT_ST_TOG_OK)) { break; } #ifdef CH32_USBFS_EP_MANUAL_TOG // CH58x has no hardware auto-toggle: advance the expected RX toggle after each accepted packet // (EP0 included -- it also has no auto-toggle and a control-OUT data stage can span packets). - EP_CTRL(ep) ^= USBFS_EPC_R_TOG; + // Iso endpoints are DATA0-only, so leave them alone (matches the PID_IN path). + if (!data.isochronous[ep][TUSB_DIR_OUT]) { EP_CTRL(ep) ^= USBFS_EPC_R_TOG; } #endif update_out(rhport, ep, rx_len); break; @@ -352,7 +353,8 @@ void dcd_int_handler(uint8_t rhport) { case PID_IN: #ifdef CH32_USBFS_EP_MANUAL_TOG // Manual toggle: flip the TX toggle after each ACK'd IN packet (EP0 manages its own). - if (ep != 0) { EP_CTRL(ep) ^= USBFS_EPC_T_TOG; } + // Isochronous transfers are DATA0-only (no toggle), so leave iso endpoints alone. + if (ep != 0 && !data.isochronous[ep][TUSB_DIR_IN]) { EP_CTRL(ep) ^= USBFS_EPC_T_TOG; } #endif update_in(rhport, ep, false); break; @@ -462,6 +464,7 @@ bool dcd_edpt_open(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { uint8_t dir = tu_edpt_dir(desc_ep->bEndpointAddress); TU_ASSERT(ep < EP_MAX); + data.isochronous[ep][dir] = false; // (re)opening as a non-iso endpoint clears any stale iso flag data.xfer[ep][dir].max_size = tu_edpt_packet_size(desc_ep); if (ep != 0) { @@ -483,31 +486,38 @@ void dcd_edpt_close_all(uint8_t rhport) { bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { (void)rhport; - (void)ep_addr; - (void)largest_packet_size; -#if CFG_TUSB_MCU == OPT_MCU_CH583 - // No isochronous support on CH58x: its 8-bit T_LEN caps a packet at 255B and the endpoints use - // plain 64-byte buffers, so accepting an iso max_size (up to 1023) would let update_in()/ - // update_out() run off the end of the buffer into neighbouring ones. Refuse it outright. - return false; -#else uint8_t ep = tu_edpt_number(ep_addr); uint8_t dir = tu_edpt_dir(ep_addr); + TU_ASSERT(ep < EP_MAX); + + // Endpoint buffers are 64 B, except EP3 IN which is enlarged for full-speed iso on the parts that + // support 1023-byte EP3 packets (CH32V20x/V30x/F20x; CFG_TUD_WCH_USBFS_EP3_BUFSIZE). Reject a + // larger mps rather than running off the end into the neighbouring endpoint's memory. + uint16_t max_packet = 64; +#if CFG_TUD_WCH_USBFS_EP3_BUFSIZE > 64 + if (ep == 3 && dir == TUSB_DIR_IN) { max_packet = CFG_TUD_WCH_USBFS_EP3_BUFSIZE; } +#endif + TU_VERIFY(largest_packet_size <= max_packet); - data.isochronous[ep] = true; + data.isochronous[ep][dir] = true; data.xfer[ep][dir].max_size = largest_packet_size; return true; -#endif } bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { (void)rhport; - (void)desc_ep; -#if CFG_TUSB_MCU == OPT_MCU_CH583 - return false; // CH58x has no isochronous support (see dcd_edpt_iso_alloc) -#else + const uint8_t ep = tu_edpt_number(desc_ep->bEndpointAddress); + const uint8_t dir = tu_edpt_dir(desc_ep->bEndpointAddress); + + // a transfer armed before SET_INTERFACE survives to here (no dcd close on this port): drop the + // stale descriptor and NAK the endpoint so the ISR can't complete it against the old buffer + data.xfer[ep][dir].valid = false; + if (dir == TUSB_DIR_IN) { + ep_tx_set_response(ep, USBFS_EP_T_RES_NAK); + } else { + ep_rx_set_response(ep, USBFS_EP_R_RES_NAK); + } return true; -#endif } bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes, bool is_isr) { @@ -529,7 +539,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to if (dir == TUSB_DIR_IN) { update_in(rhport, ep, true); } else { - uint8_t rx_res = data.isochronous[ep] ? USBFS_EP_R_RES_NYET : USBFS_EP_R_RES_ACK; + uint8_t rx_res = data.isochronous[ep][TUSB_DIR_OUT] ? USBFS_EP_R_RES_NYET : USBFS_EP_R_RES_ACK; ep_rx_set_response(ep, rx_res); } dcd_int_enable(rhport); @@ -565,9 +575,15 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { ep_rx_ctrl_set(0, USBFS_EP_R_RES_ACK); } } else { - // clear-stall resets the toggle to DATA0 (USB spec); manual-toggle parts then re-sync via ISR + // clear-stall resets the toggle to DATA0 (USB spec); manual-toggle parts then re-sync via ISR. + // Preserve an in-flight receive: if a read is still armed (the class driver considers it + // submitted and won't re-arm), fall back to ACK, not NAK, or the endpoint NAKs forever and the + // host times out (usbtest toggle test 29 clears the halt between bulk writes on an armed EP). if (dir == TUSB_DIR_OUT) { - ep_rx_ctrl_set(ep, EP_R_AUTO_TOG | USBFS_EP_R_RES_NAK); + uint8_t res = data.xfer[ep][TUSB_DIR_OUT].valid + ? (data.isochronous[ep][TUSB_DIR_OUT] ? USBFS_EP_R_RES_NYET : USBFS_EP_R_RES_ACK) + : USBFS_EP_R_RES_NAK; + ep_rx_ctrl_set(ep, EP_R_AUTO_TOG | res); } else { ep_tx_ctrl_set(ep, EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK); } diff --git a/src/portable/wch/dcd_ch32_usbhs.c b/src/portable/wch/dcd_ch32_usbhs.c index ea3b052ad..577f86582 100644 --- a/src/portable/wch/dcd_ch32_usbhs.c +++ b/src/portable/wch/dcd_ch32_usbhs.c @@ -1,26 +1,8 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2022 Greg Davill - * Copyright (c) 2023 Denis Krasutski - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2022 Greg Davill + * SPDX-FileCopyrightText: Copyright (c) 2023 Denis Krasutski + * SPDX-FileCopyrightText: Copyright (c) 2022 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -366,8 +348,16 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { const tusb_dir_t dir = tu_edpt_dir(ep_addr); if (dir == TUSB_DIR_OUT) { - EP_RX_CTRL(ep_num) = USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0; - ep_data_tog[ep_num][TUSB_DIR_OUT] = false; + ep_data_tog[ep_num][TUSB_DIR_OUT] = false; // clear-halt resets the toggle to DATA0 + xfer_ctl_t *xfer = XFER_CTL_BASE(ep_num, TUSB_DIR_OUT); + if (xfer->valid) { + // A receive is still armed (the class driver considers it submitted and won't re-arm it); + // re-queue it (ACK/NYET) instead of leaving it NAKing, or the endpoint NAKs forever after + // clear-halt (usbtest toggle test 29 clears the halt on an armed bulk-OUT pipe). + queue_out_packet(ep_num, xfer); + } else { + EP_RX_CTRL(ep_num) = USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0; + } } else { EP_TX_CTRL(ep_num) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; ep_data_tog[ep_num][TUSB_DIR_IN] = false; diff --git a/src/portable/wch/hcd_ch32_usbfs.c b/src/portable/wch/hcd_ch32_usbfs.c index 7bbf122dd..5caa1bbf1 100644 --- a/src/portable/wch/hcd_ch32_usbfs.c +++ b/src/portable/wch/hcd_ch32_usbfs.c @@ -1,25 +1,7 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2024 Mitsumine Suzu (verylowfreq) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2024 Mitsumine Suzu (verylowfreq) + * SPDX-FileCopyrightText: Copyright (c) 2024 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/tinyusb.mk b/src/tinyusb.mk index 365043927..941791670 100644 --- a/src/tinyusb.mk +++ b/src/tinyusb.mk @@ -26,4 +26,3 @@ TINYUSB_SRC_C += \ src/class/midi/midi_host.c \ src/class/midi/midi2_host.c \ src/class/msc/msc_host.c \ - src/class/vendor/vendor_host.c \ diff --git a/src/tusb.c b/src/tusb.c index 634cbc10b..e1548e8c1 100644 --- a/src/tusb.c +++ b/src/tusb.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -293,7 +274,7 @@ bool tu_edpt_validate(const tusb_desc_endpoint_t *desc_ep, tusb_speed_t speed) { #endif bool tu_bind_driver_to_ep_itf(uint8_t driver_id, uint8_t ep2drv[][2], uint8_t itf2drv[], uint8_t itf_max, - const uint8_t *p_desc, uint16_t desc_len) { + uint8_t ep_max, const uint8_t *p_desc, uint16_t desc_len) { const uint8_t *desc_end = p_desc + desc_len; while (tu_desc_in_bounds(p_desc, desc_end)) { const uint8_t desc_type = tu_desc_type(p_desc); @@ -302,6 +283,7 @@ bool tu_bind_driver_to_ep_itf(uint8_t driver_id, uint8_t ep2drv[][2], uint8_t it const uint8_t ep_addr = ((const tusb_desc_endpoint_t *)p_desc)->bEndpointAddress; const uint8_t ep_num = tu_edpt_number(ep_addr); const uint8_t ep_dir = tu_edpt_dir(ep_addr); + TU_ASSERT(ep_num < ep_max); ep2drv[ep_num][ep_dir] = driver_id; } else if (desc_type == TUSB_DESC_INTERFACE) { const tusb_desc_interface_t *desc_itf = (const tusb_desc_interface_t *)p_desc; diff --git a/src/tusb.h b/src/tusb.h index aa6b461e5..cdf6f8171 100644 --- a/src/tusb.h +++ b/src/tusb.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -67,9 +48,6 @@ #include "class/midi/midi2_host.h" #endif - #if CFG_TUH_VENDOR - #include "class/vendor/vendor_host.h" - #endif #else #ifndef tuh_int_handler #define tuh_int_handler(...) diff --git a/src/tusb_option.h b/src/tusb_option.h index b23b37467..1eb23fb00 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -223,6 +204,12 @@ // HPMicro #define OPT_MCU_HPM 2600 ///< HPMicro +// Puya +#define OPT_MCU_PY32F0 2700 ///< Puya PY32F0 + +// Geehy +#define OPT_MCU_APM32F0XX 2800 ///< Geehy APM32F0xx + // Check if configured MCU is one of listed // Apply TU_MCU_IS_EQUAL with || as separator to list of input #define TU_MCU_IS_EQUAL(_m) (CFG_TUSB_MCU == (_m)) @@ -259,6 +246,16 @@ #define OPT_MODE_SPEED_MASK 0xff00u //--------------------------------------------------------------------+ +// Validation Level +// Optional validation of data received from the USB peer, traded against code size. Coverage is parser-specific +// and expanded incrementally. CFG_TUSB_VALIDATION_LEVEL sets the default for both device and host; use the +// CFG_TUD_VALIDATION_LEVEL / CFG_TUH_VALIDATION_LEVEL overrides when the roles need different policies. +//--------------------------------------------------------------------+ +#define TUSB_VALIDATION_NONE 0 ///< trusted peers, minimal code size +#define TUSB_VALIDATION_BASIC 1 ///< structural memory-safety checks where supported +#define TUSB_VALIDATION_STRICT 2 ///< additional USB and class-specific conformance checks + +//--------------------------------------------------------------------+ // Include tusb_config.h //--------------------------------------------------------------------+ @@ -272,6 +269,46 @@ #include "common/tusb_mcu.h" //--------------------------------------------------------------------+ +// Validation Options +//--------------------------------------------------------------------+ + +#ifndef CFG_TUSB_VALIDATION_LEVEL + #define CFG_TUSB_VALIDATION_LEVEL TUSB_VALIDATION_BASIC +#endif + +#ifndef CFG_TUD_VALIDATION_LEVEL + #define CFG_TUD_VALIDATION_LEVEL CFG_TUSB_VALIDATION_LEVEL +#endif + +#ifndef CFG_TUH_VALIDATION_LEVEL + #define CFG_TUH_VALIDATION_LEVEL CFG_TUSB_VALIDATION_LEVEL +#endif + +#if (CFG_TUSB_VALIDATION_LEVEL < TUSB_VALIDATION_NONE) || \ + (CFG_TUSB_VALIDATION_LEVEL > TUSB_VALIDATION_STRICT) + #error "CFG_TUSB_VALIDATION_LEVEL must be TUSB_VALIDATION_NONE, TUSB_VALIDATION_BASIC, or TUSB_VALIDATION_STRICT" +#endif + +#if (CFG_TUD_VALIDATION_LEVEL < TUSB_VALIDATION_NONE) || \ + (CFG_TUD_VALIDATION_LEVEL > TUSB_VALIDATION_STRICT) + #error "CFG_TUD_VALIDATION_LEVEL must be TUSB_VALIDATION_NONE, TUSB_VALIDATION_BASIC, or TUSB_VALIDATION_STRICT" +#endif + +#if (CFG_TUH_VALIDATION_LEVEL < TUSB_VALIDATION_NONE) || \ + (CFG_TUH_VALIDATION_LEVEL > TUSB_VALIDATION_STRICT) + #error "CFG_TUH_VALIDATION_LEVEL must be TUSB_VALIDATION_NONE, TUSB_VALIDATION_BASIC, or TUSB_VALIDATION_STRICT" +#endif + +// Validation conditions are short-circuited at lower levels and compile out when the result is unused. +#define TUD_VALIDATION_CHECK(_level, _cond) ((CFG_TUD_VALIDATION_LEVEL < (_level)) || (_cond)) +#define TUH_VALIDATION_CHECK(_level, _cond) ((CFG_TUH_VALIDATION_LEVEL < (_level)) || (_cond)) + +#define TUD_VALIDATE_BASIC(_cond) TUD_VALIDATION_CHECK(TUSB_VALIDATION_BASIC, _cond) +#define TUH_VALIDATE_BASIC(_cond) TUH_VALIDATION_CHECK(TUSB_VALIDATION_BASIC, _cond) +#define TUD_VALIDATE_STRICT(_cond) TUD_VALIDATION_CHECK(TUSB_VALIDATION_STRICT, _cond) +#define TUH_VALIDATE_STRICT(_cond) TUH_VALIDATION_CHECK(TUSB_VALIDATION_STRICT, _cond) + +//--------------------------------------------------------------------+ // USBIP //--------------------------------------------------------------------+ @@ -369,7 +406,9 @@ #if defined(TUP_USBIP_MUSB) #define CFG_TUD_EDPT_DEDICATED_HWFIFO 1 #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 4 // 32 bit data - #define CFG_TUSB_FIFO_HWFIFO_DATA_ODD_16BIT_ACCESS // allow odd 16bit access + #if !defined(TUP_USBIP_MUSB_PY32) + #define CFG_TUSB_FIFO_HWFIFO_DATA_ODD_16BIT_ACCESS // allow odd 16bit access + #endif #define CFG_TUSB_FIFO_HWFIFO_DATA_ODD_8BIT_ACCESS // allow odd 8bit access #define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 0 // fixed hwfifo #endif @@ -713,6 +752,7 @@ #ifndef CFG_TUH_ENUMERATION_BUFSIZE #define CFG_TUH_ENUMERATION_BUFSIZE 256 #endif + #endif // CFG_TUH_ENABLED // Attribute to place data in accessible RAM for host controller (default: CFG_TUSB_MEM_SECTION) @@ -854,9 +894,6 @@ #define CFG_TUH_MSC 0 #endif -#ifndef CFG_TUH_VENDOR - #define CFG_TUH_VENDOR 0 -#endif #ifndef CFG_TUH_API_EDPT_XFER #define CFG_TUH_API_EDPT_XFER 0 diff --git a/src/typec/pd_types.h b/src/typec/pd_types.h index eebcec632..1592305d8 100644 --- a/src/typec/pd_types.h +++ b/src/typec/pd_types.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2023 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2023 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/typec/tcd.h b/src/typec/tcd.h index 6e18cd063..75692ad15 100644 --- a/src/typec/tcd.h +++ b/src/typec/tcd.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2023 Ha Thach ([email protected]) for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2023 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ diff --git a/src/typec/usbc.c b/src/typec/usbc.c index 8071e93c3..5b0e4423a 100644 --- a/src/typec/usbc.c +++ b/src/typec/usbc.c @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2023 Ha Thach ([email protected]) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2023 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -50,6 +31,7 @@ static bool _usbc_inited = false; // if port is initialized static bool _port_inited[TUP_TYPEC_RHPORTS_NUM]; +static bool _port_attached[TUP_TYPEC_RHPORTS_NUM]; // Max possible PD size is 262 bytes static uint8_t _rx_buf[64] TU_ATTR_ALIGNED(4); @@ -76,6 +58,11 @@ TU_ATTR_WEAK bool tuc_pd_control_received_cb(uint8_t rhport, pd_header_t const* return false; } +TU_ATTR_WEAK void tuc_attach_changed_cb(uint8_t rhport, bool attached) { + (void) rhport; + (void) attached; +} + TU_ATTR_WEAK void tcd_connect(uint8_t rhport) { (void) rhport; } @@ -109,6 +96,7 @@ bool tuc_init(uint8_t rhport, uint32_t port_type) { // Initialize stack if (!_usbc_inited) { tu_memclr(_port_inited, sizeof(_port_inited)); + tu_memclr(_port_attached, sizeof(_port_attached)); _usbc_q = osal_queue_create(&_usbc_qdef); TU_ASSERT(_usbc_q != NULL); @@ -143,8 +131,14 @@ void tuc_task_ext(uint32_t timeout_ms, bool in_isr) { if (!osal_queue_receive(_usbc_q, &event, timeout_ms)) return; switch (event.event_id) { - case TCD_EVENT_CC_CHANGED: + case TCD_EVENT_CC_CHANGED: { + bool const attached = event.cc_changed.cc_state[0] != 0 || event.cc_changed.cc_state[1] != 0; + if (_port_attached[event.rhport] != attached) { + _port_attached[event.rhport] = attached; + tuc_attach_changed_cb(event.rhport, attached); + } break; + } case TCD_EVENT_RX_COMPLETE: // TODO process message here in ISR, move to thread later diff --git a/src/typec/usbc.h b/src/typec/usbc.h index ed8595d27..fc4773b07 100644 --- a/src/typec/usbc.h +++ b/src/typec/usbc.h @@ -1,25 +1,6 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2023 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-FileCopyrightText: Copyright (c) 2023 Ha Thach (tinyusb.org) + * SPDX-License-Identifier: MIT * * This file is part of the TinyUSB stack. */ @@ -84,6 +65,7 @@ extern void tcd_int_handler(uint8_t rhport); bool tuc_pd_data_received_cb(uint8_t rhport, pd_header_t const* header, uint8_t const* dobj, uint8_t const* p_end); bool tuc_pd_control_received_cb(uint8_t rhport, pd_header_t const* header); +void tuc_attach_changed_cb(uint8_t rhport, bool attached); //--------------------------------------------------------------------+ // |
