1 /*
2  * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <errno.h>
8 #include <string.h>
9 
10 #include <common/debug.h>
11 
12 #include <platform_def.h>
13 #include <usb_dfu.h>
14 
15 /* Device states as defined in DFU spec */
16 #define STATE_APP_IDLE			0
17 #define STATE_APP_DETACH		1
18 #define STATE_DFU_IDLE			2
19 #define STATE_DFU_DNLOAD_SYNC		3
20 #define STATE_DFU_DNLOAD_BUSY		4
21 #define STATE_DFU_DNLOAD_IDLE		5
22 #define STATE_DFU_MANIFEST_SYNC		6
23 #define STATE_DFU_MANIFEST		7
24 #define STATE_DFU_MANIFEST_WAIT_RESET	8
25 #define STATE_DFU_UPLOAD_IDLE		9
26 #define STATE_DFU_ERROR			10
27 
28 /* DFU errors */
29 #define DFU_ERROR_NONE			0x00
30 #define DFU_ERROR_TARGET		0x01
31 #define DFU_ERROR_FILE			0x02
32 #define DFU_ERROR_WRITE			0x03
33 #define DFU_ERROR_ERASE			0x04
34 #define DFU_ERROR_CHECK_ERASED		0x05
35 #define DFU_ERROR_PROG			0x06
36 #define DFU_ERROR_VERIFY		0x07
37 #define DFU_ERROR_ADDRESS		0x08
38 #define DFU_ERROR_NOTDONE		0x09
39 #define DFU_ERROR_FIRMWARE		0x0A
40 #define DFU_ERROR_VENDOR		0x0B
41 #define DFU_ERROR_USB			0x0C
42 #define DFU_ERROR_POR			0x0D
43 #define DFU_ERROR_UNKNOWN		0x0E
44 #define DFU_ERROR_STALLEDPKT		0x0F
45 
46 /* DFU request */
47 #define DFU_DETACH			0
48 #define DFU_DNLOAD			1
49 #define DFU_UPLOAD			2
50 #define DFU_GETSTATUS			3
51 #define DFU_CLRSTATUS			4
52 #define DFU_GETSTATE			5
53 #define DFU_ABORT			6
54 
55 static bool usb_dfu_detach_req;
56 
57 /*
58  * usb_dfu_init
59  *         Initialize the DFU interface
60  * pdev: device instance
61  * cfgidx: Configuration index
62  * return: status
63  */
usb_dfu_init(struct usb_handle * pdev,uint8_t cfgidx)64 static uint8_t usb_dfu_init(struct usb_handle *pdev, uint8_t cfgidx)
65 {
66 	(void)pdev;
67 	(void)cfgidx;
68 
69 	/* Nothing to do in this stage */
70 	return USBD_OK;
71 }
72 
73 /*
74  * usb_dfu_de_init
75  *         De-Initialize the DFU layer
76  * pdev: device instance
77  * cfgidx: Configuration index
78  * return: status
79  */
usb_dfu_de_init(struct usb_handle * pdev,uint8_t cfgidx)80 static uint8_t usb_dfu_de_init(struct usb_handle *pdev, uint8_t cfgidx)
81 {
82 	(void)pdev;
83 	(void)cfgidx;
84 
85 	/* Nothing to do in this stage */
86 	return USBD_OK;
87 }
88 
89 /*
90  * usb_dfu_data_in
91  *         handle data IN Stage
92  * pdev: device instance
93  * epnum: endpoint index
94  * return: status
95  */
usb_dfu_data_in(struct usb_handle * pdev,uint8_t epnum)96 static uint8_t usb_dfu_data_in(struct usb_handle *pdev, uint8_t epnum)
97 {
98 	(void)pdev;
99 	(void)epnum;
100 
101 	return USBD_OK;
102 }
103 
104 /*
105  * usb_dfu_ep0_rx_ready
106  *         handle EP0 Rx Ready event
107  * pdev: device
108  * return: status
109  */
usb_dfu_ep0_rx_ready(struct usb_handle * pdev)110 static uint8_t usb_dfu_ep0_rx_ready(struct usb_handle *pdev)
111 {
112 	(void)pdev;
113 
114 	return USBD_OK;
115 }
116 
117 /*
118  * usb_dfu_ep0_tx_ready
119  *         handle EP0 TRx Ready event
120  * pdev: device instance
121  * return: status
122  */
usb_dfu_ep0_tx_ready(struct usb_handle * pdev)123 static uint8_t usb_dfu_ep0_tx_ready(struct usb_handle *pdev)
124 {
125 	(void)pdev;
126 
127 	return USBD_OK;
128 }
129 
130 /*
131  * usb_dfu_sof
132  *         handle SOF event
133  * pdev: device instance
134  * return: status
135  */
usb_dfu_sof(struct usb_handle * pdev)136 static uint8_t usb_dfu_sof(struct usb_handle *pdev)
137 {
138 	(void)pdev;
139 
140 	return USBD_OK;
141 }
142 
143 /*
144  * usb_dfu_iso_in_incomplete
145  *         handle data ISO IN Incomplete event
146  * pdev: device instance
147  * epnum: endpoint index
148  * return: status
149  */
usb_dfu_iso_in_incomplete(struct usb_handle * pdev,uint8_t epnum)150 static uint8_t usb_dfu_iso_in_incomplete(struct usb_handle *pdev, uint8_t epnum)
151 {
152 	(void)pdev;
153 	(void)epnum;
154 
155 	return USBD_OK;
156 }
157 
158 /*
159  * usb_dfu_iso_out_incomplete
160  *         handle data ISO OUT Incomplete event
161  * pdev: device instance
162  * epnum: endpoint index
163  * return: status
164  */
usb_dfu_iso_out_incomplete(struct usb_handle * pdev,uint8_t epnum)165 static uint8_t usb_dfu_iso_out_incomplete(struct usb_handle *pdev,
166 					  uint8_t epnum)
167 {
168 	(void)pdev;
169 	(void)epnum;
170 
171 	return USBD_OK;
172 }
173 
174 /*
175  * usb_dfu_data_out
176  *         handle data OUT Stage
177  * pdev: device instance
178  * epnum: endpoint index
179  * return: status
180  */
usb_dfu_data_out(struct usb_handle * pdev,uint8_t epnum)181 static uint8_t usb_dfu_data_out(struct usb_handle *pdev, uint8_t epnum)
182 {
183 	(void)pdev;
184 	(void)epnum;
185 
186 	return USBD_OK;
187 }
188 
189 /*
190  * usb_dfu_detach
191  *         Handles the DFU DETACH request.
192  * pdev: device instance
193  * req: pointer to the request structure.
194  */
usb_dfu_detach(struct usb_handle * pdev,struct usb_setup_req * req)195 static void usb_dfu_detach(struct usb_handle *pdev, struct usb_setup_req *req)
196 {
197 	struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
198 
199 	INFO("Receive DFU Detach\n");
200 
201 	if ((hdfu->dev_state == STATE_DFU_IDLE) ||
202 	    (hdfu->dev_state == STATE_DFU_DNLOAD_SYNC) ||
203 	    (hdfu->dev_state == STATE_DFU_DNLOAD_IDLE) ||
204 	    (hdfu->dev_state == STATE_DFU_MANIFEST_SYNC) ||
205 	    (hdfu->dev_state == STATE_DFU_UPLOAD_IDLE)) {
206 		/* Update the state machine */
207 		hdfu->dev_state = STATE_DFU_IDLE;
208 		hdfu->dev_status = DFU_ERROR_NONE;
209 	}
210 
211 	usb_dfu_detach_req = true;
212 }
213 
214 /*
215  * usb_dfu_download
216  *         Handles the DFU DNLOAD request.
217  * pdev: device instance
218  * req: pointer to the request structure
219  */
usb_dfu_download(struct usb_handle * pdev,struct usb_setup_req * req)220 static void usb_dfu_download(struct usb_handle *pdev, struct usb_setup_req *req)
221 {
222 	struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
223 	uintptr_t data_ptr;
224 	uint32_t length;
225 	int ret;
226 
227 	/* Data setup request */
228 	if (req->length > 0) {
229 		/* Unsupported state */
230 		if ((hdfu->dev_state != STATE_DFU_IDLE) &&
231 		    (hdfu->dev_state != STATE_DFU_DNLOAD_IDLE)) {
232 			/* Call the error management function (command will be nacked) */
233 			usb_core_ctl_error(pdev);
234 			return;
235 		}
236 
237 		/* Get the data address */
238 		length = req->length;
239 		ret = hdfu->callback->download(hdfu->alt_setting, &data_ptr,
240 					       &length, pdev->user_data);
241 		if (ret == 0U) {
242 			/* Update the state machine */
243 			hdfu->dev_state = STATE_DFU_DNLOAD_SYNC;
244 			/* Start the transfer */
245 			usb_core_receive_ep0(pdev, (uint8_t *)data_ptr, length);
246 		} else {
247 			usb_core_ctl_error(pdev);
248 		}
249 	} else {
250 		/* End of DNLOAD operation*/
251 		if (hdfu->dev_state != STATE_DFU_DNLOAD_IDLE) {
252 			/* Call the error management function (command will be nacked) */
253 			usb_core_ctl_error(pdev);
254 			return;
255 		}
256 		/* End of DNLOAD operation*/
257 		hdfu->dev_state = STATE_DFU_MANIFEST_SYNC;
258 		ret = hdfu->callback->manifestation(hdfu->alt_setting, pdev->user_data);
259 		if (ret == 0U) {
260 			hdfu->dev_state = STATE_DFU_MANIFEST_SYNC;
261 		} else {
262 			usb_core_ctl_error(pdev);
263 		}
264 	}
265 }
266 
267 /*
268  * usb_dfu_upload
269  *         Handles the DFU UPLOAD request.
270  * pdev: instance
271  * req: pointer to the request structure
272  */
usb_dfu_upload(struct usb_handle * pdev,struct usb_setup_req * req)273 static void usb_dfu_upload(struct usb_handle *pdev, struct usb_setup_req *req)
274 {
275 	struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
276 	uintptr_t data_ptr;
277 	uint32_t length;
278 	int ret;
279 
280 	/* Data setup request */
281 	if (req->length == 0) {
282 		/* No Data setup request */
283 		hdfu->dev_state = STATE_DFU_IDLE;
284 		return;
285 	}
286 
287 	/* Unsupported state */
288 	if ((hdfu->dev_state != STATE_DFU_IDLE) && (hdfu->dev_state != STATE_DFU_UPLOAD_IDLE)) {
289 		ERROR("UPLOAD : Unsupported State\n");
290 		/* Call the error management function (command will be nacked) */
291 		usb_core_ctl_error(pdev);
292 		return;
293 	}
294 
295 	/* Update the data address */
296 	length = req->length;
297 	ret = hdfu->callback->upload(hdfu->alt_setting, &data_ptr, &length, pdev->user_data);
298 	if (ret == 0U) {
299 		/* Short frame */
300 		hdfu->dev_state = (req->length > length) ? STATE_DFU_IDLE : STATE_DFU_UPLOAD_IDLE;
301 
302 		/* Start the transfer */
303 		usb_core_transmit_ep0(pdev, (uint8_t *)data_ptr, length);
304 	} else {
305 		ERROR("UPLOAD : bad block %i on alt %i\n", req->value, req->index);
306 		hdfu->dev_state = STATE_DFU_ERROR;
307 		hdfu->dev_status = DFU_ERROR_STALLEDPKT;
308 
309 		/* Call the error management function (command will be nacked) */
310 		usb_core_ctl_error(pdev);
311 	}
312 }
313 
314 /*
315  * usb_dfu_get_status
316  *         Handles the DFU GETSTATUS request.
317  * pdev: instance
318  */
usb_dfu_get_status(struct usb_handle * pdev)319 static void usb_dfu_get_status(struct usb_handle *pdev)
320 {
321 	struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
322 
323 	hdfu->status[0] = hdfu->dev_status;	/* bStatus */
324 	hdfu->status[1] = 0;			/* bwPollTimeout[3] */
325 	hdfu->status[2] = 0;
326 	hdfu->status[3] = 0;
327 	hdfu->status[4] = hdfu->dev_state;	/* bState */
328 	hdfu->status[5] = 0;			/* iString */
329 
330 	/* next step */
331 	switch (hdfu->dev_state) {
332 	case STATE_DFU_DNLOAD_SYNC:
333 		hdfu->dev_state = STATE_DFU_DNLOAD_IDLE;
334 		break;
335 	case STATE_DFU_MANIFEST_SYNC:
336 		/* the device is 'ManifestationTolerant' */
337 		hdfu->status[4] = STATE_DFU_MANIFEST;
338 		hdfu->status[1] = 1U; /* bwPollTimeout = 1ms */
339 		hdfu->dev_state = STATE_DFU_IDLE;
340 		break;
341 
342 	default:
343 		break;
344 	}
345 
346 	/* Start the transfer */
347 	usb_core_transmit_ep0(pdev, (uint8_t *)&hdfu->status[0], sizeof(hdfu->status));
348 }
349 
350 /*
351  * usb_dfu_clear_status
352  *         Handles the DFU CLRSTATUS request.
353  * pdev: device instance
354  */
usb_dfu_clear_status(struct usb_handle * pdev)355 static void usb_dfu_clear_status(struct usb_handle *pdev)
356 {
357 	struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
358 
359 	if (hdfu->dev_state == STATE_DFU_ERROR) {
360 		hdfu->dev_state = STATE_DFU_IDLE;
361 		hdfu->dev_status = DFU_ERROR_NONE;
362 	} else {
363 		/* State Error */
364 		hdfu->dev_state = STATE_DFU_ERROR;
365 		hdfu->dev_status = DFU_ERROR_UNKNOWN;
366 	}
367 }
368 
369 /*
370  * usb_dfu_get_state
371  *         Handles the DFU GETSTATE request.
372  * pdev: device instance
373  */
usb_dfu_get_state(struct usb_handle * pdev)374 static void usb_dfu_get_state(struct usb_handle *pdev)
375 {
376 	struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
377 
378 	/* Return the current state of the DFU interface */
379 	usb_core_transmit_ep0(pdev, &hdfu->dev_state, 1);
380 }
381 
382 /*
383  * usb_dfu_abort
384  *         Handles the DFU ABORT request.
385  * pdev: device instance
386  */
usb_dfu_abort(struct usb_handle * pdev)387 static void usb_dfu_abort(struct usb_handle *pdev)
388 {
389 	struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
390 
391 	if ((hdfu->dev_state == STATE_DFU_IDLE) ||
392 	    (hdfu->dev_state == STATE_DFU_DNLOAD_SYNC) ||
393 	    (hdfu->dev_state == STATE_DFU_DNLOAD_IDLE) ||
394 	    (hdfu->dev_state == STATE_DFU_MANIFEST_SYNC) ||
395 	    (hdfu->dev_state == STATE_DFU_UPLOAD_IDLE)) {
396 		hdfu->dev_state = STATE_DFU_IDLE;
397 		hdfu->dev_status = DFU_ERROR_NONE;
398 	}
399 }
400 
401 /*
402  * usb_dfu_setup
403  *         Handle the DFU specific requests
404  * pdev: instance
405  * req: usb requests
406  * return: status
407  */
usb_dfu_setup(struct usb_handle * pdev,struct usb_setup_req * req)408 static uint8_t usb_dfu_setup(struct usb_handle *pdev, struct usb_setup_req *req)
409 {
410 	uint8_t *pbuf = NULL;
411 	uint16_t len = 0U;
412 	uint8_t ret = USBD_OK;
413 	struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
414 
415 	switch (req->bm_request & USB_REQ_TYPE_MASK) {
416 	case USB_REQ_TYPE_CLASS:
417 		switch (req->b_request) {
418 		case DFU_DNLOAD:
419 			usb_dfu_download(pdev, req);
420 			break;
421 
422 		case DFU_UPLOAD:
423 			usb_dfu_upload(pdev, req);
424 			break;
425 
426 		case DFU_GETSTATUS:
427 			usb_dfu_get_status(pdev);
428 			break;
429 
430 		case DFU_CLRSTATUS:
431 			usb_dfu_clear_status(pdev);
432 			break;
433 
434 		case DFU_GETSTATE:
435 			usb_dfu_get_state(pdev);
436 			break;
437 
438 		case DFU_ABORT:
439 			usb_dfu_abort(pdev);
440 			break;
441 
442 		case DFU_DETACH:
443 			usb_dfu_detach(pdev, req);
444 			break;
445 
446 		default:
447 			ERROR("unknown request %x on alternate %i\n",
448 			      req->b_request, hdfu->alt_setting);
449 			usb_core_ctl_error(pdev);
450 			ret = USBD_FAIL;
451 			break;
452 		}
453 		break;
454 	case USB_REQ_TYPE_STANDARD:
455 		switch (req->b_request) {
456 		case USB_REQ_GET_DESCRIPTOR:
457 			if (HIBYTE(req->value) == DFU_DESCRIPTOR_TYPE) {
458 				pbuf = pdev->desc->get_config_desc(&len);
459 				/* DFU descriptor at the end of the USB */
460 				pbuf += len - 9U;
461 				len = 9U;
462 				len = MIN(len, req->length);
463 			}
464 
465 			/* Start the transfer */
466 			usb_core_transmit_ep0(pdev, pbuf, len);
467 
468 			break;
469 
470 		case USB_REQ_GET_INTERFACE:
471 			/* Start the transfer */
472 			usb_core_transmit_ep0(pdev, (uint8_t *)&hdfu->alt_setting, 1U);
473 			break;
474 
475 		case USB_REQ_SET_INTERFACE:
476 			hdfu->alt_setting = LOBYTE(req->value);
477 			break;
478 
479 		default:
480 			usb_core_ctl_error(pdev);
481 			ret = USBD_FAIL;
482 			break;
483 		}
484 	default:
485 		break;
486 	}
487 
488 	return ret;
489 }
490 
491 static const struct usb_class usb_dfu = {
492 	.init = usb_dfu_init,
493 	.de_init = usb_dfu_de_init,
494 	.setup = usb_dfu_setup,
495 	.ep0_tx_sent = usb_dfu_ep0_tx_ready,
496 	.ep0_rx_ready = usb_dfu_ep0_rx_ready,
497 	.data_in = usb_dfu_data_in,
498 	.data_out = usb_dfu_data_out,
499 	.sof = usb_dfu_sof,
500 	.iso_in_incomplete = usb_dfu_iso_in_incomplete,
501 	.iso_out_incomplete = usb_dfu_iso_out_incomplete,
502 };
503 
usb_dfu_register(struct usb_handle * pdev,struct usb_dfu_handle * phandle)504 void usb_dfu_register(struct usb_handle *pdev, struct usb_dfu_handle *phandle)
505 {
506 	pdev->class = (struct usb_class *)&usb_dfu;
507 	pdev->class_data = phandle;
508 
509 	phandle->dev_state = STATE_DFU_IDLE;
510 	phandle->dev_status = DFU_ERROR_NONE;
511 }
512 
usb_dfu_loop(struct usb_handle * pdev,const struct usb_dfu_media * pmedia)513 int usb_dfu_loop(struct usb_handle *pdev, const struct usb_dfu_media *pmedia)
514 {
515 	uint32_t it_count;
516 	enum usb_status ret;
517 	struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
518 
519 	hdfu->callback = pmedia;
520 	usb_dfu_detach_req = false;
521 	/* Continue to handle USB core IT to assure complete data transmission */
522 	it_count = 100U;
523 
524 	/* DFU infinite loop until DETACH_REQ */
525 	while (it_count != 0U) {
526 		ret = usb_core_handle_it(pdev);
527 		if (ret != USBD_OK) {
528 			return -EIO;
529 		}
530 
531 		/* Detach request received */
532 		if (usb_dfu_detach_req) {
533 			it_count--;
534 		}
535 	}
536 
537 	return 0;
538 }
539