xref: /openbmc/u-boot/common/dfu.c (revision 13bdce8f8cadf07bc81d7000a04e48f3028de543)
1  /*
2   * dfu.c -- dfu command
3   *
4   * Copyright (C) 2015
5   * Lukasz Majewski <l.majewski@majess.pl>
6   *
7   * Copyright (C) 2012 Samsung Electronics
8   * authors: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
9   *	    Lukasz Majewski <l.majewski@samsung.com>
10   *
11   * SPDX-License-Identifier:	GPL-2.0+
12   */
13  
14  #include <common.h>
15  #include <watchdog.h>
16  #include <dfu.h>
17  #include <console.h>
18  #include <g_dnl.h>
19  #include <usb.h>
20  #include <net.h>
21  
22  int run_usb_dnl_gadget(int usbctrl_index, char *usb_dnl_gadget)
23  {
24  	bool dfu_reset = false;
25  	int ret, i = 0;
26  
27  	ret = board_usb_init(usbctrl_index, USB_INIT_DEVICE);
28  	if (ret) {
29  		error("board usb init failed\n");
30  		return CMD_RET_FAILURE;
31  	}
32  	g_dnl_clear_detach();
33  	ret = g_dnl_register(usb_dnl_gadget);
34  	if (ret) {
35  		error("g_dnl_register failed");
36  		return CMD_RET_FAILURE;
37  	}
38  
39  	while (1) {
40  		if (g_dnl_detach()) {
41  			/*
42  			 * Check if USB bus reset is performed after detach,
43  			 * which indicates that -R switch has been passed to
44  			 * dfu-util. In this case reboot the device
45  			 */
46  			if (dfu_usb_get_reset()) {
47  				dfu_reset = true;
48  				goto exit;
49  			}
50  
51  			/*
52  			 * This extra number of usb_gadget_handle_interrupts()
53  			 * calls is necessary to assure correct transmission
54  			 * completion with dfu-util
55  			 */
56  			if (++i == 10000)
57  				goto exit;
58  		}
59  
60  		if (ctrlc())
61  			goto exit;
62  
63  		if (dfu_get_defer_flush()) {
64  			/*
65  			 * Call to usb_gadget_handle_interrupts() is necessary
66  			 * to act on ZLP OUT transaction from HOST PC after
67  			 * transmitting the whole file.
68  			 *
69  			 * If this ZLP OUT packet is NAK'ed, the HOST libusb
70  			 * function fails after timeout (by default it is set to
71  			 * 5 seconds). In such situation the dfu-util program
72  			 * exits with error message.
73  			 */
74  			usb_gadget_handle_interrupts(usbctrl_index);
75  			ret = dfu_flush(dfu_get_defer_flush(), NULL, 0, 0);
76  			dfu_set_defer_flush(NULL);
77  			if (ret) {
78  				error("Deferred dfu_flush() failed!");
79  				goto exit;
80  			}
81  		}
82  
83  		WATCHDOG_RESET();
84  		usb_gadget_handle_interrupts(usbctrl_index);
85  	}
86  exit:
87  	g_dnl_unregister();
88  	board_usb_cleanup(usbctrl_index, USB_INIT_DEVICE);
89  
90  	if (dfu_reset)
91  		do_reset(NULL, 0, 0, NULL);
92  
93  	g_dnl_clear_detach();
94  
95  	return ret;
96  }
97