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