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 #include <android_avb/rk_avb_ops_user.h> 22 23 int run_usb_dnl_gadget(int usbctrl_index, char *usb_dnl_gadget) 24 { 25 bool dfu_reset = false; 26 int ret, i = 0; 27 #ifdef CONFIG_ANDROID_AB 28 char select_slot[3] = {0}; 29 unsigned int slot_number[2] = {0, 1}; 30 #endif 31 32 ret = usb_gadget_initialize(usbctrl_index); 33 if (ret) { 34 pr_err("usb_gadget_initialize failed\n"); 35 return CMD_RET_FAILURE; 36 } 37 g_dnl_clear_detach(); 38 ret = g_dnl_register(usb_dnl_gadget); 39 if (ret) { 40 pr_err("g_dnl_register failed"); 41 return CMD_RET_FAILURE; 42 } 43 44 while (1) { 45 if (g_dnl_detach()) { 46 /* 47 * Check if USB bus reset is performed after detach, 48 * which indicates that -R switch has been passed to 49 * dfu-util. In this case reboot the device 50 */ 51 if (dfu_usb_get_reset()) { 52 dfu_reset = true; 53 #ifdef CONFIG_ANDROID_AB 54 if (rk_avb_get_current_slot(select_slot)) 55 printf("Obtain current slot failed!\n"); 56 /* 57 * After the firmware is successfully upgrade, 58 * the device changes the slot priority during 59 * reboot based on the current slot 60 */ 61 if (strcmp(select_slot, "_a") == 0) 62 rk_avb_set_slot_active(&slot_number[1]); 63 else 64 rk_avb_set_slot_active(&slot_number[0]); 65 #endif 66 goto exit; 67 } 68 69 /* 70 * This extra number of usb_gadget_handle_interrupts() 71 * calls is necessary to assure correct transmission 72 * completion with dfu-util 73 */ 74 if (++i == 10000) 75 goto exit; 76 } 77 78 if (ctrlc()) 79 goto exit; 80 81 if (dfu_get_defer_flush()) { 82 /* 83 * Call to usb_gadget_handle_interrupts() is necessary 84 * to act on ZLP OUT transaction from HOST PC after 85 * transmitting the whole file. 86 * 87 * If this ZLP OUT packet is NAK'ed, the HOST libusb 88 * function fails after timeout (by default it is set to 89 * 5 seconds). In such situation the dfu-util program 90 * exits with error message. 91 */ 92 usb_gadget_handle_interrupts(usbctrl_index); 93 ret = dfu_flush(dfu_get_defer_flush(), NULL, 0, 0); 94 dfu_set_defer_flush(NULL); 95 if (ret) { 96 pr_err("Deferred dfu_flush() failed!"); 97 goto exit; 98 } 99 } 100 101 WATCHDOG_RESET(); 102 usb_gadget_handle_interrupts(usbctrl_index); 103 } 104 exit: 105 g_dnl_unregister(); 106 usb_gadget_release(usbctrl_index); 107 108 if (dfu_reset) 109 do_reset(NULL, 0, 0, NULL); 110 111 g_dnl_clear_detach(); 112 113 return ret; 114 } 115