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 <init.h>
42 #include <kernel.h>
43 #include <stdio.h>
44 #include <errno.h>
45 #include <drivers/flash.h>
46 #include <storage/flash_map.h>
47 #include <dfu/mcuboot.h>
48 #include <dfu/flash_img.h>
49 #include <sys/byteorder.h>
50 #include <usb/usb_device.h>
51 #include <usb/class/usb_dfu.h>
52 #include <usb_descriptor.h>
53 #include <usb_work_q.h>
54
55 #define LOG_LEVEL CONFIG_USB_DEVICE_LOG_LEVEL
56 #include <logging/log.h>
57 LOG_MODULE_REGISTER(usb_dfu);
58
59 #define USB_DFU_MAX_XFER_SIZE CONFIG_USB_REQUEST_BUFFER_SIZE
60
61 #define FIRMWARE_IMAGE_0_LABEL FLASH_AREA_LABEL_STR(image_0)
62 #if FLASH_AREA_LABEL_EXISTS(image_1)
63 #define FIRMWARE_IMAGE_1_LABEL FLASH_AREA_LABEL_STR(image_1)
64 #endif
65
66 #define INTERMITTENT_CHECK_DELAY 50
67
68 static struct k_poll_event dfu_event;
69 static struct k_poll_signal dfu_signal;
70 static struct k_timer dfu_timer;
71
72 static struct k_work dfu_work;
73
74 struct dfu_worker_data_t {
75 uint8_t buf[USB_DFU_MAX_XFER_SIZE];
76 enum dfu_state worker_state;
77 uint16_t worker_len;
78 };
79
80 static struct dfu_worker_data_t dfu_data_worker;
81
82 struct usb_dfu_config {
83 struct usb_if_descriptor if0;
84 struct dfu_runtime_descriptor dfu_descr;
85 } __packed;
86
87 USBD_CLASS_DESCR_DEFINE(primary, 0) struct usb_dfu_config dfu_cfg = {
88 /* Interface descriptor */
89 .if0 = {
90 .bLength = sizeof(struct usb_if_descriptor),
91 .bDescriptorType = USB_DESC_INTERFACE,
92 .bInterfaceNumber = 0,
93 .bAlternateSetting = 0,
94 .bNumEndpoints = 0,
95 .bInterfaceClass = USB_BCC_APPLICATION,
96 .bInterfaceSubClass = DFU_SUBCLASS,
97 .bInterfaceProtocol = DFU_RT_PROTOCOL,
98 .iInterface = 0,
99 },
100 .dfu_descr = {
101 .bLength = sizeof(struct dfu_runtime_descriptor),
102 .bDescriptorType = DFU_FUNC_DESC,
103 .bmAttributes = DFU_ATTR_CAN_DNLOAD |
104 DFU_ATTR_CAN_UPLOAD |
105 DFU_ATTR_MANIFESTATION_TOLERANT,
106 .wDetachTimeOut =
107 sys_cpu_to_le16(CONFIG_USB_DFU_DETACH_TIMEOUT),
108 .wTransferSize =
109 sys_cpu_to_le16(USB_DFU_MAX_XFER_SIZE),
110 .bcdDFUVersion =
111 sys_cpu_to_le16(DFU_VERSION),
112 },
113 };
114
115 /* dfu mode device descriptor */
116
117 struct dev_dfu_mode_descriptor {
118 struct usb_device_descriptor device_descriptor;
119 struct usb_cfg_descriptor cfg_descr;
120 struct usb_sec_dfu_config {
121 struct usb_if_descriptor if0;
122 #if FLASH_AREA_LABEL_EXISTS(image_1)
123 struct usb_if_descriptor if1;
124 #endif
125 struct dfu_runtime_descriptor dfu_descr;
126 } __packed sec_dfu_cfg;
127 } __packed;
128
129
130 USBD_DEVICE_DESCR_DEFINE(secondary)
131 struct dev_dfu_mode_descriptor dfu_mode_desc = {
132 /* Device descriptor */
133 .device_descriptor = {
134 .bLength = sizeof(struct usb_device_descriptor),
135 .bDescriptorType = USB_DESC_DEVICE,
136 .bcdUSB = sys_cpu_to_le16(USB_SRN_2_0),
137 .bDeviceClass = 0,
138 .bDeviceSubClass = 0,
139 .bDeviceProtocol = 0,
140 .bMaxPacketSize0 = USB_MAX_CTRL_MPS,
141 .idVendor = sys_cpu_to_le16((uint16_t)CONFIG_USB_DEVICE_VID),
142 .idProduct =
143 sys_cpu_to_le16((uint16_t)CONFIG_USB_DEVICE_DFU_PID),
144 .bcdDevice = sys_cpu_to_le16(USB_BCD_DRN),
145 .iManufacturer = 1,
146 .iProduct = 2,
147 .iSerialNumber = 3,
148 .bNumConfigurations = 1,
149 },
150 /* Configuration descriptor */
151 .cfg_descr = {
152 .bLength = sizeof(struct usb_cfg_descriptor),
153 .bDescriptorType = USB_DESC_CONFIGURATION,
154 .wTotalLength = 0,
155 .bNumInterfaces = 1,
156 .bConfigurationValue = 1,
157 .iConfiguration = 0,
158 .bmAttributes = USB_SCD_ATTRIBUTES,
159 .bMaxPower = CONFIG_USB_MAX_POWER,
160 },
161 .sec_dfu_cfg = {
162 /* Interface descriptor */
163 .if0 = {
164 .bLength = sizeof(struct usb_if_descriptor),
165 .bDescriptorType = USB_DESC_INTERFACE,
166 .bInterfaceNumber = 0,
167 .bAlternateSetting = 0,
168 .bNumEndpoints = 0,
169 .bInterfaceClass = USB_BCC_APPLICATION,
170 .bInterfaceSubClass = DFU_SUBCLASS,
171 .bInterfaceProtocol = DFU_MODE_PROTOCOL,
172 .iInterface = 4,
173 },
174 #if FLASH_AREA_LABEL_EXISTS(image_1)
175 .if1 = {
176 .bLength = sizeof(struct usb_if_descriptor),
177 .bDescriptorType = USB_DESC_INTERFACE,
178 .bInterfaceNumber = 0,
179 .bAlternateSetting = 1,
180 .bNumEndpoints = 0,
181 .bInterfaceClass = USB_BCC_APPLICATION,
182 .bInterfaceSubClass = DFU_SUBCLASS,
183 .bInterfaceProtocol = DFU_MODE_PROTOCOL,
184 .iInterface = 5,
185 },
186 #endif
187 .dfu_descr = {
188 .bLength = sizeof(struct dfu_runtime_descriptor),
189 .bDescriptorType = DFU_FUNC_DESC,
190 .bmAttributes = DFU_ATTR_CAN_DNLOAD |
191 DFU_ATTR_CAN_UPLOAD |
192 DFU_ATTR_MANIFESTATION_TOLERANT,
193 .wDetachTimeOut =
194 sys_cpu_to_le16(CONFIG_USB_DFU_DETACH_TIMEOUT),
195 .wTransferSize =
196 sys_cpu_to_le16(USB_DFU_MAX_XFER_SIZE),
197 .bcdDFUVersion =
198 sys_cpu_to_le16(DFU_VERSION),
199 },
200 },
201 };
202
203 struct usb_string_desription {
204 struct usb_string_descriptor lang_descr;
205 struct usb_mfr_descriptor {
206 uint8_t bLength;
207 uint8_t bDescriptorType;
208 uint8_t bString[USB_BSTRING_LENGTH(
209 CONFIG_USB_DEVICE_MANUFACTURER)];
210 } __packed utf16le_mfr;
211
212 struct usb_product_descriptor {
213 uint8_t bLength;
214 uint8_t bDescriptorType;
215 uint8_t bString[USB_BSTRING_LENGTH(CONFIG_USB_DEVICE_PRODUCT)];
216 } __packed utf16le_product;
217
218 struct usb_sn_descriptor {
219 uint8_t bLength;
220 uint8_t bDescriptorType;
221 uint8_t bString[USB_BSTRING_LENGTH(CONFIG_USB_DEVICE_SN)];
222 } __packed utf16le_sn;
223
224 struct image_0_descriptor {
225 uint8_t bLength;
226 uint8_t bDescriptorType;
227 uint8_t bString[USB_BSTRING_LENGTH(FIRMWARE_IMAGE_0_LABEL)];
228 } __packed utf16le_image0;
229
230 #if FLASH_AREA_LABEL_EXISTS(image_1)
231 struct image_1_descriptor {
232 uint8_t bLength;
233 uint8_t bDescriptorType;
234 uint8_t bString[USB_BSTRING_LENGTH(FIRMWARE_IMAGE_1_LABEL)];
235 } __packed utf16le_image1;
236 #endif
237 } __packed;
238
239 USBD_STRING_DESCR_DEFINE(secondary)
240 struct usb_string_desription string_descr = {
241 .lang_descr = {
242 .bLength = sizeof(struct usb_string_descriptor),
243 .bDescriptorType = USB_DESC_STRING,
244 .bString = sys_cpu_to_le16(0x0409),
245 },
246 /* Manufacturer String Descriptor */
247 .utf16le_mfr = {
248 .bLength = USB_STRING_DESCRIPTOR_LENGTH(
249 CONFIG_USB_DEVICE_MANUFACTURER),
250 .bDescriptorType = USB_DESC_STRING,
251 .bString = CONFIG_USB_DEVICE_MANUFACTURER,
252 },
253 /* Product String Descriptor */
254 .utf16le_product = {
255 .bLength = USB_STRING_DESCRIPTOR_LENGTH(
256 CONFIG_USB_DEVICE_PRODUCT),
257 .bDescriptorType = USB_DESC_STRING,
258 .bString = CONFIG_USB_DEVICE_PRODUCT,
259 },
260 /* Serial Number String Descriptor */
261 .utf16le_sn = {
262 .bLength = USB_STRING_DESCRIPTOR_LENGTH(CONFIG_USB_DEVICE_SN),
263 .bDescriptorType = USB_DESC_STRING,
264 .bString = CONFIG_USB_DEVICE_SN,
265 },
266 /* Image 0 String Descriptor */
267 .utf16le_image0 = {
268 .bLength = USB_STRING_DESCRIPTOR_LENGTH(
269 FIRMWARE_IMAGE_0_LABEL),
270 .bDescriptorType = USB_DESC_STRING,
271 .bString = FIRMWARE_IMAGE_0_LABEL,
272 },
273 #if FLASH_AREA_LABEL_EXISTS(image_1)
274 /* Image 1 String Descriptor */
275 .utf16le_image1 = {
276 .bLength = USB_STRING_DESCRIPTOR_LENGTH(
277 FIRMWARE_IMAGE_1_LABEL),
278 .bDescriptorType = USB_DESC_STRING,
279 .bString = FIRMWARE_IMAGE_1_LABEL,
280 },
281 #endif
282 };
283
284 /* This element marks the end of the entire descriptor. */
285 USBD_TERM_DESCR_DEFINE(secondary) struct usb_desc_header term_descr = {
286 .bLength = 0,
287 .bDescriptorType = 0,
288 };
289
290 static struct usb_cfg_data dfu_config;
291
292 /* Device data structure */
293 struct dfu_data_t {
294 uint8_t flash_area_id;
295 uint32_t flash_upload_size;
296 /* Number of bytes sent during upload */
297 uint32_t bytes_sent;
298 uint32_t alt_setting; /* DFU alternate setting */
299 struct flash_img_context ctx;
300 enum dfu_state state; /* State of the DFU device */
301 enum dfu_status status; /* Status of the DFU device */
302 uint16_t block_nr; /* DFU block number */
303 uint16_t bwPollTimeout;
304 };
305
306 #if FLASH_AREA_LABEL_EXISTS(image_1)
307 #define UPLOAD_FLASH_AREA_ID FLASH_AREA_ID(image_1)
308 #else
309 #define UPLOAD_FLASH_AREA_ID FLASH_AREA_ID(image_0)
310 #endif
311
312
313 static struct dfu_data_t dfu_data = {
314 .state = appIDLE,
315 .status = statusOK,
316 .flash_area_id = UPLOAD_FLASH_AREA_ID,
317 .alt_setting = 0,
318 .bwPollTimeout = CONFIG_USB_DFU_DEFAULT_POLLTIMEOUT,
319 };
320
321 /**
322 * @brief Helper function to check if in DFU app state.
323 *
324 * @return true if app state, false otherwise.
325 */
dfu_check_app_state(void)326 static bool dfu_check_app_state(void)
327 {
328 if (dfu_data.state == appIDLE ||
329 dfu_data.state == appDETACH) {
330 dfu_data.state = appIDLE;
331 return true;
332 }
333
334 return false;
335 }
336
337 /**
338 * @brief Helper function to reset DFU internal counters.
339 */
dfu_reset_counters(void)340 static void dfu_reset_counters(void)
341 {
342 dfu_data.bytes_sent = 0U;
343 dfu_data.block_nr = 0U;
344 if (flash_img_init(&dfu_data.ctx)) {
345 LOG_ERR("flash img init error");
346 dfu_data.state = dfuERROR;
347 dfu_data.status = errUNKNOWN;
348 }
349 }
350
dfu_flash_write(uint8_t * data,size_t len)351 static void dfu_flash_write(uint8_t *data, size_t len)
352 {
353 bool flush = false;
354
355 if (!len) {
356 /* Download completed */
357 flush = true;
358 }
359
360 if (flash_img_buffered_write(&dfu_data.ctx, data, len, flush)) {
361 LOG_ERR("flash write error");
362 dfu_data.state = dfuERROR;
363 dfu_data.status = errWRITE;
364 } else if (!len) {
365 LOG_DBG("flash write done");
366 dfu_data.state = dfuMANIFEST_SYNC;
367 dfu_reset_counters();
368 if (boot_request_upgrade(false)) {
369 dfu_data.state = dfuERROR;
370 dfu_data.status = errWRITE;
371 }
372
373 k_poll_signal_raise(&dfu_signal, 0);
374 } else {
375 dfu_data.state = dfuDNLOAD_IDLE;
376 }
377
378 LOG_DBG("bytes written 0x%x", flash_img_bytes_written(&dfu_data.ctx));
379 }
380
dfu_timer_expired(struct k_timer * timer)381 static void dfu_timer_expired(struct k_timer *timer)
382 {
383 if (dfu_data.state == appDETACH) {
384 dfu_data.state = appIDLE;
385 }
386 }
387
dfu_class_handle_to_host(struct usb_setup_packet * setup,int32_t * data_len,uint8_t ** data)388 static int dfu_class_handle_to_host(struct usb_setup_packet *setup,
389 int32_t *data_len, uint8_t **data)
390 {
391 uint32_t bytes_left;
392 uint32_t len;
393 int ret;
394
395 switch (setup->bRequest) {
396 case DFU_GETSTATUS:
397 LOG_DBG("DFU_GETSTATUS: status %d, state %d",
398 dfu_data.status, dfu_data.state);
399
400 if (dfu_data.state == dfuMANIFEST_SYNC) {
401 dfu_data.state = dfuIDLE;
402 }
403
404 /* bStatus */
405 (*data)[0] = dfu_data.status;
406 /* bwPollTimeout */
407 sys_put_le16(dfu_data.bwPollTimeout, &(*data)[1]);
408 (*data)[3] = 0U;
409 /* bState */
410 (*data)[4] = dfu_data.state;
411 /* iString */
412 (*data)[5] = 0U;
413 *data_len = 6;
414 break;
415
416 case DFU_GETSTATE:
417 LOG_DBG("DFU_GETSTATE");
418 (*data)[0] = dfu_data.state;
419 *data_len = 1;
420 break;
421
422 case DFU_UPLOAD:
423 LOG_DBG("DFU_UPLOAD block %d, len %d, state %d",
424 setup->wValue, setup->wLength, dfu_data.state);
425
426 if (dfu_check_app_state()) {
427 return -EINVAL;
428 }
429
430 switch (dfu_data.state) {
431 case dfuIDLE:
432 dfu_reset_counters();
433 LOG_DBG("DFU_UPLOAD start");
434 __fallthrough;
435 case dfuUPLOAD_IDLE:
436 if (!setup->wLength ||
437 dfu_data.block_nr != setup->wValue) {
438 LOG_ERR("DFU_UPLOAD block %d, expected %d, "
439 "len %d", setup->wValue,
440 dfu_data.block_nr, setup->wLength);
441 dfu_data.state = dfuERROR;
442 dfu_data.status = errUNKNOWN;
443 return -EINVAL;
444 }
445
446 /* Upload in progress */
447 bytes_left = dfu_data.flash_upload_size -
448 dfu_data.bytes_sent;
449 if (bytes_left < setup->wLength) {
450 len = bytes_left;
451 } else {
452 len = setup->wLength;
453 }
454
455 if (len > USB_DFU_MAX_XFER_SIZE) {
456 /*
457 * The host could requests more data as stated
458 * in wTransferSize. Limit upload length to the
459 * size of the request-buffer.
460 */
461 len = USB_DFU_MAX_XFER_SIZE;
462 }
463
464 if (len) {
465 const struct flash_area *fa;
466
467 ret = flash_area_open(dfu_data.flash_area_id,
468 &fa);
469 if (ret) {
470 dfu_data.state = dfuERROR;
471 dfu_data.status = errFILE;
472 return -EINVAL;
473 }
474 ret = flash_area_read(fa, dfu_data.bytes_sent,
475 *data, len);
476 flash_area_close(fa);
477 if (ret) {
478 dfu_data.state = dfuERROR;
479 dfu_data.status = errFILE;
480 return -EINVAL;
481 }
482 }
483 *data_len = len;
484
485 dfu_data.bytes_sent += len;
486 dfu_data.block_nr++;
487
488 if (dfu_data.bytes_sent == dfu_data.flash_upload_size &&
489 len < setup->wLength) {
490 /* Upload completed when a
491 * short packet is received
492 */
493 *data_len = 0;
494 dfu_data.state = dfuIDLE;
495 } else {
496 dfu_data.state = dfuUPLOAD_IDLE;
497 }
498
499 break;
500 default:
501 LOG_ERR("DFU_UPLOAD wrong state %d", dfu_data.state);
502 dfu_data.state = dfuERROR;
503 dfu_data.status = errUNKNOWN;
504 dfu_reset_counters();
505 return -EINVAL;
506 }
507 break;
508
509 default:
510 LOG_DBG("Unsupported bmRequestType 0x%02x bRequest 0x%02x",
511 setup->bmRequestType, setup->bRequest);
512 return -EINVAL;
513 }
514
515 return 0;
516 }
517
dfu_class_handle_to_device(struct usb_setup_packet * setup,int32_t * data_len,uint8_t ** data)518 static int dfu_class_handle_to_device(struct usb_setup_packet *setup,
519 int32_t *data_len, uint8_t **data)
520 {
521 uint16_t timeout;
522
523 switch (setup->bRequest) {
524 case DFU_ABORT:
525 LOG_DBG("DFU_ABORT");
526
527 if (dfu_check_app_state()) {
528 return -EINVAL;
529 }
530
531 dfu_reset_counters();
532 dfu_data.state = dfuIDLE;
533 dfu_data.status = statusOK;
534 break;
535
536 case DFU_CLRSTATUS:
537 LOG_DBG("DFU_CLRSTATUS");
538
539 if (dfu_check_app_state()) {
540 return -EINVAL;
541 }
542
543 dfu_data.state = dfuIDLE;
544 dfu_data.status = statusOK;
545 break;
546
547 case DFU_DNLOAD:
548 LOG_DBG("DFU_DNLOAD block %d, len %d, state %d",
549 setup->wValue, setup->wLength, dfu_data.state);
550
551 if (dfu_check_app_state()) {
552 return -EINVAL;
553 }
554
555 switch (dfu_data.state) {
556 case dfuIDLE:
557 LOG_DBG("DFU_DNLOAD start");
558 dfu_reset_counters();
559 k_poll_signal_reset(&dfu_signal);
560
561 if (dfu_data.flash_area_id != UPLOAD_FLASH_AREA_ID) {
562 dfu_data.status = errWRITE;
563 dfu_data.state = dfuERROR;
564 LOG_ERR("This area can not be overwritten");
565 break;
566 }
567
568 dfu_data.state = dfuDNBUSY;
569 dfu_data_worker.worker_state = dfuIDLE;
570 dfu_data_worker.worker_len = setup->wLength;
571 memcpy(dfu_data_worker.buf, *data, setup->wLength);
572 k_work_submit_to_queue(&USB_WORK_Q, &dfu_work);
573 break;
574 case dfuDNLOAD_IDLE:
575 dfu_data.state = dfuDNBUSY;
576 dfu_data_worker.worker_state = dfuDNLOAD_IDLE;
577 dfu_data_worker.worker_len = setup->wLength;
578
579 memcpy(dfu_data_worker.buf, *data, setup->wLength);
580 k_work_submit_to_queue(&USB_WORK_Q, &dfu_work);
581 break;
582 default:
583 LOG_ERR("DFU_DNLOAD wrong state %d", dfu_data.state);
584 dfu_data.state = dfuERROR;
585 dfu_data.status = errUNKNOWN;
586 dfu_reset_counters();
587 return -EINVAL;
588 }
589 break;
590 case DFU_DETACH:
591 LOG_DBG("DFU_DETACH timeout %d, state %d",
592 setup->wValue, dfu_data.state);
593
594 if (dfu_data.state != appIDLE) {
595 dfu_data.state = appIDLE;
596 return -EINVAL;
597 }
598
599 /* Move to appDETACH state */
600 dfu_data.state = appDETACH;
601 /* Begin detach timeout timer */
602 timeout = MIN(setup->wValue, CONFIG_USB_DFU_DETACH_TIMEOUT);
603 k_timer_start(&dfu_timer, K_MSEC(timeout), K_FOREVER);
604 break;
605 default:
606 LOG_DBG("Unsupported bmRequestType 0x%02x bRequest 0x%02x",
607 setup->bmRequestType, setup->bRequest);
608 return -EINVAL;
609 }
610
611 return 0;
612 }
613
614 /**
615 * @brief Handler called for DFU Class requests not handled by the USB stack.
616 *
617 * @param setup Information about the request to execute.
618 * @param len Size of the buffer.
619 * @param data Buffer containing the request result.
620 *
621 * @return 0 on success, negative errno code on fail.
622 */
dfu_class_handle_req(struct usb_setup_packet * setup,int32_t * data_len,uint8_t ** data)623 static int dfu_class_handle_req(struct usb_setup_packet *setup,
624 int32_t *data_len, uint8_t **data)
625 {
626 if (usb_reqtype_is_to_host(setup)) {
627 return dfu_class_handle_to_host(setup, data_len, data);
628 } else {
629 return dfu_class_handle_to_device(setup, data_len, data);
630 }
631 }
632
633
634 /**
635 * @brief Callback used to know the USB connection status
636 *
637 * @param status USB device status code.
638 *
639 * @return N/A.
640 */
dfu_status_cb(struct usb_cfg_data * cfg,enum usb_dc_status_code status,const uint8_t * param)641 static void dfu_status_cb(struct usb_cfg_data *cfg,
642 enum usb_dc_status_code status,
643 const uint8_t *param)
644 {
645 ARG_UNUSED(param);
646 ARG_UNUSED(cfg);
647
648 /* Check the USB status and do needed action if required */
649 switch (status) {
650 case USB_DC_ERROR:
651 LOG_DBG("USB device error");
652 break;
653 case USB_DC_RESET:
654 LOG_DBG("USB device reset detected, state %d", dfu_data.state);
655 /* Stop the appDETACH timeout timer */
656 k_timer_stop(&dfu_timer);
657 if (dfu_data.state == appDETACH) {
658 dfu_data.state = dfuIDLE;
659
660 /* Set the DFU mode descriptors to be used after
661 * reset
662 */
663 dfu_config.usb_device_description =
664 (uint8_t *) &dfu_mode_desc;
665 if (usb_set_config(dfu_config.usb_device_description)) {
666 LOG_ERR("usb_set_config failed during USB "
667 "device reset");
668 }
669 }
670 break;
671 case USB_DC_CONNECTED:
672 LOG_DBG("USB device connected");
673 break;
674 case USB_DC_CONFIGURED:
675 LOG_DBG("USB device configured");
676 break;
677 case USB_DC_DISCONNECTED:
678 LOG_DBG("USB device disconnected");
679 break;
680 case USB_DC_SUSPEND:
681 LOG_DBG("USB device supended");
682 break;
683 case USB_DC_RESUME:
684 LOG_DBG("USB device resumed");
685 break;
686 case USB_DC_SOF:
687 break;
688 case USB_DC_UNKNOWN:
689 default:
690 LOG_DBG("USB unknown state");
691 break;
692 }
693 }
694
695 /**
696 * @brief Custom handler for standard ('chapter 9') requests
697 * in order to catch the SET_INTERFACE request and
698 * extract the interface alternate setting
699 *
700 * @param setup Information about the request to execute.
701 * @param len Size of the buffer.
702 * @param data Buffer containing the request result.
703 *
704 * @return -ENOTSUP so that the stack can process control request.
705 */
706
dfu_custom_handle_req(struct usb_setup_packet * setup,int32_t * data_len,uint8_t ** data)707 static int dfu_custom_handle_req(struct usb_setup_packet *setup,
708 int32_t *data_len, uint8_t **data)
709 {
710 ARG_UNUSED(data);
711
712 if (usb_reqtype_is_to_host(setup) ||
713 setup->RequestType.recipient != USB_REQTYPE_RECIPIENT_INTERFACE) {
714 return -ENOTSUP;
715 }
716
717 if (setup->bRequest == USB_SREQ_SET_INTERFACE) {
718 LOG_DBG("DFU alternate setting %d", setup->wValue);
719
720 const struct flash_area *fa;
721
722 switch (setup->wValue) {
723 case 0:
724 dfu_data.flash_area_id =
725 FLASH_AREA_ID(image_0);
726 break;
727 #if FLASH_AREA_LABEL_EXISTS(image_1)
728 case 1:
729 dfu_data.flash_area_id =
730 UPLOAD_FLASH_AREA_ID;
731 break;
732 #endif
733 default:
734 LOG_WRN("Invalid DFU alternate setting");
735 return -ENOTSUP;
736 }
737
738 if (flash_area_open(dfu_data.flash_area_id, &fa)) {
739 return -EIO;
740 }
741
742 dfu_data.flash_upload_size = fa->fa_size;
743 flash_area_close(fa);
744 dfu_data.alt_setting = setup->wValue;
745 }
746
747 /* Never handled by us */
748 return -EINVAL;
749 }
750
dfu_interface_config(struct usb_desc_header * head,uint8_t bInterfaceNumber)751 static void dfu_interface_config(struct usb_desc_header *head,
752 uint8_t bInterfaceNumber)
753 {
754 ARG_UNUSED(head);
755
756 dfu_cfg.if0.bInterfaceNumber = bInterfaceNumber;
757 }
758
759 /* Configuration of the DFU Device send to the USB Driver */
760 USBD_CFG_DATA_DEFINE(primary, dfu) struct usb_cfg_data dfu_config = {
761 .usb_device_description = NULL,
762 .interface_config = dfu_interface_config,
763 .interface_descriptor = &dfu_cfg.if0,
764 .cb_usb_status = dfu_status_cb,
765 .interface = {
766 .class_handler = dfu_class_handle_req,
767 .custom_handler = dfu_custom_handle_req,
768 },
769 .num_endpoints = 0,
770 };
771
772 /*
773 * Dummy configuration, this is necessary to configure DFU mode descriptor
774 * which is an alternative (secondary) device descriptor.
775 */
776 USBD_CFG_DATA_DEFINE(secondary, dfu) struct usb_cfg_data dfu_mode_config = {
777 .usb_device_description = NULL,
778 .interface_config = NULL,
779 .interface_descriptor = &dfu_mode_desc.sec_dfu_cfg.if0,
780 .cb_usb_status = dfu_status_cb,
781 .interface = {
782 .class_handler = dfu_class_handle_req,
783 .custom_handler = dfu_custom_handle_req,
784 },
785 .num_endpoints = 0,
786 };
787
dfu_work_handler(struct k_work * item)788 static void dfu_work_handler(struct k_work *item)
789 {
790 ARG_UNUSED(item);
791
792 switch (dfu_data_worker.worker_state) {
793 case dfuIDLE:
794 /*
795 * If progressive erase is enabled, then erase take place while
796 * image collection, so not erase whole bank at DFU beginning
797 */
798 #ifndef CONFIG_IMG_ERASE_PROGRESSIVELY
799 if (boot_erase_img_bank(UPLOAD_FLASH_AREA_ID)) {
800 dfu_data.state = dfuERROR;
801 dfu_data.status = errERASE;
802 break;
803 }
804 #endif
805 case dfuDNLOAD_IDLE:
806 dfu_flash_write(dfu_data_worker.buf,
807 dfu_data_worker.worker_len);
808 break;
809 default:
810 LOG_ERR("OUT of state machine");
811 break;
812 }
813 }
814
usb_dfu_init(const struct device * dev)815 static int usb_dfu_init(const struct device *dev)
816 {
817 const struct flash_area *fa;
818
819 ARG_UNUSED(dev);
820
821 k_work_init(&dfu_work, dfu_work_handler);
822 k_poll_signal_init(&dfu_signal);
823 k_timer_init(&dfu_timer, dfu_timer_expired, NULL);
824
825 if (flash_area_open(dfu_data.flash_area_id, &fa)) {
826 return -EIO;
827 }
828
829 dfu_data.flash_upload_size = fa->fa_size;
830 flash_area_close(fa);
831
832 return 0;
833 }
834
835 /**
836 * @brief Function to check if DFU is started.
837 *
838 * @return true if DNBUSY/DNLOAD_IDLE, false otherwise.
839 */
is_dfu_started(void)840 static bool is_dfu_started(void)
841 {
842 if ((dfu_data.state == dfuDNBUSY) ||
843 (dfu_data.state == dfuDNLOAD_IDLE)) {
844 return true;
845 }
846
847 return false;
848 }
849
850 /**
851 * @brief Function to check and wait while the USB DFU is in progress.
852 *
853 * @return N/A
854 */
wait_for_usb_dfu(k_timeout_t delay)855 void wait_for_usb_dfu(k_timeout_t delay)
856 {
857 uint64_t end = sys_clock_timeout_end_calc(delay);
858
859 /* Wait for a prescribed duration of time. If DFU hasn't started within
860 * that time, stop waiting and proceed further.
861 */
862 while (end > k_uptime_ticks()) {
863 if (is_dfu_started()) {
864 k_poll_event_init(&dfu_event, K_POLL_TYPE_SIGNAL,
865 K_POLL_MODE_NOTIFY_ONLY, &dfu_signal);
866
867 /* Wait till DFU is complete */
868 if (k_poll(&dfu_event, 1, K_FOREVER) != 0) {
869 LOG_DBG("USB DFU Error");
870 }
871
872 LOG_INF("USB DFU Completed");
873 break;
874 }
875
876 k_msleep(INTERMITTENT_CHECK_DELAY);
877 }
878 }
879
880 SYS_INIT(usb_dfu_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);
881