blob: cd60f9a1e275a237d5eb716cc75408254380cd76 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
B, Ravi05341a82016-07-28 17:39:15 +05302/*
3 * dfu.c -- dfu command
4 *
5 * Copyright (C) 2015
6 * Lukasz Majewski <l.majewski@majess.pl>
7 *
8 * Copyright (C) 2012 Samsung Electronics
9 * authors: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
10 * Lukasz Majewski <l.majewski@samsung.com>
B, Ravi05341a82016-07-28 17:39:15 +053011 */
12
13#include <common.h>
Simon Glass09140112020-05-10 11:40:03 -060014#include <command.h>
B, Ravi05341a82016-07-28 17:39:15 +053015#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
22int run_usb_dnl_gadget(int usbctrl_index, char *usb_dnl_gadget)
23{
24 bool dfu_reset = false;
25 int ret, i = 0;
26
Jean-Jacques Hiblota06955a2018-11-29 10:52:41 +010027 ret = usb_gadget_initialize(usbctrl_index);
Michal Simekdbdc2742016-08-30 15:32:17 +020028 if (ret) {
Jean-Jacques Hiblota06955a2018-11-29 10:52:41 +010029 pr_err("usb_gadget_initialize failed\n");
Michal Simekdbdc2742016-08-30 15:32:17 +020030 return CMD_RET_FAILURE;
31 }
B, Ravi05341a82016-07-28 17:39:15 +053032 g_dnl_clear_detach();
Sanchayan Maity54a708c2016-08-08 16:56:17 +053033 ret = g_dnl_register(usb_dnl_gadget);
34 if (ret) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +090035 pr_err("g_dnl_register failed");
Sanchayan Maity54a708c2016-08-08 16:56:17 +053036 return CMD_RET_FAILURE;
37 }
38
Andy Shevchenko98a8f442019-11-27 18:12:15 +020039#ifdef CONFIG_DFU_TIMEOUT
40 unsigned long start_time = get_timer(0);
41#endif
42
B, Ravi05341a82016-07-28 17:39:15 +053043 while (1) {
44 if (g_dnl_detach()) {
45 /*
46 * Check if USB bus reset is performed after detach,
47 * which indicates that -R switch has been passed to
48 * dfu-util. In this case reboot the device
49 */
50 if (dfu_usb_get_reset()) {
51 dfu_reset = true;
52 goto exit;
53 }
54
55 /*
56 * This extra number of usb_gadget_handle_interrupts()
57 * calls is necessary to assure correct transmission
58 * completion with dfu-util
59 */
60 if (++i == 10000)
61 goto exit;
62 }
63
64 if (ctrlc())
65 goto exit;
66
67 if (dfu_get_defer_flush()) {
68 /*
69 * Call to usb_gadget_handle_interrupts() is necessary
70 * to act on ZLP OUT transaction from HOST PC after
71 * transmitting the whole file.
72 *
73 * If this ZLP OUT packet is NAK'ed, the HOST libusb
74 * function fails after timeout (by default it is set to
75 * 5 seconds). In such situation the dfu-util program
76 * exits with error message.
77 */
78 usb_gadget_handle_interrupts(usbctrl_index);
79 ret = dfu_flush(dfu_get_defer_flush(), NULL, 0, 0);
80 dfu_set_defer_flush(NULL);
81 if (ret) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +090082 pr_err("Deferred dfu_flush() failed!");
B, Ravi05341a82016-07-28 17:39:15 +053083 goto exit;
84 }
85 }
86
Andy Shevchenko98a8f442019-11-27 18:12:15 +020087#ifdef CONFIG_DFU_TIMEOUT
88 unsigned long wait_time = dfu_get_timeout();
89
90 if (wait_time) {
91 unsigned long current_time = get_timer(start_time);
92
93 if (current_time > wait_time) {
94 debug("Inactivity timeout, abort DFU\n");
95 goto exit;
96 }
97 }
98#endif
99
B, Ravi05341a82016-07-28 17:39:15 +0530100 WATCHDOG_RESET();
101 usb_gadget_handle_interrupts(usbctrl_index);
102 }
103exit:
104 g_dnl_unregister();
Jean-Jacques Hiblota06955a2018-11-29 10:52:41 +0100105 usb_gadget_release(usbctrl_index);
B, Ravi05341a82016-07-28 17:39:15 +0530106
107 if (dfu_reset)
B, Ravi66928af2017-05-04 15:45:29 +0530108 do_reset(NULL, 0, 0, NULL);
B, Ravi05341a82016-07-28 17:39:15 +0530109
110 g_dnl_clear_detach();
111
112 return ret;
113}