Skip to content

Commit 712bc16

Browse files
jfischer-nokartben
authored andcommitted
usb: device_next: add USB DFU flash backend
Add a simpler flash backend, similar to what we have in the legacy USB DFU implementation. Support slot-0 and slot-1 flash partitions, but allow them to be enabled/disabled via Kconfig options. Signed-off-by: Johann Fischer <johann.fischer@nordicsemi.no>
1 parent 8b0bdb5 commit 712bc16

File tree

3 files changed

+185
-0
lines changed

3 files changed

+185
-0
lines changed

subsys/usb/device_next/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@ zephyr_library_sources_ifdef(
8787
class/usbd_dfu.c
8888
)
8989

90+
zephyr_library_sources_ifdef(
91+
CONFIG_USBD_DFU_FLASH
92+
class/usbd_dfu_flash.c
93+
)
94+
9095
zephyr_linker_sources_ifdef(
9196
CONFIG_USBD_DFU
9297
SECTIONS class/usbd_dfu.ld

subsys/usb/device_next/class/Kconfig.dfu

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,29 @@ module = USBD_DFU
4848
module-str = usbd dfu
4949
source "subsys/logging/Kconfig.template.log_config"
5050

51+
config USBD_DFU_FLASH
52+
depends on FLASH && FLASH_MAP && STREAM_FLASH
53+
depends on IMG_MANAGER && IMG_ERASE_PROGRESSIVELY
54+
bool "Built-in flash backend"
55+
help
56+
Enable the built-in flash backend, which can serve up to two image
57+
slots, which is the common configuration of in-tree boards.
58+
59+
if USBD_DFU_FLASH
60+
61+
config USBD_DFU_FLASH_SLOT0
62+
bool "Flash backend for the slot-0 partition"
63+
default y
64+
help
65+
This option enables download or upload for the slot-0 partition, if
66+
one is defined.
67+
68+
config USBD_DFU_FLASH_SLOT1
69+
bool "Flash backend for the slot-1 partition"
70+
help
71+
This option enables download or upload for the slot-1 partition, if
72+
one is defined.
73+
74+
endif # USBD_DFU_FLASH
75+
5176
endif
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
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/kernel.h>
10+
#include <zephyr/usb/usbd.h>
11+
#include <zephyr/usb/class/usbd_dfu.h>
12+
#include <zephyr/drivers/flash.h>
13+
#include <zephyr/storage/flash_map.h>
14+
#include <zephyr/dfu/flash_img.h>
15+
16+
#include <zephyr/logging/log.h>
17+
LOG_MODULE_REGISTER(dfu_flash, CONFIG_USBD_DFU_LOG_LEVEL);
18+
19+
/*
20+
* This file implements the flash backend for the USB DFU implementation. The
21+
* flash backend can serve up to two image slots, which are typically defined
22+
* for the in-tree boards in the Zephyr project.
23+
*/
24+
25+
struct usbd_dfu_flash_data {
26+
struct flash_img_context fi_ctx;
27+
uint32_t last_block;
28+
const uint8_t id;
29+
union {
30+
uint32_t uploaded;
31+
uint32_t downloaded;
32+
};
33+
};
34+
35+
static int dfu_flash_read(void *const priv,
36+
const uint32_t block, const uint16_t size,
37+
uint8_t buf[static CONFIG_USBD_DFU_TRANSFER_SIZE])
38+
{
39+
struct usbd_dfu_flash_data *const data = priv;
40+
const struct flash_area *fa;
41+
uint32_t to_upload;
42+
int len;
43+
int ret;
44+
45+
if (size == 0) {
46+
/* There is nothing to upload */
47+
return 0;
48+
}
49+
50+
if (block == 0) {
51+
data->last_block = 0;
52+
data->uploaded = 0;
53+
} else {
54+
if (data->last_block + 1U != block) {
55+
return -EINVAL;
56+
}
57+
58+
}
59+
60+
ret = flash_area_open(data->id, &fa);
61+
if (ret) {
62+
return ret;
63+
}
64+
65+
if (block == 0) {
66+
LOG_DBG("Flash area size %u", fa->fa_size);
67+
}
68+
69+
to_upload = fa->fa_size - data->uploaded;
70+
if (to_upload < size) {
71+
len = to_upload;
72+
} else {
73+
len = size;
74+
}
75+
76+
ret = flash_area_read(fa, data->uploaded, buf, len);
77+
flash_area_close(fa);
78+
if (ret) {
79+
return ret;
80+
}
81+
82+
data->last_block = block;
83+
data->uploaded += size;
84+
LOG_DBG("uploaded %u block %u len %u", data->uploaded, block, len);
85+
86+
return len;
87+
}
88+
89+
static int dfu_flash_write(void *const priv,
90+
const uint32_t block, const uint16_t size,
91+
const uint8_t buf[static CONFIG_USBD_DFU_TRANSFER_SIZE])
92+
{
93+
struct usbd_dfu_flash_data *const data = priv;
94+
const bool flush = size == 0 ? true : false;
95+
int ret;
96+
97+
if (block == 0) {
98+
if (flash_img_init(&data->fi_ctx)) {
99+
return -EINVAL;
100+
}
101+
102+
data->last_block = 0;
103+
data->downloaded = 0;
104+
105+
if (size == 0) {
106+
/* There is nothing to download */
107+
return 0;
108+
}
109+
} else {
110+
if (data->last_block + 1U != block) {
111+
return -EINVAL;
112+
}
113+
114+
}
115+
116+
ret = flash_img_buffered_write(&data->fi_ctx, buf, size, flush);
117+
if (ret) {
118+
return ret;
119+
}
120+
121+
data->last_block = block;
122+
data->downloaded += size;
123+
LOG_DBG("downloaded %u (%u) block %u size %u", data->downloaded,
124+
flash_img_bytes_written(&data->fi_ctx), block, size);
125+
126+
return 0;
127+
}
128+
129+
static bool dfu_flash_next(void *const priv,
130+
const enum usb_dfu_state state, const enum usb_dfu_state next)
131+
{
132+
if (state == DFU_MANIFEST_SYNC && next == DFU_IDLE) {
133+
LOG_DBG("Download finished");
134+
}
135+
136+
return true;
137+
}
138+
139+
#if FIXED_PARTITION_EXISTS(slot0_partition) && defined(CONFIG_USBD_DFU_FLASH_SLOT0)
140+
static struct usbd_dfu_flash_data slot0_data = {
141+
.id = FIXED_PARTITION_ID(slot0_partition),
142+
};
143+
144+
USBD_DFU_DEFINE_IMG(slot0_image, "slot0_image", &slot0_data,
145+
dfu_flash_read, dfu_flash_write, dfu_flash_next);
146+
#endif
147+
148+
#if FIXED_PARTITION_EXISTS(slot1_partition) && defined(CONFIG_USBD_DFU_FLASH_SLOT1)
149+
static struct usbd_dfu_flash_data slot1_data = {
150+
.id = FIXED_PARTITION_ID(slot1_partition),
151+
};
152+
153+
USBD_DFU_DEFINE_IMG(slot1_image, "slot1_image", &slot1_data,
154+
dfu_flash_read, dfu_flash_write, dfu_flash_next);
155+
#endif

0 commit comments

Comments
 (0)