1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "usbd_msg.h"
8 
9 #include <zephyr/init.h>
10 #include <zephyr/usb/usbd.h>
11 #include <zephyr/usb/class/usbd_dfu.h>
12 
13 #include <zephyr/logging/log.h>
14 LOG_MODULE_REGISTER(usbd_dfu, CONFIG_USBD_DFU_LOG_LEVEL);
15 
16 /*
17  * It is very unlikely that anyone would need more than one instance of the DFU
18  * class. Therefore, we make an exception here and do not support multiple
19  * instances, which allows us to have a much simpler implementation.
20  *
21  * This implementation provides two class instances, one with a single
22  * interface for the run-time mode, and the other with a number of user-defined
23  * interfaces for the DFU mode. The DFU mode instance can have up to 256
24  * (0...255) image (memory) segments, limited by the
25  * CONFIG_USBD_DFU_NUMOF_IMAGES and maximum value of bAlternateSetting.
26  *
27  * The implementation implicitly sets the bitWillDetach flag and expects the
28  * user to disable the device with run-time mode and enable a device with DFU
29  * mode.
30  */
31 
32 #if defined(CONFIG_USBD_DFU_ENABLE_UPLOAD)
33 #define ATTR_CAN_UPLOAD USB_DFU_ATTR_CAN_UPLOAD
34 #else
35 #define ATTR_CAN_UPLOAD 0
36 #endif
37 
38 #if defined(CONFIG_USBD_DFU_MANIFESTATION_TOLERANT)
39 #define ATTR_MANIFESTATION_TOLERANT USB_DFU_ATTR_MANIFESTATION_TOLERANT
40 #else
41 #define ATTR_MANIFESTATION_TOLERANT 0
42 #endif
43 
44 /* DFU Functional Descriptor used for Run-Time und DFU mode */
45 static const struct usb_dfu_descriptor dfu_desc = {
46 	.bLength = sizeof(struct usb_dfu_descriptor),
47 	.bDescriptorType = USB_DESC_DFU_FUNCTIONAL,
48 	.bmAttributes = USB_DFU_ATTR_CAN_DNLOAD |
49 			ATTR_CAN_UPLOAD | ATTR_MANIFESTATION_TOLERANT |
50 			USB_DFU_ATTR_WILL_DETACH,
51 	.wDetachTimeOut = 0,
52 	.wTransferSize = sys_cpu_to_le16(CONFIG_USBD_DFU_TRANSFER_SIZE),
53 	.bcdDFUVersion = sys_cpu_to_le16(USB_DFU_VERSION),
54 };
55 
56 /* Common class data for both run-time and DFU instances. */
57 struct usbd_dfu_data {
58 	struct usb_desc_header **const runtime_mode_descs;
59 	struct usb_desc_header **const dfu_mode_descs;
60 	enum usb_dfu_state state;
61 	enum usb_dfu_state next;
62 	enum usb_dfu_status status;
63 	struct k_work_delayable dwork;
64 	struct usbd_context *ctx;
65 	bool dfu_mode;
66 	struct usbd_dfu_image *image;
67 	uint8_t alternate;
68 };
69 
70 /* Run-Time mode interface descriptor */
71 static __noinit struct usb_if_descriptor runtime_if0_desc;
72 
73 /* Run-Time mode descriptors. No endpoints, identical for high and full speed. */
74 static struct usb_desc_header *runtime_mode_descs[] = {
75 	(struct usb_desc_header *) &runtime_if0_desc,
76 	(struct usb_desc_header *) &dfu_desc,
77 	NULL,
78 };
79 
80 /*
81  * DFU mode descriptors with two reserved indices for functional descriptor and
82  * at least one for NULL. No endpoints, identical for high and full speed.
83  */
84 static struct usb_desc_header *dfu_mode_descs[CONFIG_USBD_DFU_NUMOF_IMAGES + 2];
85 
86 static struct usbd_dfu_data dfu_data = {
87 	.runtime_mode_descs = runtime_mode_descs,
88 	.dfu_mode_descs = dfu_mode_descs,
89 };
90 
91 static const char *const dfu_state_list[] = {
92 	"APP_IDLE",
93 	"APP_DETACH",
94 	"DFU_IDLE",
95 	"DNLOAD_SYNC",
96 	"DNBUSY",
97 	"DNLOAD_IDLE",
98 	"MANIFEST_SYNC",
99 	"MANIFEST",
100 	"MANIFEST_WAIT_RST",
101 	"UPLOAD_IDLE",
102 	"ERROR",
103 };
104 
105 static const char *const dfu_req_list[] = {
106 	"DETACH",
107 	"DNLOAD",
108 	"UPLOAD",
109 	"GETSTATUS",
110 	"CLRSTATUS",
111 	"GETSTATE",
112 	"ABORT",
113 };
114 
115 BUILD_ASSERT(ARRAY_SIZE(dfu_state_list) == DFU_STATE_MAX,
116 	     "Number of entries in dfu_state_list is not equal to DFU_STATE_MAX");
117 
118 BUILD_ASSERT(ARRAY_SIZE(dfu_req_list) == USB_DFU_REQ_ABORT + 1,
119 	     "Number of entries in dfu_req_list is not equal to USB_DFU_REQ_ABORT + 1");
120 
dfu_state_string(const enum usb_dfu_state state)121 static const char *dfu_state_string(const enum usb_dfu_state state)
122 {
123 	if (state >= 0 && state < DFU_STATE_MAX) {
124 		return dfu_state_list[state];
125 	}
126 
127 	return "?";
128 }
129 
dfu_req_string(const enum usb_dfu_state state)130 static const char *dfu_req_string(const enum usb_dfu_state state)
131 {
132 	if (state >= 0 && state <= USB_DFU_REQ_ABORT) {
133 		return dfu_req_list[state];
134 	}
135 
136 	return "?";
137 }
138 
runtime_detach_work(struct k_work * work)139 static void runtime_detach_work(struct k_work *work)
140 {
141 	struct k_work_delayable *dwork = k_work_delayable_from_work(work);
142 	struct usbd_dfu_data *data = CONTAINER_OF(dwork, struct usbd_dfu_data, dwork);
143 
144 	usbd_msg_pub_simple(data->ctx, USBD_MSG_DFU_APP_DETACH, 0);
145 }
146 
init_if_desc(struct usb_if_descriptor * const desc,const uint8_t alternate,const uint8_t protocol)147 static void init_if_desc(struct usb_if_descriptor *const desc,
148 			 const uint8_t alternate, const uint8_t protocol)
149 {
150 	desc->bLength = sizeof(struct usb_if_descriptor);
151 	desc->bDescriptorType = USB_DESC_INTERFACE;
152 	desc->bInterfaceNumber = 0;
153 	desc->bAlternateSetting = alternate;
154 	desc->bNumEndpoints = 0;
155 	desc->bInterfaceClass = USB_BCC_APPLICATION;
156 	desc->bInterfaceSubClass = USB_DFU_SUBCLASS;
157 	desc->bInterfaceProtocol = protocol;
158 	desc->iInterface = 0;
159 }
160 
usbd_dfu_preinit(void)161 static int usbd_dfu_preinit(void)
162 {
163 	struct usb_if_descriptor *if_desc;
164 	int n = 0;
165 
166 	init_if_desc(&runtime_if0_desc, 0, USB_DFU_PROTOCOL_RUNTIME);
167 
168 	STRUCT_SECTION_FOREACH(usbd_dfu_image, image) {
169 		if (n >= CONFIG_USBD_DFU_NUMOF_IMAGES) {
170 			LOG_ERR("Cannot register USB DFU image %s", image->name);
171 			return -ENOMEM;
172 		}
173 
174 		if_desc = image->if_desc;
175 		init_if_desc(if_desc, n, USB_DFU_PROTOCOL_DFU);
176 		dfu_mode_descs[n] = (struct usb_desc_header *)if_desc;
177 		n++;
178 	}
179 
180 	dfu_mode_descs[n] = (struct usb_desc_header *)&dfu_desc;
181 
182 	k_work_init_delayable(&dfu_data.dwork, runtime_detach_work);
183 
184 	return 0;
185 }
186 
187 /*
188  * Perhaps it makes sense to implement an on_registration class interface
189  * callback and not use SYS_INIT().
190  */
191 SYS_INIT(usbd_dfu_preinit, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);
192 
193 /*
194  * This function is used for two purposes, to inform the image backend about
195  * the next step and in some cases to get feedback if the next step is possible
196  * from the image perspective.
197  */
usbd_dfu_image_next(struct usbd_class_data * const c_data,const enum usb_dfu_state next)198 static inline bool usbd_dfu_image_next(struct usbd_class_data *const c_data,
199 				       const enum usb_dfu_state next)
200 {
201 	struct usbd_dfu_data *data = usbd_class_get_private(c_data);
202 	struct usbd_dfu_image *const image = data->image;
203 
204 	if (image->next_cb != NULL) {
205 		return image->next_cb(image->priv, data->state, next);
206 	}
207 
208 	return true;
209 }
210 
dfu_error(struct usbd_class_data * const c_data,const enum usb_dfu_state next,const enum usb_dfu_status status)211 static ALWAYS_INLINE void dfu_error(struct usbd_class_data *const c_data,
212 				    const enum usb_dfu_state next,
213 				    const enum usb_dfu_status status)
214 {
215 	struct usbd_dfu_data *data = usbd_class_get_private(c_data);
216 
217 	data->next = next;
218 	data->status = status;
219 }
220 
221 /*
222  * Because some states (e.g. APP_IDLE, APP_DETACH) require a stall handshake to
223  * be sent, but the state does not change to DFU_ERROR, there are some "return
224  * -ENOTSUP" without state change to indicate a protocol error.
225  */
226 
app_idle_next(struct usbd_class_data * const c_data,const struct usb_setup_packet * const setup)227 static int app_idle_next(struct usbd_class_data *const c_data,
228 			 const struct usb_setup_packet *const setup)
229 {
230 	struct usbd_dfu_data *data = usbd_class_get_private(c_data);
231 
232 	switch (setup->bRequest) {
233 	case USB_DFU_REQ_DETACH:
234 		data->next = APP_DETACH;
235 		return 0;
236 	case USB_DFU_REQ_GETSTATUS:
237 		__fallthrough;
238 	case USB_DFU_REQ_GETSTATE:
239 		return 0;
240 	default:
241 		return -ENOTSUP;
242 	}
243 }
244 
app_detach_next(struct usbd_class_data * const c_data,const struct usb_setup_packet * const setup)245 static int app_detach_next(struct usbd_class_data *const c_data,
246 			   const struct usb_setup_packet *const setup)
247 {
248 	switch (setup->bRequest) {
249 	case USB_DFU_REQ_GETSTATUS:
250 		__fallthrough;
251 	case USB_DFU_REQ_GETSTATE:
252 		return 0;
253 	default:
254 		return -ENOTSUP;
255 	}
256 }
257 
dfu_idle_next(struct usbd_class_data * const c_data,const struct usb_setup_packet * const setup)258 static int dfu_idle_next(struct usbd_class_data *const c_data,
259 			 const struct usb_setup_packet *const setup)
260 {
261 	struct usbd_dfu_data *data = usbd_class_get_private(c_data);
262 
263 	switch (setup->bRequest) {
264 	case USB_DFU_REQ_DNLOAD:
265 		if (!(dfu_desc.bmAttributes & USB_DFU_ATTR_CAN_DNLOAD)) {
266 			dfu_error(c_data, DFU_ERROR, ERR_STALLEDPKT);
267 			return -ENOTSUP;
268 		}
269 
270 		if (data->image == NULL || data->image->write_cb == NULL) {
271 			dfu_error(c_data, DFU_ERROR, ERR_VENDOR);
272 			return -ENOTSUP;
273 		}
274 
275 		if (setup->wLength == 0) {
276 			dfu_error(c_data, DFU_ERROR, ERR_STALLEDPKT);
277 			return -ENOTSUP;
278 		}
279 
280 		data->next = DFU_DNLOAD_SYNC;
281 		return 0;
282 	case USB_DFU_REQ_UPLOAD:
283 		if (!(dfu_desc.bmAttributes & USB_DFU_ATTR_CAN_UPLOAD)) {
284 			dfu_error(c_data, DFU_ERROR, ERR_STALLEDPKT);
285 			return -ENOTSUP;
286 		}
287 
288 		if (data->image == NULL || data->image->read_cb == NULL) {
289 			dfu_error(c_data, DFU_ERROR, ERR_VENDOR);
290 			return -ENOTSUP;
291 		}
292 
293 		if (setup->wLength > sys_le16_to_cpu(dfu_desc.wTransferSize)) {
294 			dfu_error(c_data, DFU_ERROR, ERR_STALLEDPKT);
295 			return -ENOTSUP;
296 		}
297 
298 		data->next = DFU_UPLOAD_IDLE;
299 		return 0;
300 	case USB_DFU_REQ_ABORT:
301 		__fallthrough;
302 	case USB_DFU_REQ_GETSTATUS:
303 		__fallthrough;
304 	case USB_DFU_REQ_GETSTATE:
305 		return 0;
306 	default:
307 		dfu_error(c_data, DFU_ERROR, ERR_STALLEDPKT);
308 		return -ENOTSUP;
309 	}
310 }
311 
dfu_dnload_sync_next(struct usbd_class_data * const c_data,const struct usb_setup_packet * const setup)312 static int dfu_dnload_sync_next(struct usbd_class_data *const c_data,
313 				const struct usb_setup_packet *const setup)
314 {
315 	struct usbd_dfu_data *data = usbd_class_get_private(c_data);
316 
317 	switch (setup->bRequest) {
318 	case USB_DFU_REQ_GETSTATUS:
319 		/* Chack if image backend can change DFU_DNLOAD_SYNC -> DFU_DNLOAD_IDLE */
320 		if (usbd_dfu_image_next(c_data, DFU_DNLOAD_IDLE)) {
321 			data->next = DFU_DNLOAD_IDLE;
322 		} else {
323 			data->next = DFU_DNBUSY;
324 		}
325 
326 		return 0;
327 	case USB_DFU_REQ_GETSTATE:
328 		return 0;
329 	default:
330 		dfu_error(c_data, DFU_ERROR, ERR_STALLEDPKT);
331 		return -ENOTSUP;
332 	}
333 }
334 
dfu_dnbusy_next(struct usbd_class_data * const c_data,const struct usb_setup_packet * const setup)335 static int dfu_dnbusy_next(struct usbd_class_data *const c_data,
336 			   const struct usb_setup_packet *const setup)
337 {
338 	struct usbd_dfu_data *data = usbd_class_get_private(c_data);
339 
340 	/* Do not enforce bmPollTimeout (allow GET_STATUS immediately) */
341 	data->state = DFU_DNLOAD_SYNC;
342 
343 	return dfu_dnload_sync_next(c_data, setup);
344 }
345 
dfu_dnload_idle_next(struct usbd_class_data * const c_data,const struct usb_setup_packet * const setup)346 static int dfu_dnload_idle_next(struct usbd_class_data *const c_data,
347 				const struct usb_setup_packet *const setup)
348 {
349 	struct usbd_dfu_data *data = usbd_class_get_private(c_data);
350 
351 	switch (setup->bRequest) {
352 	case USB_DFU_REQ_DNLOAD:
353 		if (setup->wLength == 0) {
354 			data->next = DFU_MANIFEST_SYNC;
355 		} else {
356 			data->next = DFU_DNLOAD_SYNC;
357 		}
358 
359 		return 0;
360 	case USB_DFU_REQ_ABORT:
361 		data->next = DFU_IDLE;
362 		/* Notify image backend about DFU_DNLOAD_IDLE -> DFU_IDLE change */
363 		usbd_dfu_image_next(c_data, data->next);
364 	case USB_DFU_REQ_GETSTATUS:
365 		__fallthrough;
366 	case USB_DFU_REQ_GETSTATE:
367 		return 0;
368 	default:
369 		dfu_error(c_data, DFU_ERROR, ERR_STALLEDPKT);
370 		return -ENOTSUP;
371 	}
372 }
373 
dfu_manifest_sync_next(struct usbd_class_data * const c_data,const struct usb_setup_packet * const setup)374 static int dfu_manifest_sync_next(struct usbd_class_data *const c_data,
375 				  const struct usb_setup_packet *const setup)
376 {
377 	struct usbd_dfu_data *data = usbd_class_get_private(c_data);
378 
379 	switch (setup->bRequest) {
380 	case USB_DFU_REQ_GETSTATUS:
381 		if (usbd_dfu_image_next(c_data, DFU_IDLE)) {
382 			data->next = DFU_IDLE;
383 			usbd_msg_pub_simple(data->ctx, USBD_MSG_DFU_DOWNLOAD_COMPLETED, 0);
384 		} else {
385 			data->next = DFU_MANIFEST;
386 		}
387 	case USB_DFU_REQ_GETSTATE:
388 		return 0;
389 	default:
390 		dfu_error(c_data, DFU_ERROR, ERR_STALLEDPKT);
391 		return -ENOTSUP;
392 	}
393 
394 	return 0;
395 }
396 
dfu_manifest_next(struct usbd_class_data * const c_data,const struct usb_setup_packet * const setup)397 static int dfu_manifest_next(struct usbd_class_data *const c_data,
398 			     const struct usb_setup_packet *const setup)
399 {
400 	struct usbd_dfu_data *data = usbd_class_get_private(c_data);
401 
402 	/* Ignore poll timeout, proceed directly to next state. */
403 
404 	if (dfu_desc.bmAttributes & USB_DFU_ATTR_MANIFESTATION_TOLERANT) {
405 		data->state = DFU_MANIFEST_SYNC;
406 		return dfu_manifest_sync_next(c_data, setup);
407 	}
408 
409 	data->next = DFU_MANIFEST_WAIT_RST;
410 	usbd_dfu_image_next(c_data, DFU_MANIFEST_WAIT_RST);
411 
412 	return 0;
413 }
414 
dfu_manifest_wait_rst_next(struct usbd_class_data * const c_data,const struct usb_setup_packet * const setup)415 static int dfu_manifest_wait_rst_next(struct usbd_class_data *const c_data,
416 				      const struct usb_setup_packet *const setup)
417 {
418 	/* Ignore all requests, wait for system or bus reset */
419 
420 	return 0;
421 }
422 
dfu_upload_idle_next(struct usbd_class_data * const c_data,const struct usb_setup_packet * const setup)423 static int dfu_upload_idle_next(struct usbd_class_data *const c_data,
424 				const struct usb_setup_packet *const setup)
425 {
426 	struct usbd_dfu_data *data = usbd_class_get_private(c_data);
427 
428 	switch (setup->bRequest) {
429 	case USB_DFU_REQ_UPLOAD:
430 		if (setup->wLength > sys_le16_to_cpu(dfu_desc.wTransferSize)) {
431 			dfu_error(c_data, DFU_ERROR, ERR_STALLEDPKT);
432 			return -ENOTSUP;
433 		}
434 
435 		data->next = DFU_UPLOAD_IDLE;
436 		return 0;
437 	case USB_DFU_REQ_ABORT:
438 		data->next = DFU_IDLE;
439 		/* Notify image backend about DFU_UPLOAD_IDLE -> DFU_IDLE change */
440 		usbd_dfu_image_next(c_data, data->next);
441 	case USB_DFU_REQ_GETSTATUS:
442 		__fallthrough;
443 	case USB_DFU_REQ_GETSTATE:
444 		return 0;
445 	default:
446 		dfu_error(c_data, DFU_ERROR, ERR_STALLEDPKT);
447 		return -ENOTSUP;
448 	}
449 }
450 
dfu_error_next(struct usbd_class_data * const c_data,const struct usb_setup_packet * const setup)451 static int dfu_error_next(struct usbd_class_data *const c_data,
452 			  const struct usb_setup_packet *const setup)
453 {
454 	switch (setup->bRequest) {
455 	case USB_DFU_REQ_GETSTATUS:
456 		__fallthrough;
457 	case USB_DFU_REQ_GETSTATE:
458 		return 0;
459 	case USB_DFU_REQ_CLRSTATUS:
460 		dfu_error(c_data, DFU_IDLE, ERR_OK);
461 		return 0;
462 	default:
463 		return -ENOTSUP;
464 	}
465 }
466 
467 static int (*next_entries[])(struct usbd_class_data *const c_data,
468 			     const struct usb_setup_packet *const setup) = {
469 	app_idle_next,
470 	app_detach_next,
471 	dfu_idle_next,
472 	dfu_dnload_sync_next,
473 	dfu_dnbusy_next,
474 	dfu_dnload_idle_next,
475 	dfu_manifest_sync_next,
476 	dfu_manifest_next,
477 	dfu_manifest_wait_rst_next,
478 	dfu_upload_idle_next,
479 	dfu_error_next,
480 };
481 
482 BUILD_ASSERT(ARRAY_SIZE(next_entries) == DFU_STATE_MAX,
483 	     "Number of entries in next_entries is not equal to DFU_STATE_MAX");
484 
485 /*
486  * Here we only set the next state based on the current state, image state and
487  * the new request. We do not copy/move any data and we do not update DFU state.
488  *
489  * The state change and additional actions are performed in four places, in the
490  * host/device requests in runtime mode and in the host/device request in DFU
491  * mode.
492  */
dfu_set_next_state(struct usbd_class_data * const c_data,const struct usb_setup_packet * const setup)493 static int dfu_set_next_state(struct usbd_class_data *const c_data,
494 			      const struct usb_setup_packet *const setup)
495 {
496 	struct usbd_dfu_data *data = usbd_class_get_private(c_data);
497 	int err;
498 
499 	if (setup->RequestType.type != USB_REQTYPE_TYPE_CLASS) {
500 		return -ENOTSUP;
501 	}
502 
503 	if (setup->bRequest >= ARRAY_SIZE(next_entries)) {
504 		return -ENOTSUP;
505 	}
506 
507 	data->next = data->state;
508 	err = next_entries[data->state](c_data, setup);
509 
510 	LOG_DBG("bRequest %s, state %s, next %s, error %d",
511 		dfu_req_string(setup->bRequest), dfu_state_string(data->state),
512 		dfu_state_string(data->next), err);
513 
514 	return err;
515 }
516 
517 /* Run-Time mode instance implementation, for instance "dfu_runtime" */
518 
handle_get_status(struct usbd_class_data * const c_data,const struct usb_setup_packet * const setup,struct net_buf * const buf)519 static int handle_get_status(struct usbd_class_data *const c_data,
520 			     const struct usb_setup_packet *const setup,
521 			     struct net_buf *const buf)
522 {
523 	struct usbd_dfu_data *data = usbd_class_get_private(c_data);
524 	size_t len = MIN(setup->wLength, net_buf_tailroom(buf));
525 	const size_t getstatus_len = 6;
526 
527 	if (len != getstatus_len) {
528 		errno = -ENOTSUP;
529 		return 0;
530 	}
531 
532 	/*
533 	 * Add GET_STATUS response consisting of
534 	 * bStatus, bwPollTimeout, bStatus, iString (no strings defined)
535 	 */
536 	net_buf_add_u8(buf, data->status);
537 	net_buf_add_le16(buf, CONFIG_USBD_DFU_POLLTIMEOUT);
538 	net_buf_add_u8(buf, 0);
539 	net_buf_add_u8(buf, data->state);
540 	net_buf_add_u8(buf, 0);
541 
542 	return 0;
543 }
544 
handle_get_state(struct usbd_class_data * const c_data,const struct usb_setup_packet * const setup,struct net_buf * const buf)545 static int handle_get_state(struct usbd_class_data *const c_data,
546 			    const struct usb_setup_packet *const setup,
547 			    struct net_buf *const buf)
548 {
549 	struct usbd_dfu_data *data = usbd_class_get_private(c_data);
550 	size_t len = MIN(setup->wLength, net_buf_tailroom(buf));
551 	const size_t getstate_len = 1;
552 
553 	if (len != getstate_len) {
554 		errno = -ENOTSUP;
555 		return 0;
556 	}
557 
558 	net_buf_add_u8(buf, data->state);
559 
560 	return 0;
561 }
562 
runtime_mode_control_to_host(struct usbd_class_data * const c_data,const struct usb_setup_packet * const setup,struct net_buf * const buf)563 static int runtime_mode_control_to_host(struct usbd_class_data *const c_data,
564 					const struct usb_setup_packet *const setup,
565 					struct net_buf *const buf)
566 {
567 	struct usbd_dfu_data *data = usbd_class_get_private(c_data);
568 
569 	errno = dfu_set_next_state(c_data, setup);
570 
571 	if (errno == 0) {
572 		switch (setup->bRequest) {
573 		case USB_DFU_REQ_GETSTATUS:
574 			errno = handle_get_status(c_data, setup, buf);
575 			break;
576 		case USB_DFU_REQ_GETSTATE:
577 			errno = handle_get_state(c_data, setup, buf);
578 			break;
579 		default:
580 			break;
581 		}
582 	}
583 
584 	data->state = data->next;
585 
586 	return 0;
587 }
588 
runtime_mode_control_to_dev(struct usbd_class_data * const c_data,const struct usb_setup_packet * const setup,const struct net_buf * const buf)589 static int runtime_mode_control_to_dev(struct usbd_class_data *const c_data,
590 				       const struct usb_setup_packet *const setup,
591 				       const struct net_buf *const buf)
592 {
593 	struct usbd_dfu_data *data = usbd_class_get_private(c_data);
594 
595 	errno = dfu_set_next_state(c_data, setup);
596 
597 	if (errno == 0) {
598 		if (setup->bRequest == USB_DFU_REQ_DETACH) {
599 			k_work_reschedule(&data->dwork, K_MSEC(100));
600 		}
601 	}
602 
603 	data->state = data->next;
604 
605 	return 0;
606 }
607 
runtime_mode_get_desc(struct usbd_class_data * const c_data,const enum usbd_speed speed)608 static void *runtime_mode_get_desc(struct usbd_class_data *const c_data,
609 				   const enum usbd_speed speed)
610 {
611 	struct usbd_dfu_data *data = usbd_class_get_private(c_data);
612 
613 	return data->runtime_mode_descs;
614 }
615 
runtime_mode_init(struct usbd_class_data * const c_data)616 static int runtime_mode_init(struct usbd_class_data *const c_data)
617 {
618 	struct usbd_dfu_data *data = usbd_class_get_private(c_data);
619 
620 	LOG_DBG("Init class instance %p", c_data);
621 	data->dfu_mode = false;
622 	data->alternate = 0;
623 	data->state = APP_IDLE;
624 	data->next = APP_IDLE;
625 	data->image = NULL;
626 	data->ctx = usbd_class_get_ctx(c_data);
627 
628 	return 0;
629 }
630 
631 struct usbd_class_api runtime_mode_api = {
632 	.control_to_host = runtime_mode_control_to_host,
633 	.control_to_dev = runtime_mode_control_to_dev,
634 	.get_desc = runtime_mode_get_desc,
635 	.init = runtime_mode_init,
636 };
637 
638 USBD_DEFINE_CLASS(dfu_runtime, &runtime_mode_api, &dfu_data, NULL);
639 
640 /* DFU mode instance implementation, for instance "dfu_dfu" */
641 
handle_upload(struct usbd_class_data * const c_data,const struct usb_setup_packet * const setup,struct net_buf * const buf)642 static int handle_upload(struct usbd_class_data *const c_data,
643 			 const struct usb_setup_packet *const setup,
644 			 struct net_buf *const buf)
645 {
646 	struct usbd_dfu_data *data = usbd_class_get_private(c_data);
647 	uint16_t size = MIN(setup->wLength, net_buf_tailroom(buf));
648 	struct usbd_dfu_image *const image = data->image;
649 	int ret;
650 
651 	ret = image->read_cb(image->priv, setup->wValue, size, buf->data);
652 	if (ret >= 0) {
653 		net_buf_add(buf, ret);
654 		if (ret < sys_le16_to_cpu(dfu_desc.wTransferSize)) {
655 			data->state = DFU_IDLE;
656 		}
657 	} else {
658 		errno = -ENOTSUP;
659 		dfu_error(c_data, DFU_ERROR, ERR_UNKNOWN);
660 	}
661 
662 	return 0;
663 }
664 
handle_download(struct usbd_class_data * const c_data,const struct usb_setup_packet * const setup,const struct net_buf * const buf)665 static int handle_download(struct usbd_class_data *const c_data,
666 			   const struct usb_setup_packet *const setup,
667 			   const struct net_buf *const buf)
668 {
669 	struct usbd_dfu_data *data = usbd_class_get_private(c_data);
670 	struct usbd_dfu_image *const image = data->image;
671 	uint16_t size = MIN(setup->wLength, buf->len);
672 	int ret;
673 
674 	ret = image->write_cb(image->priv, setup->wValue, size, buf->data);
675 	if (ret < 0) {
676 		errno = -ENOTSUP;
677 		dfu_error(c_data, DFU_ERROR, ERR_UNKNOWN);
678 	}
679 
680 	return 0;
681 }
682 
dfu_mode_control_to_host(struct usbd_class_data * const c_data,const struct usb_setup_packet * const setup,struct net_buf * const buf)683 static int dfu_mode_control_to_host(struct usbd_class_data *const c_data,
684 				    const struct usb_setup_packet *const setup,
685 				    struct net_buf *const buf)
686 {
687 	struct usbd_dfu_data *data = usbd_class_get_private(c_data);
688 
689 	errno = dfu_set_next_state(c_data, setup);
690 
691 	if (errno == 0) {
692 		switch (setup->bRequest) {
693 		case USB_DFU_REQ_GETSTATUS:
694 			errno = handle_get_status(c_data, setup, buf);
695 			break;
696 		case USB_DFU_REQ_GETSTATE:
697 			errno = handle_get_state(c_data, setup, buf);
698 			break;
699 		case USB_DFU_REQ_UPLOAD:
700 			errno = handle_upload(c_data, setup, buf);
701 			break;
702 		default:
703 			break;
704 		}
705 	}
706 
707 	data->state = data->next;
708 
709 	return 0;
710 }
711 
dfu_mode_control_to_dev(struct usbd_class_data * const c_data,const struct usb_setup_packet * const setup,const struct net_buf * const buf)712 static int dfu_mode_control_to_dev(struct usbd_class_data *const c_data,
713 				   const struct usb_setup_packet *const setup,
714 				   const struct net_buf *const buf)
715 {
716 	struct usbd_dfu_data *data = usbd_class_get_private(c_data);
717 
718 	errno = dfu_set_next_state(c_data, setup);
719 
720 	if (errno == 0) {
721 		if (setup->bRequest == USB_DFU_REQ_DNLOAD) {
722 			handle_download(c_data, setup, buf);
723 		}
724 	}
725 
726 	data->state = data->next;
727 
728 	return 0;
729 }
730 
dfu_mode_update(struct usbd_class_data * const c_data,const uint8_t iface,const uint8_t alternate)731 static void dfu_mode_update(struct usbd_class_data *const c_data,
732 			    const uint8_t iface, const uint8_t alternate)
733 {
734 	struct usbd_dfu_data *data = usbd_class_get_private(c_data);
735 
736 	LOG_DBG("Instance %p, interface %u alternate %u changed",
737 		c_data, iface, alternate);
738 
739 	data->alternate = alternate;
740 	data->image = NULL;
741 
742 	STRUCT_SECTION_FOREACH(usbd_dfu_image, image) {
743 		if (image->if_desc->bAlternateSetting == alternate) {
744 			data->image = image;
745 			break;
746 		}
747 	}
748 }
749 
dfu_mode_get_desc(struct usbd_class_data * const c_data,const enum usbd_speed speed)750 static void *dfu_mode_get_desc(struct usbd_class_data *const c_data,
751 			       const enum usbd_speed speed)
752 {
753 	struct usbd_dfu_data *data = usbd_class_get_private(c_data);
754 
755 	return data->dfu_mode_descs;
756 }
757 
dfu_mode_init(struct usbd_class_data * const c_data)758 static int dfu_mode_init(struct usbd_class_data *const c_data)
759 {
760 	struct usbd_dfu_data *data = usbd_class_get_private(c_data);
761 	struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data);
762 
763 	LOG_DBG("Init class instance %p", c_data);
764 	data->dfu_mode = true;
765 	data->alternate = 0;
766 	data->image = NULL;
767 	data->state = DFU_IDLE;
768 	data->next = DFU_IDLE;
769 	data->ctx = usbd_class_get_ctx(c_data);
770 
771 	STRUCT_SECTION_FOREACH(usbd_dfu_image, image) {
772 		if (image->if_desc->bAlternateSetting == data->alternate) {
773 			data->image = image;
774 		}
775 
776 		if (usbd_add_descriptor(uds_ctx, image->sd_nd)) {
777 			LOG_ERR("Failed to add string descriptor");
778 		} else {
779 			image->if_desc->iInterface = usbd_str_desc_get_idx(image->sd_nd);
780 		}
781 	}
782 
783 	return data->image == NULL ? -EINVAL : 0;
784 }
785 
786 struct usbd_class_api dfu_api = {
787 	.control_to_host = dfu_mode_control_to_host,
788 	.control_to_dev = dfu_mode_control_to_dev,
789 	.update = dfu_mode_update,
790 	.get_desc = dfu_mode_get_desc,
791 	.init = dfu_mode_init,
792 };
793 
794 USBD_DEFINE_CLASS(dfu_dfu, &dfu_api, &dfu_data, NULL);
795