1 /*
2  * Copyright (c) 2022, sakumisu
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include "usbd_core.h"
7 #include "usbd_dfu.h"
8 
9 /** Modify the following three parameters according to different platforms */
10 #ifndef USBD_DFU_XFER_SIZE
11 #define USBD_DFU_XFER_SIZE 1024
12 #endif
13 
14 #ifndef USBD_DFU_APP_DEFAULT_ADD
15 #define USBD_DFU_APP_DEFAULT_ADD 0x8004000
16 #endif
17 
18 #ifndef FLASH_PROGRAM_TIME
19 #define FLASH_PROGRAM_TIME 50
20 #endif
21 
22 #ifndef FLASH_ERASE_TIME
23 #define FLASH_ERASE_TIME 50
24 #endif
25 
26 struct usbd_dfu_priv {
27     struct dfu_info info;
28     union {
29         uint32_t d32[USBD_DFU_XFER_SIZE / 4U];
30         uint8_t d8[USBD_DFU_XFER_SIZE];
31     } buffer;
32 
33     uint32_t wblock_num;
34     uint32_t wlength;
35     uint32_t data_ptr;
36     uint32_t alt_setting;
37 
38     uint8_t dev_status[6];
39     uint8_t ReservedForAlign[2];
40     uint8_t dev_state;
41     uint8_t manif_state;
42     uint8_t firmwar_flag;
43 } g_usbd_dfu;
44 
dfu_reset(void)45 static void dfu_reset(void)
46 {
47     memset(&g_usbd_dfu, 0, sizeof(g_usbd_dfu));
48 
49     g_usbd_dfu.alt_setting = 0U;
50     g_usbd_dfu.data_ptr = USBD_DFU_APP_DEFAULT_ADD;
51     g_usbd_dfu.wblock_num = 0U;
52     g_usbd_dfu.wlength = 0U;
53 
54     g_usbd_dfu.manif_state = DFU_MANIFEST_COMPLETE;
55     g_usbd_dfu.dev_state = DFU_STATE_DFU_IDLE;
56 
57     g_usbd_dfu.dev_status[0] = DFU_STATUS_OK;
58     g_usbd_dfu.dev_status[1] = 0U;
59     g_usbd_dfu.dev_status[2] = 0U;
60     g_usbd_dfu.dev_status[3] = 0U;
61     g_usbd_dfu.dev_status[4] = DFU_STATE_DFU_IDLE;
62     g_usbd_dfu.dev_status[5] = 0U;
63 }
64 
dfu_getstatus(uint32_t add,uint8_t cmd,uint8_t * buffer)65 static uint16_t dfu_getstatus(uint32_t add, uint8_t cmd, uint8_t *buffer)
66 {
67     switch (cmd) {
68         case DFU_MEDIA_PROGRAM:
69             buffer[1] = (uint8_t)FLASH_PROGRAM_TIME;
70             buffer[2] = (uint8_t)(FLASH_PROGRAM_TIME << 8);
71             buffer[3] = 0;
72             break;
73 
74         case DFU_MEDIA_ERASE:
75             buffer[1] = (uint8_t)FLASH_ERASE_TIME;
76             buffer[2] = (uint8_t)(FLASH_ERASE_TIME << 8);
77             buffer[3] = 0;
78         default:
79 
80             break;
81     }
82     return (0);
83 }
84 
dfu_request_detach(void)85 static void dfu_request_detach(void)
86 {
87     if ((g_usbd_dfu.dev_state == DFU_STATE_DFU_IDLE) ||
88         (g_usbd_dfu.dev_state == DFU_STATE_DFU_DNLOAD_SYNC) ||
89         (g_usbd_dfu.dev_state == DFU_STATE_DFU_DNLOAD_IDLE) ||
90         (g_usbd_dfu.dev_state == DFU_STATE_DFU_MANIFEST_SYNC) ||
91         (g_usbd_dfu.dev_state == DFU_STATE_DFU_UPLOAD_IDLE)) {
92         /* Update the state machine */
93         g_usbd_dfu.dev_state = DFU_STATE_DFU_IDLE;
94         g_usbd_dfu.dev_status[0] = DFU_STATUS_OK;
95         g_usbd_dfu.dev_status[1] = 0U;
96         g_usbd_dfu.dev_status[2] = 0U;
97         g_usbd_dfu.dev_status[3] = 0U; /*bwPollTimeout=0ms*/
98         g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
99         g_usbd_dfu.dev_status[5] = 0U; /*iString*/
100         g_usbd_dfu.wblock_num = 0U;
101         g_usbd_dfu.wlength = 0U;
102     }
103 }
104 
dfu_request_upload(struct usb_setup_packet * setup,uint8_t ** data,uint32_t * len)105 static void dfu_request_upload(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
106 {
107     struct usb_setup_packet *req = setup;
108     uint32_t addr;
109     uint8_t *phaddr;
110     /* Data setup request */
111     if (req->wLength > 0U) {
112         if ((g_usbd_dfu.dev_state == DFU_STATE_DFU_IDLE) || (g_usbd_dfu.dev_state == DFU_STATE_DFU_UPLOAD_IDLE)) {
113             /* Update the global length and block number */
114             g_usbd_dfu.wblock_num = req->wValue;
115             g_usbd_dfu.wlength = MIN(req->wLength, USBD_DFU_XFER_SIZE);
116 
117             /* DFU Get Command */
118             if (g_usbd_dfu.wblock_num == 0U) {
119                 /* Update the state machine */
120                 g_usbd_dfu.dev_state = (g_usbd_dfu.wlength > 3U) ? DFU_STATE_DFU_IDLE : DFU_STATE_DFU_UPLOAD_IDLE;
121 
122                 g_usbd_dfu.dev_status[1] = 0U;
123                 g_usbd_dfu.dev_status[2] = 0U;
124                 g_usbd_dfu.dev_status[3] = 0U;
125                 g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
126 
127                 /* Store the values of all supported commands */
128                 g_usbd_dfu.buffer.d8[0] = DFU_CMD_GETCOMMANDS;
129                 g_usbd_dfu.buffer.d8[1] = DFU_CMD_SETADDRESSPOINTER;
130                 g_usbd_dfu.buffer.d8[2] = DFU_CMD_ERASE;
131 
132                 /* Send the status data over EP0 */
133                 memcpy(*data, g_usbd_dfu.buffer.d8, 3);
134                 *len = 3;
135             } else if (g_usbd_dfu.wblock_num > 1U) {
136                 g_usbd_dfu.dev_state = DFU_STATE_DFU_UPLOAD_IDLE;
137 
138                 g_usbd_dfu.dev_status[1] = 0U;
139                 g_usbd_dfu.dev_status[2] = 0U;
140                 g_usbd_dfu.dev_status[3] = 0U;
141                 g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
142 
143                 addr = ((g_usbd_dfu.wblock_num - 2U) * USBD_DFU_XFER_SIZE) + g_usbd_dfu.data_ptr;
144 
145                 /* Return the physical address where data are stored */
146                 phaddr = dfu_read_flash((uint8_t *)addr, g_usbd_dfu.buffer.d8, g_usbd_dfu.wlength);
147 
148                 /* Send the status data over EP0 */
149                 memcpy(*data, g_usbd_dfu.buffer.d8, g_usbd_dfu.wlength);
150                 *len = g_usbd_dfu.wlength;
151             } else /* unsupported g_usbd_dfu.wblock_num */
152             {
153                 g_usbd_dfu.dev_state = DFU_STATUS_ERR_STALLEDPKT;
154 
155                 g_usbd_dfu.dev_status[1] = 0U;
156                 g_usbd_dfu.dev_status[2] = 0U;
157                 g_usbd_dfu.dev_status[3] = 0U;
158                 g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
159 
160                 /* Call the error management function (command will be NAKed */
161                 USB_LOG_ERR("Dfu_request_upload unsupported g_usbd_dfu.wblock_num\r\n");
162             }
163         }
164         /* Unsupported state */
165         else {
166             g_usbd_dfu.wlength = 0U;
167             g_usbd_dfu.wblock_num = 0U;
168 
169             /* Call the error management function (command will be NAKed */
170             USB_LOG_ERR("Dfu_request_upload unsupported state\r\n");
171         }
172     }
173     /* No Data setup request */
174     else {
175         g_usbd_dfu.dev_state = DFU_STATE_DFU_IDLE;
176 
177         g_usbd_dfu.dev_status[1] = 0U;
178         g_usbd_dfu.dev_status[2] = 0U;
179         g_usbd_dfu.dev_status[3] = 0U;
180         g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
181     }
182 }
183 
dfu_request_dnload(struct usb_setup_packet * setup,uint8_t ** data,uint32_t * len)184 static void dfu_request_dnload(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
185 {
186     /* Data setup request */
187     struct usb_setup_packet *req = setup;
188     if (req->wLength > 0U) {
189         if ((g_usbd_dfu.dev_state == DFU_STATE_DFU_IDLE) || (g_usbd_dfu.dev_state == DFU_STATE_DFU_DNLOAD_IDLE)) {
190             /* Update the global length and block number */
191             g_usbd_dfu.wblock_num = req->wValue;
192             g_usbd_dfu.wlength = MIN(req->wLength, USBD_DFU_XFER_SIZE);
193 
194             /* Update the state machine */
195             g_usbd_dfu.dev_state = DFU_STATE_DFU_DNLOAD_SYNC;
196             g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
197 
198             /*!< Data has received complete */
199             memcpy((uint8_t *)g_usbd_dfu.buffer.d8, (uint8_t *)*data, g_usbd_dfu.wlength);
200             /*!< Set flag = 1 Write the firmware to the flash in the next dfu_request_getstatus */
201             g_usbd_dfu.firmwar_flag = 1;
202         }
203         /* Unsupported state */
204         else {
205             USB_LOG_ERR("Dfu_request_dnload unsupported state\r\n");
206         }
207     }
208     /* 0 Data DNLOAD request */
209     else {
210         /* End of DNLOAD operation*/
211         if ((g_usbd_dfu.dev_state == DFU_STATE_DFU_DNLOAD_IDLE) || (g_usbd_dfu.dev_state == DFU_STATE_DFU_IDLE)) {
212             g_usbd_dfu.manif_state = DFU_MANIFEST_IN_PROGRESS;
213             g_usbd_dfu.dev_state = DFU_STATE_DFU_MANIFEST_SYNC;
214             g_usbd_dfu.dev_status[1] = 0U;
215             g_usbd_dfu.dev_status[2] = 0U;
216             g_usbd_dfu.dev_status[3] = 0U;
217             g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
218         } else {
219             /* Call the error management function (command will be NAKed */
220             USB_LOG_ERR("Dfu_request_dnload End of DNLOAD operation but dev_state %02x \r\n", g_usbd_dfu.dev_state);
221         }
222     }
223 }
224 
dfu_getstatus_special_handler(void)225 static int8_t dfu_getstatus_special_handler(void)
226 {
227     uint32_t addr;
228     if (g_usbd_dfu.dev_state == DFU_STATE_DFU_DNLOAD_BUSY) {
229         /* Decode the Special Command */
230         if (g_usbd_dfu.wblock_num == 0U) {
231             if (g_usbd_dfu.wlength == 1U) {
232                 if (g_usbd_dfu.buffer.d8[0] == DFU_CMD_GETCOMMANDS) {
233                     /* Nothing to do */
234                 }
235             } else if (g_usbd_dfu.wlength == 5U) {
236                 if (g_usbd_dfu.buffer.d8[0] == DFU_CMD_SETADDRESSPOINTER) {
237                     g_usbd_dfu.data_ptr = g_usbd_dfu.buffer.d8[1];
238                     g_usbd_dfu.data_ptr += (uint32_t)g_usbd_dfu.buffer.d8[2] << 8;
239                     g_usbd_dfu.data_ptr += (uint32_t)g_usbd_dfu.buffer.d8[3] << 16;
240                     g_usbd_dfu.data_ptr += (uint32_t)g_usbd_dfu.buffer.d8[4] << 24;
241                 } else if (g_usbd_dfu.buffer.d8[0] == DFU_CMD_ERASE) {
242                     g_usbd_dfu.data_ptr = g_usbd_dfu.buffer.d8[1];
243                     g_usbd_dfu.data_ptr += (uint32_t)g_usbd_dfu.buffer.d8[2] << 8;
244                     g_usbd_dfu.data_ptr += (uint32_t)g_usbd_dfu.buffer.d8[3] << 16;
245                     g_usbd_dfu.data_ptr += (uint32_t)g_usbd_dfu.buffer.d8[4] << 24;
246 
247                     USB_LOG_DBG("Erase start add %08x \r\n", g_usbd_dfu.data_ptr);
248                     /*!< Erase */
249                     dfu_erase_flash(g_usbd_dfu.data_ptr);
250                 } else {
251                     return -1;
252                 }
253             } else {
254                 /* Reset the global length and block number */
255                 g_usbd_dfu.wlength = 0U;
256                 g_usbd_dfu.wblock_num = 0U;
257                 /* Call the error management function (command will be NAKed) */
258                 USB_LOG_ERR("Reset the global length and block number\r\n");
259             }
260         }
261         /* Regular Download Command */
262         else {
263             if (g_usbd_dfu.wblock_num > 1U) {
264                 /* Decode the required address */
265                 addr = ((g_usbd_dfu.wblock_num - 2U) * USBD_DFU_XFER_SIZE) + g_usbd_dfu.data_ptr;
266 
267                 /* Perform the write operation */
268                 /* Write flash */
269                 USB_LOG_DBG("Write start add %08x length %d\r\n", addr, g_usbd_dfu.wlength);
270                 dfu_write_flash(g_usbd_dfu.buffer.d8, (uint8_t *)addr, g_usbd_dfu.wlength);
271             }
272         }
273 
274         /* Reset the global length and block number */
275         g_usbd_dfu.wlength = 0U;
276         g_usbd_dfu.wblock_num = 0U;
277 
278         /* Update the state machine */
279         g_usbd_dfu.dev_state = DFU_STATE_DFU_DNLOAD_SYNC;
280 
281         g_usbd_dfu.dev_status[1] = 0U;
282         g_usbd_dfu.dev_status[2] = 0U;
283         g_usbd_dfu.dev_status[3] = 0U;
284         g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
285     }
286     return 0;
287 }
288 
dfu_request_getstatus(struct usb_setup_packet * setup,uint8_t ** data,uint32_t * len)289 static void dfu_request_getstatus(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
290 {
291     /*!< Determine whether to leave DFU mode */
292     if (g_usbd_dfu.manif_state == DFU_MANIFEST_IN_PROGRESS &&
293         g_usbd_dfu.dev_state == DFU_STATE_DFU_MANIFEST_SYNC &&
294         g_usbd_dfu.dev_status[1] == 0U &&
295         g_usbd_dfu.dev_status[2] == 0U &&
296         g_usbd_dfu.dev_status[3] == 0U &&
297         g_usbd_dfu.dev_status[4] == g_usbd_dfu.dev_state) {
298         g_usbd_dfu.manif_state = DFU_MANIFEST_COMPLETE;
299 
300         if ((0x0B & DFU_MANIFEST_MASK) != 0U) {
301             g_usbd_dfu.dev_state = DFU_STATE_DFU_MANIFEST_SYNC;
302 
303             g_usbd_dfu.dev_status[1] = 0U;
304             g_usbd_dfu.dev_status[2] = 0U;
305             g_usbd_dfu.dev_status[3] = 0U;
306             g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
307             return;
308         } else {
309             g_usbd_dfu.dev_state = DFU_STATE_DFU_MANIFEST_WAIT_RESET;
310 
311             g_usbd_dfu.dev_status[1] = 0U;
312             g_usbd_dfu.dev_status[2] = 0U;
313             g_usbd_dfu.dev_status[3] = 0U;
314             g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
315             /* Generate system reset to allow jumping to the user code */
316             dfu_leave();
317         }
318     }
319 
320     switch (g_usbd_dfu.dev_state) {
321         case DFU_STATE_DFU_DNLOAD_SYNC:
322             if (g_usbd_dfu.wlength != 0U) {
323                 g_usbd_dfu.dev_state = DFU_STATE_DFU_DNLOAD_BUSY;
324 
325                 g_usbd_dfu.dev_status[1] = 0U;
326                 g_usbd_dfu.dev_status[2] = 0U;
327                 g_usbd_dfu.dev_status[3] = 0U;
328                 g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
329 
330                 if ((g_usbd_dfu.wblock_num == 0U) && (g_usbd_dfu.buffer.d8[0] == DFU_CMD_ERASE)) {
331                     dfu_getstatus(g_usbd_dfu.data_ptr, DFU_MEDIA_ERASE, g_usbd_dfu.dev_status);
332                 } else {
333                     dfu_getstatus(g_usbd_dfu.data_ptr, DFU_MEDIA_PROGRAM, g_usbd_dfu.dev_status);
334                 }
335             } else /* (g_usbd_dfu.wlength==0)*/
336             {
337                 g_usbd_dfu.dev_state = DFU_STATE_DFU_DNLOAD_IDLE;
338 
339                 g_usbd_dfu.dev_status[1] = 0U;
340                 g_usbd_dfu.dev_status[2] = 0U;
341                 g_usbd_dfu.dev_status[3] = 0U;
342                 g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
343             }
344             break;
345 
346         case DFU_STATE_DFU_MANIFEST_SYNC:
347             if (g_usbd_dfu.manif_state == DFU_MANIFEST_IN_PROGRESS) {
348                 g_usbd_dfu.dev_state = DFU_STATE_DFU_MANIFEST;
349 
350                 g_usbd_dfu.dev_status[1] = 1U; /*bwPollTimeout = 1ms*/
351                 g_usbd_dfu.dev_status[2] = 0U;
352                 g_usbd_dfu.dev_status[3] = 0U;
353                 g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
354             } else {
355                 if ((g_usbd_dfu.manif_state == DFU_MANIFEST_COMPLETE) &&
356                     ((0x0B & DFU_MANIFEST_MASK) != 0U)) {
357                     g_usbd_dfu.dev_state = DFU_STATE_DFU_IDLE;
358 
359                     g_usbd_dfu.dev_status[1] = 0U;
360                     g_usbd_dfu.dev_status[2] = 0U;
361                     g_usbd_dfu.dev_status[3] = 0U;
362                     g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
363                 }
364             }
365             break;
366 
367         default:
368             break;
369     }
370 
371     /* Send the status data over EP0 */
372     memcpy(*data, g_usbd_dfu.dev_status, 6);
373     *len = 6;
374 
375     if (g_usbd_dfu.firmwar_flag == 1) {
376         if (dfu_getstatus_special_handler() != 0) {
377             USB_LOG_ERR("dfu_getstatus_special_handler error \r\n");
378         }
379         g_usbd_dfu.firmwar_flag = 0;
380     }
381 }
382 
dfu_request_clrstatus(void)383 static void dfu_request_clrstatus(void)
384 {
385     if (g_usbd_dfu.dev_state == DFU_STATE_DFU_ERROR) {
386         g_usbd_dfu.dev_state = DFU_STATE_DFU_IDLE;
387         g_usbd_dfu.dev_status[0] = DFU_STATUS_OK; /* bStatus */
388         g_usbd_dfu.dev_status[1] = 0U;
389         g_usbd_dfu.dev_status[2] = 0U;
390         g_usbd_dfu.dev_status[3] = 0U;                     /* bwPollTimeout=0ms */
391         g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state; /* bState */
392         g_usbd_dfu.dev_status[5] = 0U;                     /* iString */
393     } else {
394         /* State Error */
395         g_usbd_dfu.dev_state = DFU_STATE_DFU_ERROR;
396         g_usbd_dfu.dev_status[0] = DFU_STATUS_ERR_UNKNOWN; /* bStatus */
397         g_usbd_dfu.dev_status[1] = 0U;
398         g_usbd_dfu.dev_status[2] = 0U;
399         g_usbd_dfu.dev_status[3] = 0U;                     /* bwPollTimeout=0ms */
400         g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state; /* bState */
401         g_usbd_dfu.dev_status[5] = 0U;                     /* iString */
402     }
403 }
404 
dfu_request_getstate(struct usb_setup_packet * setup,uint8_t ** data,uint32_t * len)405 static void dfu_request_getstate(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
406 {
407     /* Return the current state of the DFU interface */
408     (*data)[0] = g_usbd_dfu.dev_state;
409     *len = 1;
410 }
411 
dfu_request_abort(void)412 void dfu_request_abort(void)
413 {
414     if ((g_usbd_dfu.dev_state == DFU_STATE_DFU_IDLE) ||
415         (g_usbd_dfu.dev_state == DFU_STATE_DFU_DNLOAD_SYNC) ||
416         (g_usbd_dfu.dev_state == DFU_STATE_DFU_DNLOAD_IDLE) ||
417         (g_usbd_dfu.dev_state == DFU_STATE_DFU_MANIFEST_SYNC) ||
418         (g_usbd_dfu.dev_state == DFU_STATE_DFU_UPLOAD_IDLE)) {
419         g_usbd_dfu.dev_state = DFU_STATE_DFU_IDLE;
420         g_usbd_dfu.dev_status[0] = DFU_STATUS_OK;
421         g_usbd_dfu.dev_status[1] = 0U;
422         g_usbd_dfu.dev_status[2] = 0U;
423         g_usbd_dfu.dev_status[3] = 0U; /* bwPollTimeout=0ms */
424         g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
425         g_usbd_dfu.dev_status[5] = 0U; /* iString */
426         g_usbd_dfu.wblock_num = 0U;
427         g_usbd_dfu.wlength = 0U;
428     }
429 }
430 
dfu_class_interface_request_handler(uint8_t busid,struct usb_setup_packet * setup,uint8_t ** data,uint32_t * len)431 static int dfu_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
432 {
433     USB_LOG_DBG("DFU Class request: "
434                 "bRequest 0x%02x\r\n",
435                 setup->bRequest);
436 
437     switch (setup->bRequest) {
438         case DFU_REQUEST_DETACH:
439             dfu_request_detach();
440             break;
441         case DFU_REQUEST_DNLOAD:
442             dfu_request_dnload(setup, data, len);
443             break;
444         case DFU_REQUEST_UPLOAD:
445             dfu_request_upload(setup, data, len);
446             break;
447         case DFU_REQUEST_GETSTATUS:
448             dfu_request_getstatus(setup, data, len);
449             break;
450         case DFU_REQUEST_CLRSTATUS:
451             dfu_request_clrstatus();
452             break;
453         case DFU_REQUEST_GETSTATE:
454             dfu_request_getstate(setup, data, len);
455             break;
456         case DFU_REQUEST_ABORT:
457             dfu_request_abort();
458             break;
459         default:
460             USB_LOG_WRN("Unhandled DFU Class bRequest 0x%02x\r\n", setup->bRequest);
461             return -1;
462     }
463 
464     return 0;
465 }
466 
dfu_notify_handler(uint8_t busid,uint8_t event,void * arg)467 static void dfu_notify_handler(uint8_t busid, uint8_t event, void *arg)
468 {
469     switch (event) {
470         case USBD_EVENT_RESET:
471             dfu_reset();
472             break;
473         default:
474             break;
475     }
476 }
477 
usbd_dfu_init_intf(struct usbd_interface * intf)478 struct usbd_interface *usbd_dfu_init_intf(struct usbd_interface *intf)
479 {
480     intf->class_interface_handler = dfu_class_interface_request_handler;
481     intf->class_endpoint_handler = NULL;
482     intf->vendor_handler = NULL;
483     intf->notify_handler = dfu_notify_handler;
484 
485     return intf;
486 }
487 
dfu_read_flash(uint8_t * src,uint8_t * dest,uint32_t len)488 __WEAK uint8_t *dfu_read_flash(uint8_t *src, uint8_t *dest, uint32_t len)
489 {
490     return dest;
491 }
492 
dfu_write_flash(uint8_t * src,uint8_t * dest,uint32_t len)493 __WEAK uint16_t dfu_write_flash(uint8_t *src, uint8_t *dest, uint32_t len)
494 {
495     return 0;
496 }
497 
dfu_erase_flash(uint32_t add)498 __WEAK uint16_t dfu_erase_flash(uint32_t add)
499 {
500     return 0;
501 }
502 
dfu_leave(void)503 __WEAK void dfu_leave(void)
504 {
505 }
506