1 /* 2 * Copyright (c) 2024 Nordic Semiconductor ASA 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7 /** 8 * @file 9 * @brief USB Device Firmware Upgrade (DFU) public header 10 * 11 * Header exposes API for registering DFU images. 12 */ 13 14 #ifndef ZEPHYR_INCLUDE_USB_CLASS_USBD_DFU_H 15 #define ZEPHYR_INCLUDE_USB_CLASS_USBD_DFU_H 16 17 #include <stdint.h> 18 19 /* DFU Class Subclass */ 20 #define USB_DFU_SUBCLASS 0x01 21 22 /* DFU Class runtime Protocol */ 23 #define USB_DFU_PROTOCOL_RUNTIME 0x01 24 25 /* DFU Class DFU mode Protocol */ 26 #define USB_DFU_PROTOCOL_DFU 0x02 27 28 /* DFU Class Specific Requests */ 29 #define USB_DFU_REQ_DETACH 0x00 30 #define USB_DFU_REQ_DNLOAD 0x01 31 #define USB_DFU_REQ_UPLOAD 0x02 32 #define USB_DFU_REQ_GETSTATUS 0x03 33 #define USB_DFU_REQ_CLRSTATUS 0x04 34 #define USB_DFU_REQ_GETSTATE 0x05 35 #define USB_DFU_REQ_ABORT 0x06 36 37 /* Run-Time DFU Functional Descriptor */ 38 struct usb_dfu_descriptor { 39 uint8_t bLength; 40 uint8_t bDescriptorType; 41 uint8_t bmAttributes; 42 uint16_t wDetachTimeOut; 43 uint16_t wTransferSize; 44 uint16_t bcdDFUVersion; 45 } __packed; 46 47 /* DFU Functional Descriptor Type */ 48 #define USB_DESC_DFU_FUNCTIONAL 0x21 49 50 /* DFU attributes DFU Functional Descriptor */ 51 #define USB_DFU_ATTR_WILL_DETACH BIT(3) 52 #define USB_DFU_ATTR_MANIFESTATION_TOLERANT BIT(2) 53 #define USB_DFU_ATTR_CAN_UPLOAD BIT(1) 54 #define USB_DFU_ATTR_CAN_DNLOAD BIT(0) 55 56 /* DFU Specification release */ 57 #define USB_DFU_VERSION 0x0110 58 59 /* DFU device status */ 60 enum usb_dfu_status { 61 ERR_OK = 0x00, 62 ERR_TARGET = 0x01, 63 ERR_FILE = 0x02, 64 ERR_WRITE = 0x03, 65 ERR_ERASE = 0x04, 66 ERR_CHECK_ERASED = 0x05, 67 ERR_PROG = 0x06, 68 ERR_VERIFY = 0x07, 69 ERR_ADDRESS = 0x08, 70 ERR_NOTDONE = 0x09, 71 ERR_FIRMWARE = 0x0A, 72 ERR_VENDOR = 0x0B, 73 ERR_USBR = 0x0C, 74 ERR_POR = 0x0D, 75 ERR_UNKNOWN = 0x0E, 76 ERR_STALLEDPKT = 0x0F, 77 }; 78 79 /* DFU device states */ 80 enum usb_dfu_state { 81 APP_IDLE = 0, 82 APP_DETACH = 1, 83 DFU_IDLE = 2, 84 DFU_DNLOAD_SYNC = 3, 85 DFU_DNBUSY = 4, 86 DFU_DNLOAD_IDLE = 5, 87 DFU_MANIFEST_SYNC = 6, 88 DFU_MANIFEST = 7, 89 DFU_MANIFEST_WAIT_RST = 8, 90 DFU_UPLOAD_IDLE = 9, 91 DFU_ERROR = 10, 92 DFU_STATE_MAX = 11, 93 }; 94 95 struct usbd_dfu_image { 96 const char *name; 97 struct usb_if_descriptor *const if_desc; 98 void *const priv; 99 struct usbd_desc_node *const sd_nd; 100 bool (*next_cb)(void *const priv, 101 const enum usb_dfu_state state, const enum usb_dfu_state next); 102 int (*read_cb)(void *const priv, 103 const uint32_t block, const uint16_t size, 104 uint8_t buf[static CONFIG_USBD_DFU_TRANSFER_SIZE]); 105 int (*write_cb)(void *const priv, 106 const uint32_t block, const uint16_t size, 107 const uint8_t buf[static CONFIG_USBD_DFU_TRANSFER_SIZE]); 108 }; 109 110 /** 111 * @brief USB DFU device update API 112 * @defgroup usbd_dfu USB DFU device update API 113 * @ingroup usb 114 * @{ 115 */ 116 117 /** 118 * @brief Define USB DFU image 119 * 120 * Use this macro to create USB DFU image 121 * 122 * The callbacks must be in form: 123 * 124 * @code{.c} 125 * static int read(void *const priv, const uint32_t block, const uint16_t size, 126 * uint8_t buf[static CONFIG_USBD_DFU_TRANSFER_SIZE]) 127 * { 128 * int len; 129 * 130 * return len; 131 * } 132 * 133 * static int write(void *const priv, const uint32_t block, const uint16_t size, 134 * const uint8_t buf[static CONFIG_USBD_DFU_TRANSFER_SIZE]) 135 * { 136 * return 0; 137 * } 138 * 139 * static bool next(void *const priv, 140 * const enum usb_dfu_state state, const enum usb_dfu_state next) 141 * { 142 * return true; 143 * } 144 * @endcode 145 * 146 * @param id Identifier by which the linker sorts registered images 147 * @param iname Image name as used in interface descriptor 148 * @param iread Image read callback 149 * @param iwrite Image write callback 150 * @param inext Notify/confirm next state 151 */ 152 #define USBD_DFU_DEFINE_IMG(id, iname, ipriv, iread, iwrite, inext) \ 153 static __noinit struct usb_if_descriptor usbd_dfu_iface_##id; \ 154 \ 155 USBD_DESC_STRING_DEFINE(usbd_dfu_str_##id, iname, USBD_DUT_STRING_INTERFACE); \ 156 \ 157 static const STRUCT_SECTION_ITERABLE(usbd_dfu_image, usbd_dfu_image_##id) = { \ 158 .name = iname, \ 159 .if_desc = &usbd_dfu_iface_##id, \ 160 .priv = ipriv, \ 161 .sd_nd = &usbd_dfu_str_##id, \ 162 .read_cb = iread, \ 163 .write_cb = iwrite, \ 164 .next_cb = inext, \ 165 } 166 167 /** 168 * @} 169 */ 170 #endif /* ZEPHYR_INCLUDE_USB_CLASS_USBD_DFU_H */ 171