u-boot/common/dfu.c
Andy Shevchenko 98a8f445fd dfu: Add optional timeout parameter
When the `dfu` command is called from the U-Boot environment,
it now accepts an optional parameter that specifies a timeout (in seconds).
If a DFU connection is not made within that time the `dfu` command exits
(as it would if Ctrl+C was pressed). If the timeout is left empty or being
zero the `dfu` command behaves as it does now.

This is useful for allowing U-Boot to check to see if anything wants to
upload new firmware before continuing to boot.

The patch is based on the commit
5e966ccc3c
by Sebastien Colleur, which has been heavily reworked due to U-Boot changes
in the past.

Signed-off-by: Brad Campbell <bradjc5@gmail.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
2020-01-07 14:37:50 +01:00

112 lines
2.4 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* dfu.c -- dfu command
*
* Copyright (C) 2015
* Lukasz Majewski <l.majewski@majess.pl>
*
* Copyright (C) 2012 Samsung Electronics
* authors: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
* Lukasz Majewski <l.majewski@samsung.com>
*/
#include <common.h>
#include <watchdog.h>
#include <dfu.h>
#include <console.h>
#include <g_dnl.h>
#include <usb.h>
#include <net.h>
int run_usb_dnl_gadget(int usbctrl_index, char *usb_dnl_gadget)
{
bool dfu_reset = false;
int ret, i = 0;
ret = usb_gadget_initialize(usbctrl_index);
if (ret) {
pr_err("usb_gadget_initialize failed\n");
return CMD_RET_FAILURE;
}
g_dnl_clear_detach();
ret = g_dnl_register(usb_dnl_gadget);
if (ret) {
pr_err("g_dnl_register failed");
return CMD_RET_FAILURE;
}
#ifdef CONFIG_DFU_TIMEOUT
unsigned long start_time = get_timer(0);
#endif
while (1) {
if (g_dnl_detach()) {
/*
* Check if USB bus reset is performed after detach,
* which indicates that -R switch has been passed to
* dfu-util. In this case reboot the device
*/
if (dfu_usb_get_reset()) {
dfu_reset = true;
goto exit;
}
/*
* This extra number of usb_gadget_handle_interrupts()
* calls is necessary to assure correct transmission
* completion with dfu-util
*/
if (++i == 10000)
goto exit;
}
if (ctrlc())
goto exit;
if (dfu_get_defer_flush()) {
/*
* Call to usb_gadget_handle_interrupts() is necessary
* to act on ZLP OUT transaction from HOST PC after
* transmitting the whole file.
*
* If this ZLP OUT packet is NAK'ed, the HOST libusb
* function fails after timeout (by default it is set to
* 5 seconds). In such situation the dfu-util program
* exits with error message.
*/
usb_gadget_handle_interrupts(usbctrl_index);
ret = dfu_flush(dfu_get_defer_flush(), NULL, 0, 0);
dfu_set_defer_flush(NULL);
if (ret) {
pr_err("Deferred dfu_flush() failed!");
goto exit;
}
}
#ifdef CONFIG_DFU_TIMEOUT
unsigned long wait_time = dfu_get_timeout();
if (wait_time) {
unsigned long current_time = get_timer(start_time);
if (current_time > wait_time) {
debug("Inactivity timeout, abort DFU\n");
goto exit;
}
}
#endif
WATCHDOG_RESET();
usb_gadget_handle_interrupts(usbctrl_index);
}
exit:
g_dnl_unregister();
usb_gadget_release(usbctrl_index);
if (dfu_reset)
do_reset(NULL, 0, 0, NULL);
g_dnl_clear_detach();
return ret;
}