/** * Copyright (c) 2021 Raspberry Pi (Trading) Ltd. * * SPDX-License-Identifier: BSD-3-Clause */ #include "tusb.h" #include "pico/bootrom.h" #if PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE && !(PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_BOOTSEL || PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_FLASH_BOOT) #warning PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE has been selected but neither PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_BOOTSEL nor PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_FLASH_BOOT have been selected. #endif #if PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE #include "pico/stdio_usb/reset_interface.h" #include "hardware/watchdog.h" #include "device/usbd_pvt.h" static uint8_t itf_num; static void resetd_init(void) { } static void resetd_reset(uint8_t __unused rhport) { itf_num = 0; } static uint16_t resetd_open(uint8_t __unused rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass && RESET_INTERFACE_SUBCLASS == itf_desc->bInterfaceSubClass && RESET_INTERFACE_PROTOCOL == itf_desc->bInterfaceProtocol, 0); uint16_t const drv_len = sizeof(tusb_desc_interface_t); TU_VERIFY(max_len >= drv_len, 0); itf_num = itf_desc->bInterfaceNumber; return drv_len; } // Support for parameterized reset via vendor interface control request static bool resetd_control_request_cb(uint8_t __unused rhport, tusb_control_request_t const *request) { if (request->wIndex == itf_num) { #if PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_BOOTSEL if (request->bRequest == RESET_REQUEST_BOOTSEL) { #ifdef PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED uint gpio_mask = 1u << PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED; #else uint gpio_mask = 0u; #endif #if !PICO_STDIO_USB_RESET_BOOTSEL_FIXED_ACTIVITY_LED if (request->wValue & 0x100) { gpio_mask = 1u << (request->wValue >> 9u); } #endif reset_usb_boot(gpio_mask, (request->wValue & 0x7f) | PICO_STDIO_USB_RESET_BOOTSEL_INTERFACE_DISABLE_MASK); // does not return, otherwise we'd return true } #endif #if PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_FLASH_BOOT if (request->bRequest == RESET_REQUEST_FLASH) { watchdog_reboot(0, SRAM_END, PICO_STDIO_USB_RESET_RESET_TO_FLASH_DELAY_MS); return true; } #endif } return false; } static bool resetd_control_complete_cb(uint8_t __unused rhport, tusb_control_request_t __unused const *request) { return true; } static bool resetd_xfer_cb(uint8_t __unused rhport, uint8_t __unused ep_addr, xfer_result_t __unused result, uint32_t __unused xferred_bytes) { return true; } static usbd_class_driver_t const _resetd_driver = { #if CFG_TUSB_DEBUG >= 2 .name = "RESET", #endif .init = resetd_init, .reset = resetd_reset, .open = resetd_open, .control_request = resetd_control_request_cb, .control_complete = resetd_control_complete_cb, .xfer_cb = resetd_xfer_cb, .sof = NULL }; // Implement callback to add our custom driver usbd_class_driver_t const *usbd_app_driver_get_cb(uint8_t *driver_count) { *driver_count = 1; return &_resetd_driver; } #endif #if PICO_STDIO_USB_ENABLE_RESET_VIA_BAUD_RATE // Support for default BOOTSEL reset by changing baud rate void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding) { if (p_line_coding->bit_rate == PICO_STDIO_USB_RESET_MAGIC_BAUD_RATE) { #ifdef PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED const uint gpio_mask = 1u << PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED; #else const uint gpio_mask = 0u; #endif reset_usb_boot(gpio_mask, PICO_STDIO_USB_RESET_BOOTSEL_INTERFACE_DISABLE_MASK); } } #endif