1 /*******************************************************************************
2 *
3 * Copyright(c) 2015,2016 Intel Corporation.
4 * Copyright(c) 2017 PHYTEC Messtechnik GmbH
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Intel Corporation nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 ******************************************************************************/
33
34 /**
35 * @brief DFU class driver
36 *
37 * USB DFU device class driver
38 *
39 */
40
41 #include <zephyr/init.h>
42 #include <zephyr/kernel.h>
43 #include <stdio.h>
44 #include <errno.h>
45 #include <zephyr/drivers/flash.h>
46 #include <zephyr/storage/flash_map.h>
47 #include <zephyr/dfu/mcuboot.h>
48 #include <zephyr/dfu/flash_img.h>
49 #include <zephyr/sys/byteorder.h>
50 #include <zephyr/sys/reboot.h>
51 #include <zephyr/usb/usb_device.h>
52 #include <zephyr/usb/class/usb_dfu.h>
53 #include <usb_descriptor.h>
54 #include <usb_work_q.h>
55
56 #include <zephyr/logging/log.h>
57 LOG_MODULE_REGISTER(usb_dfu, CONFIG_USB_DEVICE_LOG_LEVEL);
58
59 #define SLOT0_PARTITION slot0_partition
60 #define SLOT1_PARTITION slot1_partition
61
62 #define FIRMWARE_IMAGE_0_LABEL "image_0"
63 #define FIRMWARE_IMAGE_1_LABEL "image_1"
64
65 #define USB_DFU_MAX_XFER_SIZE CONFIG_USB_REQUEST_BUFFER_SIZE
66
67 #define INTERMITTENT_CHECK_DELAY 50
68
69 #if defined(CONFIG_USB_DFU_REBOOT)
70 #define DFU_DESC_ATTRIBUTES_MANIF_TOL 0
71 #else
72 #define DFU_DESC_ATTRIBUTES_MANIF_TOL DFU_ATTR_MANIFESTATION_TOLERANT
73 #endif
74
75 #if defined(CONFIG_USB_DFU_ENABLE_UPLOAD)
76 #define DFU_DESC_ATTRIBUTES_CAN_UPLOAD DFU_ATTR_CAN_UPLOAD
77 #else
78 #define DFU_DESC_ATTRIBUTES_CAN_UPLOAD 0
79 #endif
80
81 #if defined(CONFIG_USB_DFU_WILL_DETACH)
82 #define DFU_DESC_ATTRIBUTES_WILL_DETACH DFU_ATTR_WILL_DETACH
83 #else
84 #define DFU_DESC_ATTRIBUTES_WILL_DETACH 0
85 #endif
86
87 #define DFU_DESC_ATTRIBUTES (DFU_ATTR_CAN_DNLOAD | \
88 DFU_DESC_ATTRIBUTES_CAN_UPLOAD |\
89 DFU_DESC_ATTRIBUTES_MANIF_TOL |\
90 DFU_DESC_ATTRIBUTES_WILL_DETACH)
91
92 static struct k_poll_event dfu_event;
93 static struct k_poll_signal dfu_signal;
94 static struct k_work_delayable dfu_timer_work;
95
96 static struct k_work dfu_work;
97
98 struct dfu_worker_data_t {
99 uint8_t buf[USB_DFU_MAX_XFER_SIZE];
100 enum dfu_state worker_state;
101 uint16_t worker_len;
102 };
103
104 static struct dfu_worker_data_t dfu_data_worker;
105
106 struct usb_dfu_config {
107 struct usb_if_descriptor if0;
108 struct dfu_runtime_descriptor dfu_descr;
109 } __packed;
110
111 USBD_CLASS_DESCR_DEFINE(primary, 0) struct usb_dfu_config dfu_cfg = {
112 /* Interface descriptor */
113 .if0 = {
114 .bLength = sizeof(struct usb_if_descriptor),
115 .bDescriptorType = USB_DESC_INTERFACE,
116 .bInterfaceNumber = 0,
117 .bAlternateSetting = 0,
118 .bNumEndpoints = 0,
119 .bInterfaceClass = USB_BCC_APPLICATION,
120 .bInterfaceSubClass = DFU_SUBCLASS,
121 .bInterfaceProtocol = DFU_RT_PROTOCOL,
122 .iInterface = 0,
123 },
124 .dfu_descr = {
125 .bLength = sizeof(struct dfu_runtime_descriptor),
126 .bDescriptorType = DFU_FUNC_DESC,
127 .bmAttributes = DFU_DESC_ATTRIBUTES,
128 .wDetachTimeOut =
129 sys_cpu_to_le16(CONFIG_USB_DFU_DETACH_TIMEOUT),
130 .wTransferSize =
131 sys_cpu_to_le16(USB_DFU_MAX_XFER_SIZE),
132 .bcdDFUVersion =
133 sys_cpu_to_le16(DFU_VERSION),
134 },
135 };
136
137 /* dfu mode device descriptor */
138
139 struct dev_dfu_mode_descriptor {
140 struct usb_device_descriptor device_descriptor;
141 struct usb_cfg_descriptor cfg_descr;
142 struct usb_sec_dfu_config {
143 struct usb_if_descriptor if0;
144 #if FIXED_PARTITION_EXISTS(SLOT1_PARTITION)
145 struct usb_if_descriptor if1;
146 #endif
147 struct dfu_runtime_descriptor dfu_descr;
148 } __packed sec_dfu_cfg;
149 } __packed;
150
151
152 USBD_DEVICE_DESCR_DEFINE(secondary)
153 struct dev_dfu_mode_descriptor dfu_mode_desc = {
154 /* Device descriptor */
155 .device_descriptor = {
156 .bLength = sizeof(struct usb_device_descriptor),
157 .bDescriptorType = USB_DESC_DEVICE,
158 .bcdUSB = sys_cpu_to_le16(USB_SRN_2_0),
159 .bDeviceClass = 0,
160 .bDeviceSubClass = 0,
161 .bDeviceProtocol = 0,
162 .bMaxPacketSize0 = USB_MAX_CTRL_MPS,
163 .idVendor = sys_cpu_to_le16((uint16_t)CONFIG_USB_DEVICE_VID),
164 .idProduct =
165 sys_cpu_to_le16((uint16_t)CONFIG_USB_DEVICE_DFU_PID),
166 .bcdDevice = sys_cpu_to_le16(USB_BCD_DRN),
167 .iManufacturer = 1,
168 .iProduct = 2,
169 .iSerialNumber = 3,
170 .bNumConfigurations = 1,
171 },
172 /* Configuration descriptor */
173 .cfg_descr = {
174 .bLength = sizeof(struct usb_cfg_descriptor),
175 .bDescriptorType = USB_DESC_CONFIGURATION,
176 .wTotalLength = 0,
177 .bNumInterfaces = 1,
178 .bConfigurationValue = 1,
179 .iConfiguration = 0,
180 .bmAttributes = USB_SCD_RESERVED |
181 COND_CODE_1(CONFIG_USB_SELF_POWERED,
182 (USB_SCD_SELF_POWERED), (0)) |
183 COND_CODE_1(CONFIG_USB_DEVICE_REMOTE_WAKEUP,
184 (USB_SCD_REMOTE_WAKEUP), (0)),
185 .bMaxPower = CONFIG_USB_MAX_POWER,
186 },
187 .sec_dfu_cfg = {
188 /* Interface descriptor */
189 .if0 = {
190 .bLength = sizeof(struct usb_if_descriptor),
191 .bDescriptorType = USB_DESC_INTERFACE,
192 .bInterfaceNumber = 0,
193 .bAlternateSetting = 0,
194 .bNumEndpoints = 0,
195 .bInterfaceClass = USB_BCC_APPLICATION,
196 .bInterfaceSubClass = DFU_SUBCLASS,
197 .bInterfaceProtocol = DFU_MODE_PROTOCOL,
198 .iInterface = 4,
199 },
200 #if FIXED_PARTITION_EXISTS(SLOT1_PARTITION)
201 .if1 = {
202 .bLength = sizeof(struct usb_if_descriptor),
203 .bDescriptorType = USB_DESC_INTERFACE,
204 .bInterfaceNumber = 0,
205 .bAlternateSetting = 1,
206 .bNumEndpoints = 0,
207 .bInterfaceClass = USB_BCC_APPLICATION,
208 .bInterfaceSubClass = DFU_SUBCLASS,
209 .bInterfaceProtocol = DFU_MODE_PROTOCOL,
210 .iInterface = 5,
211 },
212 #endif
213 .dfu_descr = {
214 .bLength = sizeof(struct dfu_runtime_descriptor),
215 .bDescriptorType = DFU_FUNC_DESC,
216 .bmAttributes = DFU_DESC_ATTRIBUTES,
217 .wDetachTimeOut =
218 sys_cpu_to_le16(CONFIG_USB_DFU_DETACH_TIMEOUT),
219 .wTransferSize =
220 sys_cpu_to_le16(USB_DFU_MAX_XFER_SIZE),
221 .bcdDFUVersion =
222 sys_cpu_to_le16(DFU_VERSION),
223 },
224 },
225 };
226
227 struct usb_string_desription {
228 struct usb_string_descriptor lang_descr;
229 struct usb_mfr_descriptor {
230 uint8_t bLength;
231 uint8_t bDescriptorType;
232 uint8_t bString[USB_BSTRING_LENGTH(
233 CONFIG_USB_DEVICE_MANUFACTURER)];
234 } __packed utf16le_mfr;
235
236 struct usb_product_descriptor {
237 uint8_t bLength;
238 uint8_t bDescriptorType;
239 uint8_t bString[USB_BSTRING_LENGTH(CONFIG_USB_DEVICE_PRODUCT)];
240 } __packed utf16le_product;
241
242 struct usb_sn_descriptor {
243 uint8_t bLength;
244 uint8_t bDescriptorType;
245 uint8_t bString[USB_BSTRING_LENGTH(CONFIG_USB_DEVICE_SN)];
246 } __packed utf16le_sn;
247
248 struct image_0_descriptor {
249 uint8_t bLength;
250 uint8_t bDescriptorType;
251 uint8_t bString[USB_BSTRING_LENGTH(FIRMWARE_IMAGE_0_LABEL)];
252 } __packed utf16le_image0;
253
254 #if FIXED_PARTITION_EXISTS(SLOT1_PARTITION)
255 struct image_1_descriptor {
256 uint8_t bLength;
257 uint8_t bDescriptorType;
258 uint8_t bString[USB_BSTRING_LENGTH(FIRMWARE_IMAGE_1_LABEL)];
259 } __packed utf16le_image1;
260 #endif
261 } __packed;
262
263 USBD_STRING_DESCR_DEFINE(secondary)
264 struct usb_string_desription string_descr = {
265 .lang_descr = {
266 .bLength = sizeof(struct usb_string_descriptor),
267 .bDescriptorType = USB_DESC_STRING,
268 .bString = sys_cpu_to_le16(0x0409),
269 },
270 /* Manufacturer String Descriptor */
271 .utf16le_mfr = {
272 .bLength = USB_STRING_DESCRIPTOR_LENGTH(
273 CONFIG_USB_DEVICE_MANUFACTURER),
274 .bDescriptorType = USB_DESC_STRING,
275 .bString = CONFIG_USB_DEVICE_MANUFACTURER,
276 },
277 /* Product String Descriptor */
278 .utf16le_product = {
279 .bLength = USB_STRING_DESCRIPTOR_LENGTH(
280 CONFIG_USB_DEVICE_PRODUCT),
281 .bDescriptorType = USB_DESC_STRING,
282 .bString = CONFIG_USB_DEVICE_PRODUCT,
283 },
284 /* Serial Number String Descriptor */
285 .utf16le_sn = {
286 .bLength = USB_STRING_DESCRIPTOR_LENGTH(CONFIG_USB_DEVICE_SN),
287 .bDescriptorType = USB_DESC_STRING,
288 .bString = CONFIG_USB_DEVICE_SN,
289 },
290 /* Image 0 String Descriptor */
291 .utf16le_image0 = {
292 .bLength = USB_STRING_DESCRIPTOR_LENGTH(
293 FIRMWARE_IMAGE_0_LABEL),
294 .bDescriptorType = USB_DESC_STRING,
295 .bString = FIRMWARE_IMAGE_0_LABEL,
296 },
297 #if FIXED_PARTITION_EXISTS(SLOT1_PARTITION)
298 /* Image 1 String Descriptor */
299 .utf16le_image1 = {
300 .bLength = USB_STRING_DESCRIPTOR_LENGTH(
301 FIRMWARE_IMAGE_1_LABEL),
302 .bDescriptorType = USB_DESC_STRING,
303 .bString = FIRMWARE_IMAGE_1_LABEL,
304 },
305 #endif
306 };
307
308 /* This element marks the end of the entire descriptor. */
309 USBD_TERM_DESCR_DEFINE(secondary) struct usb_desc_header term_descr = {
310 .bLength = 0,
311 .bDescriptorType = 0,
312 };
313
314 static struct usb_cfg_data dfu_config;
315
316 /* Device data structure */
317 struct dfu_data_t {
318 uint8_t flash_area_id;
319 uint32_t flash_upload_size;
320 /* Number of bytes sent during upload */
321 uint32_t bytes_sent;
322 uint32_t alt_setting; /* DFU alternate setting */
323 struct flash_img_context ctx;
324 enum dfu_state state; /* State of the DFU device */
325 enum dfu_status status; /* Status of the DFU device */
326 uint16_t block_nr; /* DFU block number */
327 uint16_t bwPollTimeout;
328 };
329
330 #if FIXED_PARTITION_EXISTS(SLOT1_PARTITION)
331 #define DOWNLOAD_FLASH_AREA_ID FIXED_PARTITION_ID(SLOT1_PARTITION)
332 #else
333 #define DOWNLOAD_FLASH_AREA_ID FIXED_PARTITION_ID(SLOT0_PARTITION)
334 #endif
335
336
337 static struct dfu_data_t dfu_data = {
338 .state = appIDLE,
339 .status = statusOK,
340 .flash_area_id = DOWNLOAD_FLASH_AREA_ID,
341 .alt_setting = 0,
342 .bwPollTimeout = CONFIG_USB_DFU_DEFAULT_POLLTIMEOUT,
343 };
344
345 /**
346 * @brief Helper function to check if in DFU app state.
347 *
348 * @return true if app state, false otherwise.
349 */
dfu_check_app_state(void)350 static bool dfu_check_app_state(void)
351 {
352 if (dfu_data.state == appIDLE ||
353 dfu_data.state == appDETACH) {
354 dfu_data.state = appIDLE;
355 return true;
356 }
357
358 return false;
359 }
360
361 /**
362 * @brief Helper function to reset DFU internal counters.
363 */
dfu_reset_counters(void)364 static void dfu_reset_counters(void)
365 {
366 dfu_data.bytes_sent = 0U;
367 dfu_data.block_nr = 0U;
368 if (flash_img_init(&dfu_data.ctx)) {
369 LOG_ERR("flash img init error");
370 dfu_data.state = dfuERROR;
371 dfu_data.status = errUNKNOWN;
372 }
373 }
374
dfu_flash_write(uint8_t * data,size_t len)375 static void dfu_flash_write(uint8_t *data, size_t len)
376 {
377 bool flush = false;
378
379 if (!len) {
380 /* Download completed */
381 flush = true;
382 }
383
384 if (flash_img_buffered_write(&dfu_data.ctx, data, len, flush)) {
385 LOG_ERR("flash write error");
386 dfu_data.state = dfuERROR;
387 dfu_data.status = errWRITE;
388 } else if (!len) {
389 const bool should_confirm = IS_ENABLED(CONFIG_USB_DFU_PERMANENT_DOWNLOAD);
390
391 LOG_DBG("flash write done");
392 dfu_data.state = dfuMANIFEST_SYNC;
393 dfu_reset_counters();
394
395 LOG_DBG("Should confirm: %d", should_confirm);
396 if (boot_request_upgrade(should_confirm)) {
397 dfu_data.state = dfuERROR;
398 dfu_data.status = errWRITE;
399 }
400
401 k_poll_signal_raise(&dfu_signal, 0);
402 } else {
403 dfu_data.state = dfuDNLOAD_IDLE;
404 }
405
406 LOG_DBG("bytes written 0x%x", flash_img_bytes_written(&dfu_data.ctx));
407 }
408
dfu_enter_idle(void)409 static void dfu_enter_idle(void)
410 {
411 dfu_data.state = dfuIDLE;
412
413 /* Set the DFU mode descriptors to be used after reset */
414 dfu_config.usb_device_description = (uint8_t *) &dfu_mode_desc;
415 if (usb_set_config(dfu_config.usb_device_description)) {
416 LOG_ERR("usb_set_config failed during DFU idle entry");
417 }
418 }
419
dfu_timer_work_handler(struct k_work * item)420 static void dfu_timer_work_handler(struct k_work *item)
421 {
422 ARG_UNUSED(item);
423
424 if (dfu_data.state == appDETACH) {
425 if (IS_ENABLED(CONFIG_USB_DFU_WILL_DETACH)) {
426 if (usb_dc_detach()) {
427 LOG_ERR("usb_dc_detach failed");
428 }
429 dfu_enter_idle();
430
431 /* Wait 1 SOF period to ensure the host notices the deconnection. */
432 k_sleep(K_MSEC(1));
433
434 if (usb_dc_attach()) {
435 LOG_ERR("usb_dc_attach failed");
436 }
437 } else {
438 dfu_data.state = appIDLE;
439 }
440 }
441 }
442
443 #ifdef CONFIG_USB_DFU_REBOOT
444 static struct k_work_delayable reboot_work;
445
reboot_work_handler(struct k_work * item)446 static void reboot_work_handler(struct k_work *item)
447 {
448 ARG_UNUSED(item);
449
450 sys_reboot(SYS_REBOOT_WARM);
451 }
452
reboot_schedule(void)453 static void reboot_schedule(void)
454 {
455 LOG_DBG("Scheduling reboot in 500ms");
456
457 /*
458 * Reboot with a delay,
459 * so there is some time to send the status to the host
460 */
461 k_work_schedule_for_queue(&USB_WORK_Q, &reboot_work, K_MSEC(500));
462 }
463 #endif
464
dfu_class_handle_to_host(struct usb_setup_packet * setup,int32_t * data_len,uint8_t ** data)465 static int dfu_class_handle_to_host(struct usb_setup_packet *setup,
466 int32_t *data_len, uint8_t **data)
467 {
468 uint32_t bytes_left;
469 uint32_t len;
470 int ret;
471
472 switch (setup->bRequest) {
473 case DFU_GETSTATUS:
474 LOG_DBG("DFU_GETSTATUS: status %d, state %d",
475 dfu_data.status, dfu_data.state);
476
477 if (dfu_data.state == dfuMANIFEST_SYNC) {
478
479 #if defined(CONFIG_USB_DFU_REBOOT)
480 dfu_data.state = dfuMANIFEST_WAIT_RST;
481 reboot_schedule();
482 #else
483 dfu_data.state = dfuIDLE;
484 #endif
485 }
486
487 /* bStatus */
488 (*data)[0] = dfu_data.status;
489 /* bwPollTimeout */
490 sys_put_le16(dfu_data.bwPollTimeout, &(*data)[1]);
491 (*data)[3] = 0U;
492 /* bState */
493 (*data)[4] = dfu_data.state;
494 /* iString */
495 (*data)[5] = 0U;
496 *data_len = 6;
497 break;
498
499 case DFU_GETSTATE:
500 LOG_DBG("DFU_GETSTATE");
501 (*data)[0] = dfu_data.state;
502 *data_len = 1;
503 break;
504
505 case DFU_UPLOAD:
506 LOG_DBG("DFU_UPLOAD block %d, len %d, state %d",
507 setup->wValue, setup->wLength, dfu_data.state);
508
509 if (!IS_ENABLED(CONFIG_USB_DFU_ENABLE_UPLOAD)) {
510 LOG_WRN("Firmware uploading is not enabled");
511 dfu_data.status = errSTALLEDPKT;
512 dfu_data.state = dfuERROR;
513 return -ENOTSUP;
514 }
515
516 if (dfu_check_app_state()) {
517 return -EINVAL;
518 }
519
520 switch (dfu_data.state) {
521 case dfuIDLE:
522 dfu_reset_counters();
523 LOG_DBG("DFU_UPLOAD start");
524 __fallthrough;
525 case dfuUPLOAD_IDLE:
526 if (!setup->wLength ||
527 dfu_data.block_nr != setup->wValue) {
528 LOG_ERR("DFU_UPLOAD block %d, expected %d, "
529 "len %d", setup->wValue,
530 dfu_data.block_nr, setup->wLength);
531 dfu_data.state = dfuERROR;
532 dfu_data.status = errUNKNOWN;
533 return -EINVAL;
534 }
535
536 /* Upload in progress */
537 bytes_left = dfu_data.flash_upload_size -
538 dfu_data.bytes_sent;
539 if (bytes_left < setup->wLength) {
540 len = bytes_left;
541 } else {
542 len = setup->wLength;
543 }
544
545 if (len > USB_DFU_MAX_XFER_SIZE) {
546 /*
547 * The host could requests more data as stated
548 * in wTransferSize. Limit upload length to the
549 * size of the request-buffer.
550 */
551 len = USB_DFU_MAX_XFER_SIZE;
552 }
553
554 if (len) {
555 const struct flash_area *fa;
556
557 ret = flash_area_open(dfu_data.flash_area_id,
558 &fa);
559 if (ret) {
560 dfu_data.state = dfuERROR;
561 dfu_data.status = errFILE;
562 return -EINVAL;
563 }
564 ret = flash_area_read(fa, dfu_data.bytes_sent,
565 *data, len);
566 flash_area_close(fa);
567 if (ret) {
568 dfu_data.state = dfuERROR;
569 dfu_data.status = errFILE;
570 return -EINVAL;
571 }
572 }
573 *data_len = len;
574
575 dfu_data.bytes_sent += len;
576 dfu_data.block_nr++;
577
578 if (dfu_data.bytes_sent == dfu_data.flash_upload_size &&
579 len < setup->wLength) {
580 /* Upload completed when a
581 * short packet is received
582 */
583 *data_len = 0;
584 dfu_data.state = dfuIDLE;
585 } else {
586 dfu_data.state = dfuUPLOAD_IDLE;
587 }
588
589 break;
590 default:
591 LOG_ERR("DFU_UPLOAD wrong state %d", dfu_data.state);
592 dfu_data.state = dfuERROR;
593 dfu_data.status = errUNKNOWN;
594 dfu_reset_counters();
595 return -EINVAL;
596 }
597 break;
598
599 default:
600 LOG_DBG("Unsupported bmRequestType 0x%02x bRequest 0x%02x",
601 setup->bmRequestType, setup->bRequest);
602 return -EINVAL;
603 }
604
605 return 0;
606 }
607
dfu_class_handle_to_device(struct usb_setup_packet * setup,int32_t * data_len,uint8_t ** data)608 static int dfu_class_handle_to_device(struct usb_setup_packet *setup,
609 int32_t *data_len, uint8_t **data)
610 {
611 uint16_t timeout;
612
613 switch (setup->bRequest) {
614 case DFU_ABORT:
615 LOG_DBG("DFU_ABORT");
616
617 if (dfu_check_app_state()) {
618 return -EINVAL;
619 }
620
621 dfu_reset_counters();
622 dfu_data.state = dfuIDLE;
623 dfu_data.status = statusOK;
624 break;
625
626 case DFU_CLRSTATUS:
627 LOG_DBG("DFU_CLRSTATUS");
628
629 if (dfu_check_app_state()) {
630 return -EINVAL;
631 }
632
633 dfu_data.state = dfuIDLE;
634 dfu_data.status = statusOK;
635 break;
636
637 case DFU_DNLOAD:
638 LOG_DBG("DFU_DNLOAD block %d, len %d, state %d",
639 setup->wValue, setup->wLength, dfu_data.state);
640
641 if (dfu_check_app_state()) {
642 return -EINVAL;
643 }
644
645 switch (dfu_data.state) {
646 case dfuIDLE:
647 LOG_DBG("DFU_DNLOAD start");
648 dfu_reset_counters();
649 k_poll_signal_reset(&dfu_signal);
650
651 if (dfu_data.flash_area_id != DOWNLOAD_FLASH_AREA_ID) {
652 dfu_data.status = errWRITE;
653 dfu_data.state = dfuERROR;
654 LOG_ERR("This area can not be overwritten");
655 break;
656 }
657
658 dfu_data.state = dfuDNBUSY;
659 dfu_data_worker.worker_state = dfuIDLE;
660 dfu_data_worker.worker_len = setup->wLength;
661 memcpy(dfu_data_worker.buf, *data, setup->wLength);
662 k_work_submit_to_queue(&USB_WORK_Q, &dfu_work);
663 break;
664 case dfuDNLOAD_IDLE:
665 dfu_data.state = dfuDNBUSY;
666 dfu_data_worker.worker_state = dfuDNLOAD_IDLE;
667 dfu_data_worker.worker_len = setup->wLength;
668
669 memcpy(dfu_data_worker.buf, *data, setup->wLength);
670 k_work_submit_to_queue(&USB_WORK_Q, &dfu_work);
671 break;
672 default:
673 LOG_ERR("DFU_DNLOAD wrong state %d", dfu_data.state);
674 dfu_data.state = dfuERROR;
675 dfu_data.status = errUNKNOWN;
676 dfu_reset_counters();
677 return -EINVAL;
678 }
679 break;
680 case DFU_DETACH:
681 LOG_DBG("DFU_DETACH timeout %d, state %d",
682 setup->wValue, dfu_data.state);
683
684 if (dfu_data.state != appIDLE) {
685 dfu_data.state = appIDLE;
686 return -EINVAL;
687 }
688
689 /* Move to appDETACH state */
690 dfu_data.state = appDETACH;
691 if (IS_ENABLED(CONFIG_USB_DFU_WILL_DETACH)) {
692 /* Note: Detach should happen once the status stage
693 * finishes but the USB device stack does not expose
694 * such callback. Wait fixed time (ignore wValue) to
695 * let device finish control transfer status stage.
696 */
697 timeout = CONFIG_USB_DFU_DETACH_TIMEOUT;
698 } else {
699 /* Begin detach timeout timer */
700 timeout = MIN(setup->wValue, CONFIG_USB_DFU_DETACH_TIMEOUT);
701 }
702 k_work_reschedule_for_queue(&USB_WORK_Q, &dfu_timer_work, K_MSEC(timeout));
703 break;
704 default:
705 LOG_DBG("Unsupported bmRequestType 0x%02x bRequest 0x%02x",
706 setup->bmRequestType, setup->bRequest);
707 return -EINVAL;
708 }
709
710 return 0;
711 }
712
713 /**
714 * @brief Handler called for DFU Class requests not handled by the USB stack.
715 *
716 * @param setup Information about the request to execute.
717 * @param len Size of the buffer.
718 * @param data Buffer containing the request result.
719 *
720 * @return 0 on success, negative errno code on fail.
721 */
dfu_class_handle_req(struct usb_setup_packet * setup,int32_t * data_len,uint8_t ** data)722 static int dfu_class_handle_req(struct usb_setup_packet *setup,
723 int32_t *data_len, uint8_t **data)
724 {
725 if (usb_reqtype_is_to_host(setup)) {
726 return dfu_class_handle_to_host(setup, data_len, data);
727 } else {
728 return dfu_class_handle_to_device(setup, data_len, data);
729 }
730 }
731
732
733 /**
734 * @brief Callback used to know the USB connection status
735 *
736 * @param status USB device status code.
737 *
738 * @return N/A.
739 */
dfu_status_cb(struct usb_cfg_data * cfg,enum usb_dc_status_code status,const uint8_t * param)740 static void dfu_status_cb(struct usb_cfg_data *cfg,
741 enum usb_dc_status_code status,
742 const uint8_t *param)
743 {
744 ARG_UNUSED(param);
745 ARG_UNUSED(cfg);
746
747 /* Check the USB status and do needed action if required */
748 switch (status) {
749 case USB_DC_ERROR:
750 LOG_DBG("USB device error");
751 break;
752 case USB_DC_RESET:
753 LOG_DBG("USB device reset detected, state %d", dfu_data.state);
754 if (!IS_ENABLED(CONFIG_USB_DFU_WILL_DETACH)) {
755 /* Stop the appDETACH timeout timer */
756 k_work_cancel_delayable(&dfu_timer_work);
757 if (dfu_data.state == appDETACH) {
758 dfu_enter_idle();
759 }
760 }
761 break;
762 case USB_DC_CONNECTED:
763 LOG_DBG("USB device connected");
764 break;
765 case USB_DC_CONFIGURED:
766 LOG_DBG("USB device configured");
767 break;
768 case USB_DC_DISCONNECTED:
769 LOG_DBG("USB device disconnected");
770 break;
771 case USB_DC_SUSPEND:
772 LOG_DBG("USB device suspended");
773 break;
774 case USB_DC_RESUME:
775 LOG_DBG("USB device resumed");
776 break;
777 case USB_DC_SOF:
778 break;
779 case USB_DC_UNKNOWN:
780 default:
781 LOG_DBG("USB unknown state");
782 break;
783 }
784 }
785
786 /**
787 * @brief Custom handler for standard ('chapter 9') requests
788 * in order to catch the SET_INTERFACE request and
789 * extract the interface alternate setting
790 *
791 * @param setup Information about the request to execute.
792 * @param len Size of the buffer.
793 * @param data Buffer containing the request result.
794 *
795 * @return -ENOTSUP so that the stack can process control request.
796 */
797
dfu_custom_handle_req(struct usb_setup_packet * setup,int32_t * data_len,uint8_t ** data)798 static int dfu_custom_handle_req(struct usb_setup_packet *setup,
799 int32_t *data_len, uint8_t **data)
800 {
801 ARG_UNUSED(data);
802
803 if (usb_reqtype_is_to_host(setup) ||
804 setup->RequestType.recipient != USB_REQTYPE_RECIPIENT_INTERFACE) {
805 return -ENOTSUP;
806 }
807
808 if (setup->bRequest == USB_SREQ_SET_INTERFACE) {
809 LOG_DBG("DFU alternate setting %d", setup->wValue);
810
811 const struct flash_area *fa;
812
813 switch (setup->wValue) {
814 case 0:
815 dfu_data.flash_area_id =
816 FIXED_PARTITION_ID(SLOT0_PARTITION);
817 break;
818 #if FIXED_PARTITION_EXISTS(SLOT1_PARTITION)
819 case 1:
820 dfu_data.flash_area_id = DOWNLOAD_FLASH_AREA_ID;
821 break;
822 #endif
823 default:
824 LOG_WRN("Invalid DFU alternate setting");
825 return -ENOTSUP;
826 }
827
828 if (flash_area_open(dfu_data.flash_area_id, &fa)) {
829 return -EIO;
830 }
831
832 dfu_data.flash_upload_size = fa->fa_size;
833 flash_area_close(fa);
834 dfu_data.alt_setting = setup->wValue;
835 }
836
837 /* Never handled by us */
838 return -EINVAL;
839 }
840
dfu_interface_config(struct usb_desc_header * head,uint8_t bInterfaceNumber)841 static void dfu_interface_config(struct usb_desc_header *head,
842 uint8_t bInterfaceNumber)
843 {
844 ARG_UNUSED(head);
845
846 dfu_cfg.if0.bInterfaceNumber = bInterfaceNumber;
847 }
848
849 /* Configuration of the DFU Device send to the USB Driver */
850 USBD_DEFINE_CFG_DATA(dfu_config) = {
851 .usb_device_description = NULL,
852 .interface_config = dfu_interface_config,
853 .interface_descriptor = &dfu_cfg.if0,
854 .cb_usb_status = dfu_status_cb,
855 .interface = {
856 .class_handler = dfu_class_handle_req,
857 .custom_handler = dfu_custom_handle_req,
858 },
859 .num_endpoints = 0,
860 };
861
862 /*
863 * Dummy configuration, this is necessary to configure DFU mode descriptor
864 * which is an alternative (secondary) device descriptor.
865 */
866 USBD_DEFINE_CFG_DATA(dfu_mode_config) = {
867 .usb_device_description = NULL,
868 .interface_config = NULL,
869 .interface_descriptor = &dfu_mode_desc.sec_dfu_cfg.if0,
870 .cb_usb_status = dfu_status_cb,
871 .interface = {
872 .class_handler = dfu_class_handle_req,
873 .custom_handler = dfu_custom_handle_req,
874 },
875 .num_endpoints = 0,
876 };
877
dfu_work_handler(struct k_work * item)878 static void dfu_work_handler(struct k_work *item)
879 {
880 ARG_UNUSED(item);
881
882 switch (dfu_data_worker.worker_state) {
883 case dfuIDLE:
884 /*
885 * If progressive erase is enabled, then erase take place while
886 * image collection, so not erase whole bank at DFU beginning
887 */
888 #ifndef CONFIG_IMG_ERASE_PROGRESSIVELY
889 if (boot_erase_img_bank(DOWNLOAD_FLASH_AREA_ID)) {
890 dfu_data.state = dfuERROR;
891 dfu_data.status = errERASE;
892 break;
893 }
894 #endif
895 case dfuDNLOAD_IDLE:
896 dfu_flash_write(dfu_data_worker.buf,
897 dfu_data_worker.worker_len);
898 break;
899 default:
900 LOG_ERR("OUT of state machine");
901 break;
902 }
903 }
904
usb_dfu_init(void)905 static int usb_dfu_init(void)
906 {
907 const struct flash_area *fa;
908
909
910 k_work_init(&dfu_work, dfu_work_handler);
911 k_poll_signal_init(&dfu_signal);
912 k_work_init_delayable(&dfu_timer_work, dfu_timer_work_handler);
913
914 #ifdef CONFIG_USB_DFU_REBOOT
915 k_work_init_delayable(&reboot_work, reboot_work_handler);
916 #endif
917
918 if (flash_area_open(dfu_data.flash_area_id, &fa)) {
919 return -EIO;
920 }
921
922 dfu_data.flash_upload_size = fa->fa_size;
923 flash_area_close(fa);
924
925 return 0;
926 }
927
928 /**
929 * @brief Function to check if DFU is started.
930 *
931 * @return true if DNBUSY/DNLOAD_IDLE, false otherwise.
932 */
is_dfu_started(void)933 static bool is_dfu_started(void)
934 {
935 if ((dfu_data.state == dfuDNBUSY) ||
936 (dfu_data.state == dfuDNLOAD_IDLE)) {
937 return true;
938 }
939
940 return false;
941 }
942
943 /**
944 * @brief Function to check and wait while the USB DFU is in progress.
945 *
946 * @return N/A
947 */
wait_for_usb_dfu(k_timeout_t delay)948 void wait_for_usb_dfu(k_timeout_t delay)
949 {
950 k_timepoint_t end = sys_timepoint_calc(delay);
951
952 /* Wait for a prescribed duration of time. If DFU hasn't started within
953 * that time, stop waiting and proceed further.
954 */
955 while (!sys_timepoint_expired(end)) {
956 if (is_dfu_started()) {
957 k_poll_event_init(&dfu_event, K_POLL_TYPE_SIGNAL,
958 K_POLL_MODE_NOTIFY_ONLY, &dfu_signal);
959
960 /* Wait till DFU is complete */
961 if (k_poll(&dfu_event, 1, K_FOREVER) != 0) {
962 LOG_DBG("USB DFU Error");
963 }
964
965 LOG_INF("USB DFU Completed");
966 break;
967 }
968
969 k_msleep(INTERMITTENT_CHECK_DELAY);
970 }
971 }
972
973 SYS_INIT(usb_dfu_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);
974