1 /**
2 * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6 #include "tusb.h"
7
8 #include "pico/bootrom.h"
9
10 #if !defined(LIB_TINYUSB_HOST) && !defined(LIB_TINYUSB_DEVICE)
11
12 #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)
13 #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.
14 #endif
15
16 #if PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE
17 #include "pico/stdio_usb/reset_interface.h"
18 #include "hardware/watchdog.h"
19 #include "device/usbd_pvt.h"
20
21 static uint8_t itf_num;
22
resetd_init(void)23 static void resetd_init(void) {
24 }
25
resetd_reset(uint8_t __unused rhport)26 static void resetd_reset(uint8_t __unused rhport) {
27 itf_num = 0;
28 }
29
resetd_open(uint8_t __unused rhport,tusb_desc_interface_t const * itf_desc,uint16_t max_len)30 static uint16_t resetd_open(uint8_t __unused rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len) {
31 TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass &&
32 RESET_INTERFACE_SUBCLASS == itf_desc->bInterfaceSubClass &&
33 RESET_INTERFACE_PROTOCOL == itf_desc->bInterfaceProtocol, 0);
34
35 uint16_t const drv_len = sizeof(tusb_desc_interface_t);
36 TU_VERIFY(max_len >= drv_len, 0);
37
38 itf_num = itf_desc->bInterfaceNumber;
39 return drv_len;
40 }
41
42 // Support for parameterized reset via vendor interface control request
resetd_control_xfer_cb(uint8_t __unused rhport,uint8_t stage,tusb_control_request_t const * request)43 static bool resetd_control_xfer_cb(uint8_t __unused rhport, uint8_t stage, tusb_control_request_t const * request) {
44 // nothing to do with DATA & ACK stage
45 if (stage != CONTROL_STAGE_SETUP) return true;
46
47 if (request->wIndex == itf_num) {
48
49 #if PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_BOOTSEL
50 if (request->bRequest == RESET_REQUEST_BOOTSEL) {
51 #ifdef PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED
52 uint gpio_mask = 1u << PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED;
53 #else
54 uint gpio_mask = 0u;
55 #endif
56 #if !PICO_STDIO_USB_RESET_BOOTSEL_FIXED_ACTIVITY_LED
57 if (request->wValue & 0x100) {
58 gpio_mask = 1u << (request->wValue >> 9u);
59 }
60 #endif
61 reset_usb_boot(gpio_mask, (request->wValue & 0x7f) | PICO_STDIO_USB_RESET_BOOTSEL_INTERFACE_DISABLE_MASK);
62 // does not return, otherwise we'd return true
63 }
64 #endif
65
66 #if PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_FLASH_BOOT
67 if (request->bRequest == RESET_REQUEST_FLASH) {
68 watchdog_reboot(0, 0, PICO_STDIO_USB_RESET_RESET_TO_FLASH_DELAY_MS);
69 return true;
70 }
71 #endif
72
73 }
74 return false;
75 }
76
resetd_xfer_cb(uint8_t __unused rhport,uint8_t __unused ep_addr,xfer_result_t __unused result,uint32_t __unused xferred_bytes)77 static bool resetd_xfer_cb(uint8_t __unused rhport, uint8_t __unused ep_addr, xfer_result_t __unused result, uint32_t __unused xferred_bytes) {
78 return true;
79 }
80
81 static usbd_class_driver_t const _resetd_driver =
82 {
83 #if CFG_TUSB_DEBUG >= 2
84 .name = "RESET",
85 #endif
86 .init = resetd_init,
87 .reset = resetd_reset,
88 .open = resetd_open,
89 .control_xfer_cb = resetd_control_xfer_cb,
90 .xfer_cb = resetd_xfer_cb,
91 .sof = NULL
92 };
93
94 // Implement callback to add our custom driver
usbd_app_driver_get_cb(uint8_t * driver_count)95 usbd_class_driver_t const *usbd_app_driver_get_cb(uint8_t *driver_count) {
96 *driver_count = 1;
97 return &_resetd_driver;
98 }
99 #endif
100
101 #if PICO_STDIO_USB_ENABLE_RESET_VIA_BAUD_RATE
102 // Support for default BOOTSEL reset by changing baud rate
tud_cdc_line_coding_cb(__unused uint8_t itf,cdc_line_coding_t const * p_line_coding)103 void tud_cdc_line_coding_cb(__unused uint8_t itf, cdc_line_coding_t const* p_line_coding) {
104 if (p_line_coding->bit_rate == PICO_STDIO_USB_RESET_MAGIC_BAUD_RATE) {
105 #ifdef PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED
106 const uint gpio_mask = 1u << PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED;
107 #else
108 const uint gpio_mask = 0u;
109 #endif
110 reset_usb_boot(gpio_mask, PICO_STDIO_USB_RESET_BOOTSEL_INTERFACE_DISABLE_MASK);
111 }
112 }
113 #endif
114
115 #endif