"Das U-Boot" Source Tree
at master 120 lines 2.6 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 2/* 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> 11 */ 12 13#include <command.h> 14#include <log.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#include <linux/printk.h> 22 23int run_usb_dnl_gadget(int usbctrl_index, char *usb_dnl_gadget) 24{ 25 bool dfu_reset = false; 26 struct udevice *udc; 27 int ret, i = 0; 28 29 ret = udc_device_get_by_index(usbctrl_index, &udc); 30 if (ret) { 31 pr_err("udc_device_get_by_index failed\n"); 32 return CMD_RET_FAILURE; 33 } 34 g_dnl_clear_detach(); 35 ret = g_dnl_register(usb_dnl_gadget); 36 if (ret) { 37 pr_err("g_dnl_register failed"); 38 ret = CMD_RET_FAILURE; 39 goto err_detach; 40 } 41 42#ifdef CONFIG_DFU_TIMEOUT 43 unsigned long start_time = get_timer(0); 44#endif 45 46 while (1) { 47 if (g_dnl_detach()) { 48 /* 49 * Check if USB bus reset is performed after detach, 50 * which indicates that -R switch has been passed to 51 * dfu-util. In this case reboot the device 52 */ 53 if (dfu_usb_get_reset()) { 54 dfu_reset = true; 55 goto exit; 56 } 57 58 /* 59 * This extra number of dm_usb_gadget_handle_interrupts() 60 * calls is necessary to assure correct transmission 61 * completion with dfu-util 62 */ 63 if (++i == 10000) 64 goto exit; 65 } 66 67 if (ctrlc()) 68 goto exit; 69 70 if (dfu_get_defer_flush()) { 71 /* 72 * Call to dm_usb_gadget_handle_interrupts() is necessary 73 * to act on ZLP OUT transaction from HOST PC after 74 * transmitting the whole file. 75 * 76 * If this ZLP OUT packet is NAK'ed, the HOST libusb 77 * function fails after timeout (by default it is set to 78 * 5 seconds). In such situation the dfu-util program 79 * exits with error message. 80 */ 81 dm_usb_gadget_handle_interrupts(udc); 82 ret = dfu_flush(dfu_get_defer_flush(), NULL, 0, 0); 83 dfu_set_defer_flush(NULL); 84 if (ret) { 85 pr_err("Deferred dfu_flush() failed!"); 86 goto exit; 87 } 88 } 89 90#ifdef CONFIG_DFU_TIMEOUT 91 unsigned long wait_time = dfu_get_timeout(); 92 93 if (wait_time) { 94 unsigned long current_time = get_timer(start_time); 95 96 if (current_time > wait_time) { 97 debug("Inactivity timeout, abort DFU\n"); 98 goto exit; 99 } 100 } 101#endif 102 103 if (dfu_reinit_needed) 104 goto exit; 105 106 schedule(); 107 dm_usb_gadget_handle_interrupts(udc); 108 } 109exit: 110 g_dnl_unregister(); 111err_detach: 112 udc_device_put(udc); 113 114 if (dfu_reset) 115 do_reset(NULL, 0, 0, NULL); 116 117 g_dnl_clear_detach(); 118 119 return ret; 120}