xref: /OK3568_Linux_fs/u-boot/drivers/usb/gadget/f_fastboot.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * (C) Copyright 2008 - 2009
3*4882a593Smuzhiyun  * Windriver, <www.windriver.com>
4*4882a593Smuzhiyun  * Tom Rix <Tom.Rix@windriver.com>
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de>
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Copyright 2014 Linaro, Ltd.
9*4882a593Smuzhiyun  * Rob Herring <robh@kernel.org>
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
12*4882a593Smuzhiyun  */
13*4882a593Smuzhiyun #include <config.h>
14*4882a593Smuzhiyun #include <common.h>
15*4882a593Smuzhiyun #include <console.h>
16*4882a593Smuzhiyun #include <android_bootloader.h>
17*4882a593Smuzhiyun #include <errno.h>
18*4882a593Smuzhiyun #include <fastboot.h>
19*4882a593Smuzhiyun #include <malloc.h>
20*4882a593Smuzhiyun #include <linux/usb/ch9.h>
21*4882a593Smuzhiyun #include <linux/usb/gadget.h>
22*4882a593Smuzhiyun #include <linux/usb/composite.h>
23*4882a593Smuzhiyun #include <linux/compiler.h>
24*4882a593Smuzhiyun #include <u-boot/sha256.h>
25*4882a593Smuzhiyun #include <version.h>
26*4882a593Smuzhiyun #include <g_dnl.h>
27*4882a593Smuzhiyun #include <fs.h>
28*4882a593Smuzhiyun #include <android_avb/avb_ops_user.h>
29*4882a593Smuzhiyun #include <android_avb/rk_avb_ops_user.h>
30*4882a593Smuzhiyun #include <dm/uclass.h>
31*4882a593Smuzhiyun #include <power/fuel_gauge.h>
32*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
33*4882a593Smuzhiyun #include <fb_mmc.h>
34*4882a593Smuzhiyun #endif
35*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV
36*4882a593Smuzhiyun #include <fb_nand.h>
37*4882a593Smuzhiyun #endif
38*4882a593Smuzhiyun #ifdef CONFIG_OPTEE_CLIENT
39*4882a593Smuzhiyun #include <optee_include/OpteeClientInterface.h>
40*4882a593Smuzhiyun #endif
41*4882a593Smuzhiyun #include <boot_rkimg.h>
42*4882a593Smuzhiyun #include <optee_include/tee_client_api.h>
43*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_OEM_UNLOCK
44*4882a593Smuzhiyun #include <keymaster.h>
45*4882a593Smuzhiyun #endif
46*4882a593Smuzhiyun #ifdef CONFIG_ANDROID_AB
47*4882a593Smuzhiyun #include <android_ab.h>
48*4882a593Smuzhiyun #endif
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun #define FASTBOOT_VERSION		"0.4"
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun #define FASTBOOT_INTERFACE_CLASS	0xff
53*4882a593Smuzhiyun #define FASTBOOT_INTERFACE_SUB_CLASS	0x42
54*4882a593Smuzhiyun #define FASTBOOT_INTERFACE_PROTOCOL	0x03
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun #define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0  (0x0200)
57*4882a593Smuzhiyun #define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1  (0x0040)
58*4882a593Smuzhiyun #define TX_ENDPOINT_MAXIMUM_PACKET_SIZE      (0x0040)
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun #define EP_BUFFER_SIZE			4096
61*4882a593Smuzhiyun #define SLEEP_COUNT 20000
62*4882a593Smuzhiyun #define MAX_PART_NUM_STR_SIZE 4
63*4882a593Smuzhiyun #define PARTITION_TYPE_STRINGS "partition-type"
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun /*
66*4882a593Smuzhiyun  * EP_BUFFER_SIZE must always be an integral multiple of maxpacket size
67*4882a593Smuzhiyun  * (64 or 512 or 1024), else we break on certain controllers like DWC3
68*4882a593Smuzhiyun  * that expect bulk OUT requests to be divisible by maxpacket size.
69*4882a593Smuzhiyun  */
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun struct f_fastboot {
72*4882a593Smuzhiyun 	struct usb_function usb_function;
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	/* IN/OUT EP's and corresponding requests */
75*4882a593Smuzhiyun 	struct usb_ep *in_ep, *out_ep;
76*4882a593Smuzhiyun 	struct usb_request *in_req, *out_req;
77*4882a593Smuzhiyun };
78*4882a593Smuzhiyun 
func_to_fastboot(struct usb_function * f)79*4882a593Smuzhiyun static inline struct f_fastboot *func_to_fastboot(struct usb_function *f)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun 	return container_of(f, struct f_fastboot, usb_function);
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun static struct f_fastboot *fastboot_func;
85*4882a593Smuzhiyun static unsigned int download_size;
86*4882a593Smuzhiyun static unsigned int download_bytes;
87*4882a593Smuzhiyun static unsigned int upload_size;
88*4882a593Smuzhiyun static unsigned int upload_bytes;
89*4882a593Smuzhiyun static bool start_upload;
90*4882a593Smuzhiyun static unsigned intthread_wakeup_needed;
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun static struct usb_endpoint_descriptor fs_ep_in = {
93*4882a593Smuzhiyun 	.bLength            = USB_DT_ENDPOINT_SIZE,
94*4882a593Smuzhiyun 	.bDescriptorType    = USB_DT_ENDPOINT,
95*4882a593Smuzhiyun 	.bEndpointAddress   = USB_DIR_IN,
96*4882a593Smuzhiyun 	.bmAttributes       = USB_ENDPOINT_XFER_BULK,
97*4882a593Smuzhiyun 	.wMaxPacketSize     = cpu_to_le16(64),
98*4882a593Smuzhiyun };
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun static struct usb_endpoint_descriptor fs_ep_out = {
101*4882a593Smuzhiyun 	.bLength		= USB_DT_ENDPOINT_SIZE,
102*4882a593Smuzhiyun 	.bDescriptorType	= USB_DT_ENDPOINT,
103*4882a593Smuzhiyun 	.bEndpointAddress	= USB_DIR_OUT,
104*4882a593Smuzhiyun 	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
105*4882a593Smuzhiyun 	.wMaxPacketSize		= cpu_to_le16(64),
106*4882a593Smuzhiyun };
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun static struct usb_endpoint_descriptor hs_ep_in = {
109*4882a593Smuzhiyun 	.bLength		= USB_DT_ENDPOINT_SIZE,
110*4882a593Smuzhiyun 	.bDescriptorType	= USB_DT_ENDPOINT,
111*4882a593Smuzhiyun 	.bEndpointAddress	= USB_DIR_IN,
112*4882a593Smuzhiyun 	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
113*4882a593Smuzhiyun 	.wMaxPacketSize		= cpu_to_le16(512),
114*4882a593Smuzhiyun };
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun static struct usb_endpoint_descriptor hs_ep_out = {
117*4882a593Smuzhiyun 	.bLength		= USB_DT_ENDPOINT_SIZE,
118*4882a593Smuzhiyun 	.bDescriptorType	= USB_DT_ENDPOINT,
119*4882a593Smuzhiyun 	.bEndpointAddress	= USB_DIR_OUT,
120*4882a593Smuzhiyun 	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
121*4882a593Smuzhiyun 	.wMaxPacketSize		= cpu_to_le16(512),
122*4882a593Smuzhiyun };
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun static struct usb_endpoint_descriptor ss_ep_in = {
125*4882a593Smuzhiyun 	.bLength		= USB_DT_ENDPOINT_SIZE,
126*4882a593Smuzhiyun 	.bDescriptorType	= USB_DT_ENDPOINT,
127*4882a593Smuzhiyun 	.bEndpointAddress	= USB_DIR_IN,
128*4882a593Smuzhiyun 	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
129*4882a593Smuzhiyun 	.wMaxPacketSize		= cpu_to_le16(1024),
130*4882a593Smuzhiyun };
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun static struct usb_ss_ep_comp_descriptor ss_ep_in_comp_desc = {
133*4882a593Smuzhiyun 	.bLength		= sizeof(ss_ep_in_comp_desc),
134*4882a593Smuzhiyun 	.bDescriptorType	= USB_DT_SS_ENDPOINT_COMP,
135*4882a593Smuzhiyun 	/* .bMaxBurst		= DYNAMIC, */
136*4882a593Smuzhiyun };
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun static struct usb_endpoint_descriptor ss_ep_out = {
139*4882a593Smuzhiyun 	.bLength		= USB_DT_ENDPOINT_SIZE,
140*4882a593Smuzhiyun 	.bDescriptorType	= USB_DT_ENDPOINT,
141*4882a593Smuzhiyun 	.bEndpointAddress	= USB_DIR_OUT,
142*4882a593Smuzhiyun 	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
143*4882a593Smuzhiyun 	.wMaxPacketSize		= cpu_to_le16(1024),
144*4882a593Smuzhiyun };
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun static struct usb_ss_ep_comp_descriptor ss_ep_out_comp_desc = {
147*4882a593Smuzhiyun 	.bLength		= sizeof(ss_ep_out_comp_desc),
148*4882a593Smuzhiyun 	.bDescriptorType	= USB_DT_SS_ENDPOINT_COMP,
149*4882a593Smuzhiyun 	/* .bMaxBurst		= DYNAMIC, */
150*4882a593Smuzhiyun };
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun static struct usb_interface_descriptor interface_desc = {
153*4882a593Smuzhiyun 	.bLength		= USB_DT_INTERFACE_SIZE,
154*4882a593Smuzhiyun 	.bDescriptorType	= USB_DT_INTERFACE,
155*4882a593Smuzhiyun 	.bInterfaceNumber	= 0x00,
156*4882a593Smuzhiyun 	.bAlternateSetting	= 0x00,
157*4882a593Smuzhiyun 	.bNumEndpoints		= 0x02,
158*4882a593Smuzhiyun 	.bInterfaceClass	= FASTBOOT_INTERFACE_CLASS,
159*4882a593Smuzhiyun 	.bInterfaceSubClass	= FASTBOOT_INTERFACE_SUB_CLASS,
160*4882a593Smuzhiyun 	.bInterfaceProtocol	= FASTBOOT_INTERFACE_PROTOCOL,
161*4882a593Smuzhiyun };
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun static struct usb_descriptor_header *fb_fs_function[] = {
164*4882a593Smuzhiyun 	(struct usb_descriptor_header *)&interface_desc,
165*4882a593Smuzhiyun 	(struct usb_descriptor_header *)&fs_ep_in,
166*4882a593Smuzhiyun 	(struct usb_descriptor_header *)&fs_ep_out,
167*4882a593Smuzhiyun };
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun static struct usb_descriptor_header *fb_hs_function[] = {
170*4882a593Smuzhiyun 	(struct usb_descriptor_header *)&interface_desc,
171*4882a593Smuzhiyun 	(struct usb_descriptor_header *)&hs_ep_in,
172*4882a593Smuzhiyun 	(struct usb_descriptor_header *)&hs_ep_out,
173*4882a593Smuzhiyun 	NULL,
174*4882a593Smuzhiyun };
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun static struct usb_descriptor_header *fb_ss_function[] = {
177*4882a593Smuzhiyun 	(struct usb_descriptor_header *)&interface_desc,
178*4882a593Smuzhiyun 	(struct usb_descriptor_header *)&ss_ep_in,
179*4882a593Smuzhiyun 	(struct usb_descriptor_header *)&ss_ep_in_comp_desc,
180*4882a593Smuzhiyun 	(struct usb_descriptor_header *)&ss_ep_out,
181*4882a593Smuzhiyun 	(struct usb_descriptor_header *)&ss_ep_out_comp_desc,
182*4882a593Smuzhiyun 	NULL,
183*4882a593Smuzhiyun };
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun static struct usb_endpoint_descriptor *
fb_ep_desc(struct usb_gadget * g,struct usb_endpoint_descriptor * fs,struct usb_endpoint_descriptor * hs,struct usb_endpoint_descriptor * ss,struct usb_ss_ep_comp_descriptor * comp_desc,struct usb_ep * ep)186*4882a593Smuzhiyun fb_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
187*4882a593Smuzhiyun 	   struct usb_endpoint_descriptor *hs,
188*4882a593Smuzhiyun 	   struct usb_endpoint_descriptor *ss,
189*4882a593Smuzhiyun 	   struct usb_ss_ep_comp_descriptor *comp_desc,
190*4882a593Smuzhiyun 	   struct usb_ep *ep)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun 	struct usb_endpoint_descriptor *speed_desc = NULL;
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	/* select desired speed */
195*4882a593Smuzhiyun 	switch (g->speed) {
196*4882a593Smuzhiyun 	case USB_SPEED_SUPER:
197*4882a593Smuzhiyun 		if (gadget_is_superspeed(g)) {
198*4882a593Smuzhiyun 			speed_desc = ss;
199*4882a593Smuzhiyun 			ep->comp_desc = comp_desc;
200*4882a593Smuzhiyun 			break;
201*4882a593Smuzhiyun 		}
202*4882a593Smuzhiyun 		/* else: Fall trough */
203*4882a593Smuzhiyun 	case USB_SPEED_HIGH:
204*4882a593Smuzhiyun 		if (gadget_is_dualspeed(g)) {
205*4882a593Smuzhiyun 			speed_desc = hs;
206*4882a593Smuzhiyun 			break;
207*4882a593Smuzhiyun 		}
208*4882a593Smuzhiyun 		/* else: fall through */
209*4882a593Smuzhiyun 	default:
210*4882a593Smuzhiyun 		speed_desc = fs;
211*4882a593Smuzhiyun 	}
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	return speed_desc;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun /*
217*4882a593Smuzhiyun  * static strings, in UTF-8
218*4882a593Smuzhiyun  */
219*4882a593Smuzhiyun static const char fastboot_name[] = "Android Fastboot";
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun static struct usb_string fastboot_string_defs[] = {
222*4882a593Smuzhiyun 	[0].s = fastboot_name,
223*4882a593Smuzhiyun 	{  }			/* end of list */
224*4882a593Smuzhiyun };
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun static struct usb_gadget_strings stringtab_fastboot = {
227*4882a593Smuzhiyun 	.language	= 0x0409,	/* en-us */
228*4882a593Smuzhiyun 	.strings	= fastboot_string_defs,
229*4882a593Smuzhiyun };
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun static struct usb_gadget_strings *fastboot_strings[] = {
232*4882a593Smuzhiyun 	&stringtab_fastboot,
233*4882a593Smuzhiyun 	NULL,
234*4882a593Smuzhiyun };
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun static void rx_handler_command(struct usb_ep *ep, struct usb_request *req);
237*4882a593Smuzhiyun static int strcmp_l1(const char *s1, const char *s2);
wakeup_thread(void)238*4882a593Smuzhiyun static void wakeup_thread(void)
239*4882a593Smuzhiyun {
240*4882a593Smuzhiyun 	intthread_wakeup_needed = false;
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun 
busy_indicator(void)243*4882a593Smuzhiyun static void busy_indicator(void)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun 	static int state;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	switch (state) {
248*4882a593Smuzhiyun 	case 0:
249*4882a593Smuzhiyun 		puts("\r|"); break;
250*4882a593Smuzhiyun 	case 1:
251*4882a593Smuzhiyun 		puts("\r/"); break;
252*4882a593Smuzhiyun 	case 2:
253*4882a593Smuzhiyun 		puts("\r-"); break;
254*4882a593Smuzhiyun 	case 3:
255*4882a593Smuzhiyun 		puts("\r\\"); break;
256*4882a593Smuzhiyun 	case 4:
257*4882a593Smuzhiyun 		puts("\r|"); break;
258*4882a593Smuzhiyun 	case 5:
259*4882a593Smuzhiyun 		puts("\r/"); break;
260*4882a593Smuzhiyun 	case 6:
261*4882a593Smuzhiyun 		puts("\r-"); break;
262*4882a593Smuzhiyun 	case 7:
263*4882a593Smuzhiyun 		puts("\r\\"); break;
264*4882a593Smuzhiyun 	default:
265*4882a593Smuzhiyun 		state = 0;
266*4882a593Smuzhiyun 	}
267*4882a593Smuzhiyun 	if (state++ == 8)
268*4882a593Smuzhiyun 		state = 0;
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun 
fb_get_fstype(const char * ifname,const int part_num,const char ** fs_type)271*4882a593Smuzhiyun static int fb_get_fstype(const char *ifname, const int part_num,
272*4882a593Smuzhiyun 			 const char **fs_type)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun 	char part_num_str[MAX_PART_NUM_STR_SIZE] = {0};
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	snprintf(part_num_str, ARRAY_SIZE(part_num_str), ":%x", part_num);
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	if (fs_set_blk_dev(ifname, part_num_str, FS_TYPE_ANY))
279*4882a593Smuzhiyun 		return -1;
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	if (fs_get_fstype(fs_type))
282*4882a593Smuzhiyun 		return -1;
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	return 0;
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun 
sleep_thread(void)287*4882a593Smuzhiyun static int sleep_thread(void)
288*4882a593Smuzhiyun {
289*4882a593Smuzhiyun 	int rc = 0;
290*4882a593Smuzhiyun 	int i = 0, k = 0;
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	/* Wait until a signal arrives or we are woken up */
293*4882a593Smuzhiyun 	for (;;) {
294*4882a593Smuzhiyun 		if (!intthread_wakeup_needed)
295*4882a593Smuzhiyun 			break;
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 		if (++i == SLEEP_COUNT) {
298*4882a593Smuzhiyun 			busy_indicator();
299*4882a593Smuzhiyun 			i = 0;
300*4882a593Smuzhiyun 			k++;
301*4882a593Smuzhiyun 		}
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 		if (k == 10) {
304*4882a593Smuzhiyun 			/* Handle CTRL+C */
305*4882a593Smuzhiyun 			if (ctrlc())
306*4882a593Smuzhiyun 				return -EPIPE;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 			/* Check cable connection */
309*4882a593Smuzhiyun 			if (!g_dnl_board_usb_cable_connected())
310*4882a593Smuzhiyun 				return -EIO;
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 			k = 0;
313*4882a593Smuzhiyun 		}
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 		usb_gadget_handle_interrupts(0);
316*4882a593Smuzhiyun 	}
317*4882a593Smuzhiyun 	intthread_wakeup_needed = true;
318*4882a593Smuzhiyun 	return rc;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun 
fastboot_complete(struct usb_ep * ep,struct usb_request * req)321*4882a593Smuzhiyun static void fastboot_complete(struct usb_ep *ep, struct usb_request *req)
322*4882a593Smuzhiyun {
323*4882a593Smuzhiyun 	int status = req->status;
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	wakeup_thread();
326*4882a593Smuzhiyun 	if (!status)
327*4882a593Smuzhiyun 		return;
328*4882a593Smuzhiyun 	printf("status: %d ep '%s' trans: %d\n", status, ep->name, req->actual);
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun 
fastboot_bind(struct usb_configuration * c,struct usb_function * f)331*4882a593Smuzhiyun static int fastboot_bind(struct usb_configuration *c, struct usb_function *f)
332*4882a593Smuzhiyun {
333*4882a593Smuzhiyun 	int id;
334*4882a593Smuzhiyun 	struct usb_gadget *gadget = c->cdev->gadget;
335*4882a593Smuzhiyun 	struct f_fastboot *f_fb = func_to_fastboot(f);
336*4882a593Smuzhiyun 	const char *s;
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 	/* DYNAMIC interface numbers assignments */
339*4882a593Smuzhiyun 	id = usb_interface_id(c, f);
340*4882a593Smuzhiyun 	if (id < 0)
341*4882a593Smuzhiyun 		return id;
342*4882a593Smuzhiyun 	interface_desc.bInterfaceNumber = id;
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	id = usb_string_id(c->cdev);
345*4882a593Smuzhiyun 	if (id < 0)
346*4882a593Smuzhiyun 		return id;
347*4882a593Smuzhiyun 	fastboot_string_defs[0].id = id;
348*4882a593Smuzhiyun 	interface_desc.iInterface = id;
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	f_fb->in_ep = usb_ep_autoconfig(gadget, &fs_ep_in);
351*4882a593Smuzhiyun 	if (!f_fb->in_ep)
352*4882a593Smuzhiyun 		return -ENODEV;
353*4882a593Smuzhiyun 	f_fb->in_ep->driver_data = c->cdev;
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	f_fb->out_ep = usb_ep_autoconfig(gadget, &fs_ep_out);
356*4882a593Smuzhiyun 	if (!f_fb->out_ep)
357*4882a593Smuzhiyun 		return -ENODEV;
358*4882a593Smuzhiyun 	f_fb->out_ep->driver_data = c->cdev;
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	f->descriptors = fb_fs_function;
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	if (gadget_is_dualspeed(gadget)) {
363*4882a593Smuzhiyun 		/* Assume endpoint addresses are the same for both speeds */
364*4882a593Smuzhiyun 		hs_ep_in.bEndpointAddress = fs_ep_in.bEndpointAddress;
365*4882a593Smuzhiyun 		hs_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
366*4882a593Smuzhiyun 		/* copy HS descriptors */
367*4882a593Smuzhiyun 		f->hs_descriptors = fb_hs_function;
368*4882a593Smuzhiyun 	}
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	if (gadget_is_superspeed(gadget)) {
371*4882a593Smuzhiyun 		/* Assume endpoint addresses are the same as full speed */
372*4882a593Smuzhiyun 		ss_ep_in.bEndpointAddress = fs_ep_in.bEndpointAddress;
373*4882a593Smuzhiyun 		ss_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
374*4882a593Smuzhiyun 		/* copy SS descriptors */
375*4882a593Smuzhiyun 		f->ss_descriptors = fb_ss_function;
376*4882a593Smuzhiyun 	}
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	s = env_get("serial#");
379*4882a593Smuzhiyun 	if (s)
380*4882a593Smuzhiyun 		g_dnl_set_serialnumber((char *)s);
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	return 0;
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun 
fastboot_unbind(struct usb_configuration * c,struct usb_function * f)385*4882a593Smuzhiyun static void fastboot_unbind(struct usb_configuration *c, struct usb_function *f)
386*4882a593Smuzhiyun {
387*4882a593Smuzhiyun 	memset(fastboot_func, 0, sizeof(*fastboot_func));
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun 
fastboot_disable(struct usb_function * f)390*4882a593Smuzhiyun static void fastboot_disable(struct usb_function *f)
391*4882a593Smuzhiyun {
392*4882a593Smuzhiyun 	struct f_fastboot *f_fb = func_to_fastboot(f);
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	usb_ep_disable(f_fb->out_ep);
395*4882a593Smuzhiyun 	usb_ep_disable(f_fb->in_ep);
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	if (f_fb->out_req) {
398*4882a593Smuzhiyun 		free(f_fb->out_req->buf);
399*4882a593Smuzhiyun 		usb_ep_free_request(f_fb->out_ep, f_fb->out_req);
400*4882a593Smuzhiyun 		f_fb->out_req = NULL;
401*4882a593Smuzhiyun 	}
402*4882a593Smuzhiyun 	if (f_fb->in_req) {
403*4882a593Smuzhiyun 		free(f_fb->in_req->buf);
404*4882a593Smuzhiyun 		usb_ep_free_request(f_fb->in_ep, f_fb->in_req);
405*4882a593Smuzhiyun 		f_fb->in_req = NULL;
406*4882a593Smuzhiyun 	}
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun 
fastboot_start_ep(struct usb_ep * ep)409*4882a593Smuzhiyun static struct usb_request *fastboot_start_ep(struct usb_ep *ep)
410*4882a593Smuzhiyun {
411*4882a593Smuzhiyun 	struct usb_request *req;
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun 	req = usb_ep_alloc_request(ep, 0);
414*4882a593Smuzhiyun 	if (!req)
415*4882a593Smuzhiyun 		return NULL;
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 	req->length = EP_BUFFER_SIZE;
418*4882a593Smuzhiyun 	req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, EP_BUFFER_SIZE);
419*4882a593Smuzhiyun 	if (!req->buf) {
420*4882a593Smuzhiyun 		usb_ep_free_request(ep, req);
421*4882a593Smuzhiyun 		return NULL;
422*4882a593Smuzhiyun 	}
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	memset(req->buf, 0, req->length);
425*4882a593Smuzhiyun 	return req;
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun 
fastboot_set_alt(struct usb_function * f,unsigned interface,unsigned alt)428*4882a593Smuzhiyun static int fastboot_set_alt(struct usb_function *f,
429*4882a593Smuzhiyun 			    unsigned interface, unsigned alt)
430*4882a593Smuzhiyun {
431*4882a593Smuzhiyun 	int ret;
432*4882a593Smuzhiyun 	struct usb_composite_dev *cdev = f->config->cdev;
433*4882a593Smuzhiyun 	struct usb_gadget *gadget = cdev->gadget;
434*4882a593Smuzhiyun 	struct f_fastboot *f_fb = func_to_fastboot(f);
435*4882a593Smuzhiyun 	const struct usb_endpoint_descriptor *d;
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	debug("%s: func: %s intf: %d alt: %d\n",
438*4882a593Smuzhiyun 	      __func__, f->name, interface, alt);
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	d = fb_ep_desc(gadget, &fs_ep_out, &hs_ep_out, &ss_ep_out,
441*4882a593Smuzhiyun 		       &ss_ep_out_comp_desc, f_fb->out_ep);
442*4882a593Smuzhiyun 	ret = usb_ep_enable(f_fb->out_ep, d);
443*4882a593Smuzhiyun 	if (ret) {
444*4882a593Smuzhiyun 		puts("failed to enable out ep\n");
445*4882a593Smuzhiyun 		return ret;
446*4882a593Smuzhiyun 	}
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	f_fb->out_req = fastboot_start_ep(f_fb->out_ep);
449*4882a593Smuzhiyun 	if (!f_fb->out_req) {
450*4882a593Smuzhiyun 		puts("failed to alloc out req\n");
451*4882a593Smuzhiyun 		ret = -EINVAL;
452*4882a593Smuzhiyun 		goto err;
453*4882a593Smuzhiyun 	}
454*4882a593Smuzhiyun 	f_fb->out_req->complete = rx_handler_command;
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	d = fb_ep_desc(gadget, &fs_ep_in, &hs_ep_in, &ss_ep_in,
457*4882a593Smuzhiyun 		       &ss_ep_in_comp_desc, f_fb->in_ep);
458*4882a593Smuzhiyun 	ret = usb_ep_enable(f_fb->in_ep, d);
459*4882a593Smuzhiyun 	if (ret) {
460*4882a593Smuzhiyun 		puts("failed to enable in ep\n");
461*4882a593Smuzhiyun 		goto err;
462*4882a593Smuzhiyun 	}
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun 	f_fb->in_req = fastboot_start_ep(f_fb->in_ep);
465*4882a593Smuzhiyun 	if (!f_fb->in_req) {
466*4882a593Smuzhiyun 		puts("failed alloc req in\n");
467*4882a593Smuzhiyun 		ret = -EINVAL;
468*4882a593Smuzhiyun 		goto err;
469*4882a593Smuzhiyun 	}
470*4882a593Smuzhiyun 	f_fb->in_req->complete = fastboot_complete;
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	ret = usb_ep_queue(f_fb->out_ep, f_fb->out_req, 0);
473*4882a593Smuzhiyun 	if (ret)
474*4882a593Smuzhiyun 		goto err;
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 	return 0;
477*4882a593Smuzhiyun err:
478*4882a593Smuzhiyun 	fastboot_disable(f);
479*4882a593Smuzhiyun 	return ret;
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun 
fastboot_add(struct usb_configuration * c)482*4882a593Smuzhiyun static int fastboot_add(struct usb_configuration *c)
483*4882a593Smuzhiyun {
484*4882a593Smuzhiyun 	struct f_fastboot *f_fb = fastboot_func;
485*4882a593Smuzhiyun 	int status;
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	debug("%s: cdev: 0x%p\n", __func__, c->cdev);
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	if (!f_fb) {
490*4882a593Smuzhiyun 		f_fb = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*f_fb));
491*4882a593Smuzhiyun 		if (!f_fb)
492*4882a593Smuzhiyun 			return -ENOMEM;
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 		fastboot_func = f_fb;
495*4882a593Smuzhiyun 		memset(f_fb, 0, sizeof(*f_fb));
496*4882a593Smuzhiyun 	}
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun 	f_fb->usb_function.name = "f_fastboot";
499*4882a593Smuzhiyun 	f_fb->usb_function.bind = fastboot_bind;
500*4882a593Smuzhiyun 	f_fb->usb_function.unbind = fastboot_unbind;
501*4882a593Smuzhiyun 	f_fb->usb_function.set_alt = fastboot_set_alt;
502*4882a593Smuzhiyun 	f_fb->usb_function.disable = fastboot_disable;
503*4882a593Smuzhiyun 	f_fb->usb_function.strings = fastboot_strings;
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	status = usb_add_function(c, &f_fb->usb_function);
506*4882a593Smuzhiyun 	if (status) {
507*4882a593Smuzhiyun 		free(f_fb);
508*4882a593Smuzhiyun 		fastboot_func = f_fb;
509*4882a593Smuzhiyun 	}
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 	return status;
512*4882a593Smuzhiyun }
513*4882a593Smuzhiyun DECLARE_GADGET_BIND_CALLBACK(usb_dnl_fastboot, fastboot_add);
514*4882a593Smuzhiyun 
fastboot_tx_write(const char * buffer,unsigned int buffer_size)515*4882a593Smuzhiyun static int fastboot_tx_write(const char *buffer, unsigned int buffer_size)
516*4882a593Smuzhiyun {
517*4882a593Smuzhiyun 	struct usb_request *in_req = fastboot_func->in_req;
518*4882a593Smuzhiyun 	int ret;
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	memcpy(in_req->buf, buffer, buffer_size);
521*4882a593Smuzhiyun 	in_req->length = buffer_size;
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 	usb_ep_dequeue(fastboot_func->in_ep, in_req);
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 	ret = usb_ep_queue(fastboot_func->in_ep, in_req, 0);
526*4882a593Smuzhiyun 	if (ret)
527*4882a593Smuzhiyun 		printf("Error %d on queue\n", ret);
528*4882a593Smuzhiyun 	return 0;
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun 
fastboot_tx_write_str(const char * buffer)531*4882a593Smuzhiyun static int fastboot_tx_write_str(const char *buffer)
532*4882a593Smuzhiyun {
533*4882a593Smuzhiyun 	int ret;
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun 	ret = sleep_thread();
536*4882a593Smuzhiyun 	if (ret < 0)
537*4882a593Smuzhiyun 		printf("warning: 0x%x, usb transmission is abnormal!\n", ret);
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 	return fastboot_tx_write(buffer, strlen(buffer));
540*4882a593Smuzhiyun }
541*4882a593Smuzhiyun 
compl_do_reset(struct usb_ep * ep,struct usb_request * req)542*4882a593Smuzhiyun static void compl_do_reset(struct usb_ep *ep, struct usb_request *req)
543*4882a593Smuzhiyun {
544*4882a593Smuzhiyun 	do_reset(NULL, 0, 0, NULL);
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun 
fb_set_reboot_flag(void)547*4882a593Smuzhiyun int __weak fb_set_reboot_flag(void)
548*4882a593Smuzhiyun {
549*4882a593Smuzhiyun 	return -ENOSYS;
550*4882a593Smuzhiyun }
551*4882a593Smuzhiyun 
cb_reboot(struct usb_ep * ep,struct usb_request * req)552*4882a593Smuzhiyun static void cb_reboot(struct usb_ep *ep, struct usb_request *req)
553*4882a593Smuzhiyun {
554*4882a593Smuzhiyun 	char *cmd = req->buf;
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun 	if (!strcmp_l1("reboot-bootloader", cmd)) {
557*4882a593Smuzhiyun 		if (fb_set_reboot_flag()) {
558*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILCannot set reboot flag");
559*4882a593Smuzhiyun 			return;
560*4882a593Smuzhiyun 		}
561*4882a593Smuzhiyun 	}
562*4882a593Smuzhiyun #ifdef CONFIG_ANDROID_BOOTLOADER
563*4882a593Smuzhiyun 	if (!strcmp_l1("reboot-fastboot", cmd)) {
564*4882a593Smuzhiyun 		if (android_bcb_write("boot-fastboot")) {
565*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILCannot set boot-fastboot");
566*4882a593Smuzhiyun 			return;
567*4882a593Smuzhiyun 		}
568*4882a593Smuzhiyun 	}
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	if (!strcmp_l1("reboot-recovery", cmd)) {
571*4882a593Smuzhiyun 		if (android_bcb_write("boot-recovery")) {
572*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILCannot set boot-recovery");
573*4882a593Smuzhiyun 			return;
574*4882a593Smuzhiyun 		}
575*4882a593Smuzhiyun 	}
576*4882a593Smuzhiyun #endif
577*4882a593Smuzhiyun 	fastboot_func->in_req->complete = compl_do_reset;
578*4882a593Smuzhiyun 	fastboot_tx_write_str("OKAY");
579*4882a593Smuzhiyun }
580*4882a593Smuzhiyun 
strcmp_l1(const char * s1,const char * s2)581*4882a593Smuzhiyun static int strcmp_l1(const char *s1, const char *s2)
582*4882a593Smuzhiyun {
583*4882a593Smuzhiyun 	if (!s1 || !s2)
584*4882a593Smuzhiyun 		return -1;
585*4882a593Smuzhiyun 	return strncmp(s1, s2, strlen(s1));
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun struct name_string {
589*4882a593Smuzhiyun 	const char *str;
590*4882a593Smuzhiyun 	int expects_args;
591*4882a593Smuzhiyun 	char delim;
592*4882a593Smuzhiyun };
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun #define NAME_NO_ARGS(s)	{.str = s, .expects_args = 0}
595*4882a593Smuzhiyun #define NAME_ARGS(s, d)	{.str = s, .expects_args = 1, .delim = d}
596*4882a593Smuzhiyun 
name_check_match(const char * str,size_t len,const struct name_string * name)597*4882a593Smuzhiyun static size_t name_check_match(const char *str, size_t len,
598*4882a593Smuzhiyun 			       const struct name_string *name)
599*4882a593Smuzhiyun {
600*4882a593Smuzhiyun 	size_t str_len = strlen(name->str);
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	/* If name len is greater than input, return 0. */
603*4882a593Smuzhiyun 	if (str_len > len)
604*4882a593Smuzhiyun 		return 0;
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun 	/* If name str does not match input string, return 0. */
607*4882a593Smuzhiyun 	if (memcmp(name->str, str, str_len))
608*4882a593Smuzhiyun 		return 0;
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun 	if (name->expects_args) {
611*4882a593Smuzhiyun 		/* string should have space for delim */
612*4882a593Smuzhiyun 		if (len == str_len)
613*4882a593Smuzhiyun 			return 0;
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 		/* Check delim match */
616*4882a593Smuzhiyun 		if (name->delim != str[str_len])
617*4882a593Smuzhiyun 			return 0;
618*4882a593Smuzhiyun 	} else {
619*4882a593Smuzhiyun 		/* Name str len should match input len */
620*4882a593Smuzhiyun 		if (str_len != len)
621*4882a593Smuzhiyun 			return 0;
622*4882a593Smuzhiyun 	}
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun 	return str_len + name->expects_args;
625*4882a593Smuzhiyun }
626*4882a593Smuzhiyun 
fb_add_string(char * dst,size_t chars_left,const char * str,const char * args)627*4882a593Smuzhiyun static void fb_add_string(char *dst, size_t chars_left,
628*4882a593Smuzhiyun 			  const char *str, const char *args)
629*4882a593Smuzhiyun {
630*4882a593Smuzhiyun 	if (!str)
631*4882a593Smuzhiyun 		return;
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun 	int ret = snprintf(dst, chars_left, str, args);
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun 	if (ret < 0)
636*4882a593Smuzhiyun 		pr_err("snprintf is error!");
637*4882a593Smuzhiyun }
638*4882a593Smuzhiyun 
fb_add_number(char * dst,size_t chars_left,const char * format,size_t num)639*4882a593Smuzhiyun static void fb_add_number(char *dst, size_t chars_left,
640*4882a593Smuzhiyun 			  const char *format, size_t num)
641*4882a593Smuzhiyun {
642*4882a593Smuzhiyun 	if (!format)
643*4882a593Smuzhiyun 		return;
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun 	int ret = snprintf(dst, chars_left, format, num);
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 	if (ret > chars_left)
648*4882a593Smuzhiyun 		pr_err("snprintf is error!");
649*4882a593Smuzhiyun }
650*4882a593Smuzhiyun 
fb_read_var(char * cmd,char * response,fb_getvar_t var,size_t chars_left)651*4882a593Smuzhiyun static int fb_read_var(char *cmd, char *response,
652*4882a593Smuzhiyun 		       fb_getvar_t var, size_t chars_left)
653*4882a593Smuzhiyun {
654*4882a593Smuzhiyun 	const char *s;
655*4882a593Smuzhiyun 	int ret = 0;
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun 	switch (var) {
658*4882a593Smuzhiyun 	case FB_VERSION:
659*4882a593Smuzhiyun 		fb_add_string(response, chars_left, FASTBOOT_VERSION, NULL);
660*4882a593Smuzhiyun 		break;
661*4882a593Smuzhiyun 	case FB_BOOTLOADER_VERSION:
662*4882a593Smuzhiyun 		fb_add_string(response, chars_left, U_BOOT_VERSION, NULL);
663*4882a593Smuzhiyun 		break;
664*4882a593Smuzhiyun 	case FB_BASEBAND_VERSION:
665*4882a593Smuzhiyun 		fb_add_string(response, chars_left, "N/A", NULL);
666*4882a593Smuzhiyun 		break;
667*4882a593Smuzhiyun 	case FB_PRODUCT:
668*4882a593Smuzhiyun 		fb_add_string(response, chars_left, CONFIG_SYS_BOARD, NULL);
669*4882a593Smuzhiyun 		break;
670*4882a593Smuzhiyun 	case FB_SERIAL_NO:
671*4882a593Smuzhiyun 		s = env_get("serial#");
672*4882a593Smuzhiyun 		if (s)
673*4882a593Smuzhiyun 			fb_add_string(response, chars_left, s, NULL);
674*4882a593Smuzhiyun 		else
675*4882a593Smuzhiyun 			ret = -1;
676*4882a593Smuzhiyun 		break;
677*4882a593Smuzhiyun 	case FB_SECURE:
678*4882a593Smuzhiyun 		fb_add_string(response, chars_left, "yes", NULL);
679*4882a593Smuzhiyun 		break;
680*4882a593Smuzhiyun 	case FB_VARIANT:
681*4882a593Smuzhiyun 		fb_add_string(response, chars_left, "userdebug", NULL);
682*4882a593Smuzhiyun 		break;
683*4882a593Smuzhiyun 	case FB_DWNLD_SIZE:
684*4882a593Smuzhiyun 		fb_add_number(response, chars_left, "0x%08x",
685*4882a593Smuzhiyun 			      CONFIG_FASTBOOT_BUF_SIZE);
686*4882a593Smuzhiyun 		break;
687*4882a593Smuzhiyun 	case FB_PART_SIZE:
688*4882a593Smuzhiyun 	case FB_PART_TYPE: {
689*4882a593Smuzhiyun 		char *part_name = cmd;
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun 		cmd = strsep(&part_name, ":");
692*4882a593Smuzhiyun 		if (!cmd || !part_name) {
693*4882a593Smuzhiyun 			fb_add_string(response, chars_left,
694*4882a593Smuzhiyun 				      "argument Invalid!", NULL);
695*4882a593Smuzhiyun 			ret = -1;
696*4882a593Smuzhiyun 			break;
697*4882a593Smuzhiyun 		}
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
700*4882a593Smuzhiyun 		disk_partition_t part_info;
701*4882a593Smuzhiyun 		struct blk_desc *dev_desc;
702*4882a593Smuzhiyun 		int part_num = -1;
703*4882a593Smuzhiyun 		const char *fs_type = NULL;
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun #ifdef CONFIG_RKIMG_BOOTLOADER
706*4882a593Smuzhiyun 		dev_desc = rockchip_get_bootdev();
707*4882a593Smuzhiyun #else
708*4882a593Smuzhiyun 		dev_desc = NULL;
709*4882a593Smuzhiyun #endif
710*4882a593Smuzhiyun 		if (!dev_desc) {
711*4882a593Smuzhiyun 			fb_add_string(response, chars_left,
712*4882a593Smuzhiyun 				      "block device not found", NULL);
713*4882a593Smuzhiyun 			ret = -1;
714*4882a593Smuzhiyun 			break;
715*4882a593Smuzhiyun 		}
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun 		part_num = part_get_info_by_name(dev_desc, part_name,
718*4882a593Smuzhiyun 						 &part_info);
719*4882a593Smuzhiyun 		if (part_num < 0) {
720*4882a593Smuzhiyun 			fb_add_string(response, chars_left,
721*4882a593Smuzhiyun 				      "partition not found", NULL);
722*4882a593Smuzhiyun 			ret = -1;
723*4882a593Smuzhiyun 		} else if (!strncmp(PARTITION_TYPE_STRINGS, cmd,
724*4882a593Smuzhiyun 					strlen(PARTITION_TYPE_STRINGS))) {
725*4882a593Smuzhiyun 			if (fb_get_fstype("mmc", part_num, &fs_type)) {
726*4882a593Smuzhiyun 				fb_add_string(response, chars_left,
727*4882a593Smuzhiyun 					      (char *)part_info.type, NULL);
728*4882a593Smuzhiyun 			} else {
729*4882a593Smuzhiyun 				fb_add_string(response, chars_left,
730*4882a593Smuzhiyun 					      fs_type, NULL);
731*4882a593Smuzhiyun 			}
732*4882a593Smuzhiyun 		} else if (!strncmp("partition-size", cmd, 14)) {
733*4882a593Smuzhiyun 			u64 part_size;
734*4882a593Smuzhiyun 
735*4882a593Smuzhiyun 			part_size = (uint64_t)part_info.size;
736*4882a593Smuzhiyun 			snprintf(response, chars_left, "0x%llx",
737*4882a593Smuzhiyun 				 part_size * dev_desc->blksz);
738*4882a593Smuzhiyun 		}
739*4882a593Smuzhiyun #else
740*4882a593Smuzhiyun 		fb_add_string(response, chars_left, "not implemented", NULL);
741*4882a593Smuzhiyun 		ret = -1;
742*4882a593Smuzhiyun #endif
743*4882a593Smuzhiyun 		break;
744*4882a593Smuzhiyun 	}
745*4882a593Smuzhiyun 	case FB_BLK_SIZE: {
746*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
747*4882a593Smuzhiyun 		struct blk_desc *dev_desc;
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun #ifdef CONFIG_RKIMG_BOOTLOADER
750*4882a593Smuzhiyun 		dev_desc = rockchip_get_bootdev();
751*4882a593Smuzhiyun #else
752*4882a593Smuzhiyun 		dev_desc = NULL;
753*4882a593Smuzhiyun #endif
754*4882a593Smuzhiyun 		if (!dev_desc) {
755*4882a593Smuzhiyun 			fb_add_string(response, chars_left,
756*4882a593Smuzhiyun 				      "block device not found", NULL);
757*4882a593Smuzhiyun 			ret = -1;
758*4882a593Smuzhiyun 		} else {
759*4882a593Smuzhiyun 			fb_add_number(response, chars_left,
760*4882a593Smuzhiyun 				      "0x%lx", dev_desc->blksz);
761*4882a593Smuzhiyun 		}
762*4882a593Smuzhiyun #else
763*4882a593Smuzhiyun 		fb_add_string(response, chars_left, "not implemented", NULL);
764*4882a593Smuzhiyun 		ret = -1;
765*4882a593Smuzhiyun #endif
766*4882a593Smuzhiyun 		break;
767*4882a593Smuzhiyun 	}
768*4882a593Smuzhiyun 	case FB_ERASE_SIZE: {
769*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
770*4882a593Smuzhiyun 		lbaint_t erase_grp_size;
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun 		erase_grp_size = fb_mmc_get_erase_grp_size();
773*4882a593Smuzhiyun 		if (erase_grp_size < 0) {
774*4882a593Smuzhiyun 			fb_add_string(response, chars_left,
775*4882a593Smuzhiyun 				      "block device not found", NULL);
776*4882a593Smuzhiyun 			ret = -1;
777*4882a593Smuzhiyun 		} else {
778*4882a593Smuzhiyun 			fb_add_number(response, chars_left, "0x"LBAF"",
779*4882a593Smuzhiyun 				      erase_grp_size);
780*4882a593Smuzhiyun 		}
781*4882a593Smuzhiyun #else
782*4882a593Smuzhiyun 		fb_add_string(response, chars_left, "not implemented", NULL);
783*4882a593Smuzhiyun 		ret = -1;
784*4882a593Smuzhiyun #endif
785*4882a593Smuzhiyun 		break;
786*4882a593Smuzhiyun 	}
787*4882a593Smuzhiyun 	case FB_UNLOCKED: {
788*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
789*4882a593Smuzhiyun 		uint8_t flash_lock_state = 0;
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun 		if (rk_avb_read_flash_lock_state(&flash_lock_state))
792*4882a593Smuzhiyun 			fb_add_string(response, chars_left, "yes", NULL);
793*4882a593Smuzhiyun 		else
794*4882a593Smuzhiyun 			fb_add_string(response, chars_left, "no", NULL);
795*4882a593Smuzhiyun #else
796*4882a593Smuzhiyun 		fb_add_string(response, chars_left, "not implemented", NULL);
797*4882a593Smuzhiyun 		ret = -1;
798*4882a593Smuzhiyun #endif
799*4882a593Smuzhiyun 		break;
800*4882a593Smuzhiyun 	}
801*4882a593Smuzhiyun 	case  FB_OFF_MODE_CHARGE: {
802*4882a593Smuzhiyun 		fb_add_string(response, chars_left, "not implemented", NULL);
803*4882a593Smuzhiyun 		break;
804*4882a593Smuzhiyun 	}
805*4882a593Smuzhiyun 	case FB_BATT_VOLTAGE: {
806*4882a593Smuzhiyun 		fb_add_string(response, chars_left, "not implemented", NULL);
807*4882a593Smuzhiyun 		break;
808*4882a593Smuzhiyun 	}
809*4882a593Smuzhiyun 	case FB_BATT_SOC_OK: {
810*4882a593Smuzhiyun 		fb_add_string(response, chars_left, "no", NULL);
811*4882a593Smuzhiyun 		break;
812*4882a593Smuzhiyun 	}
813*4882a593Smuzhiyun 	case FB_IS_USERSPACE: {
814*4882a593Smuzhiyun 		fb_add_string(response, chars_left, "no", NULL);
815*4882a593Smuzhiyun 		break;
816*4882a593Smuzhiyun 	}
817*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
818*4882a593Smuzhiyun 	case FB_HAS_COUNT: {
819*4882a593Smuzhiyun 		char slot_count[2];
820*4882a593Smuzhiyun 		char temp;
821*4882a593Smuzhiyun 
822*4882a593Smuzhiyun 		slot_count[1] = '\0';
823*4882a593Smuzhiyun 		if (rk_avb_read_slot_count(&temp) < 0) {
824*4882a593Smuzhiyun 			fb_add_number(response, chars_left, "%d", 0);
825*4882a593Smuzhiyun 			ret = -1;
826*4882a593Smuzhiyun 			break;
827*4882a593Smuzhiyun 		}
828*4882a593Smuzhiyun 		slot_count[0] = temp + 0x30;
829*4882a593Smuzhiyun 		fb_add_string(response, chars_left, slot_count, NULL);
830*4882a593Smuzhiyun 		break;
831*4882a593Smuzhiyun 	}
832*4882a593Smuzhiyun 	case FB_HAS_SLOT: {
833*4882a593Smuzhiyun 		char *part_name = cmd;
834*4882a593Smuzhiyun 		int has_slot = -1;
835*4882a593Smuzhiyun 
836*4882a593Smuzhiyun 		cmd = strsep(&part_name, ":");
837*4882a593Smuzhiyun 		if (!cmd || !part_name) {
838*4882a593Smuzhiyun 			fb_add_string(response, chars_left,
839*4882a593Smuzhiyun 				      "argument Invalid!", NULL);
840*4882a593Smuzhiyun 			ret = -1;
841*4882a593Smuzhiyun 			break;
842*4882a593Smuzhiyun 		}
843*4882a593Smuzhiyun 
844*4882a593Smuzhiyun 		has_slot = rk_avb_get_part_has_slot_info(part_name);
845*4882a593Smuzhiyun 		if (has_slot < 0)
846*4882a593Smuzhiyun 			fb_add_string(response, chars_left, "no", NULL);
847*4882a593Smuzhiyun 		else
848*4882a593Smuzhiyun 			fb_add_string(response, chars_left, "yes", NULL);
849*4882a593Smuzhiyun 		break;
850*4882a593Smuzhiyun 	}
851*4882a593Smuzhiyun 	case FB_CURR_SLOT: {
852*4882a593Smuzhiyun 		char slot_surrent[8] = {0};
853*4882a593Smuzhiyun 
854*4882a593Smuzhiyun 		if (!rk_avb_get_current_slot(slot_surrent)) {
855*4882a593Smuzhiyun 			fb_add_string(response, chars_left,
856*4882a593Smuzhiyun 				      slot_surrent + 1, NULL);
857*4882a593Smuzhiyun 		} else {
858*4882a593Smuzhiyun 			fb_add_string(response, chars_left, "get error", NULL);
859*4882a593Smuzhiyun 			ret = -1;
860*4882a593Smuzhiyun 		}
861*4882a593Smuzhiyun 		break;
862*4882a593Smuzhiyun 	}
863*4882a593Smuzhiyun 	case FB_SLOT_SUFFIXES: {
864*4882a593Smuzhiyun 		char slot_suffixes_temp[4] = {0};
865*4882a593Smuzhiyun 		char slot_suffixes[9] = {0};
866*4882a593Smuzhiyun 		int slot_cnt = 0;
867*4882a593Smuzhiyun 
868*4882a593Smuzhiyun 		rk_avb_read_slot_suffixes(slot_suffixes_temp);
869*4882a593Smuzhiyun 		while (slot_suffixes_temp[slot_cnt] != '\0') {
870*4882a593Smuzhiyun 			slot_suffixes[slot_cnt * 2]
871*4882a593Smuzhiyun 				= slot_suffixes_temp[slot_cnt];
872*4882a593Smuzhiyun 			slot_suffixes[slot_cnt * 2 + 1] = ',';
873*4882a593Smuzhiyun 			slot_cnt++;
874*4882a593Smuzhiyun 		}
875*4882a593Smuzhiyun 
876*4882a593Smuzhiyun 		slot_suffixes[(slot_cnt - 1) * 2 + 1] = '\0';
877*4882a593Smuzhiyun 		fb_add_string(response, chars_left, slot_suffixes, NULL);
878*4882a593Smuzhiyun 		break;
879*4882a593Smuzhiyun 	}
880*4882a593Smuzhiyun 	case FB_SLOT_SUCCESSFUL:{
881*4882a593Smuzhiyun 		char *slot_name = cmd;
882*4882a593Smuzhiyun 		AvbABData ab_info;
883*4882a593Smuzhiyun 
884*4882a593Smuzhiyun 		cmd = strsep(&slot_name, ":");
885*4882a593Smuzhiyun 		if (!cmd || !slot_name) {
886*4882a593Smuzhiyun 			fb_add_string(response, chars_left,
887*4882a593Smuzhiyun 				      "argument Invalid!", NULL);
888*4882a593Smuzhiyun 			ret = -1;
889*4882a593Smuzhiyun 			break;
890*4882a593Smuzhiyun 		}
891*4882a593Smuzhiyun 
892*4882a593Smuzhiyun 		if (rk_avb_get_ab_info(&ab_info) < 0) {
893*4882a593Smuzhiyun 			fb_add_string(response, chars_left,
894*4882a593Smuzhiyun 				      "get ab info failed!", NULL);
895*4882a593Smuzhiyun 			ret = -1;
896*4882a593Smuzhiyun 			break;
897*4882a593Smuzhiyun 		}
898*4882a593Smuzhiyun 
899*4882a593Smuzhiyun 		if (!strcmp(slot_name, "a")) {
900*4882a593Smuzhiyun 			if (ab_info.slots[0].successful_boot)
901*4882a593Smuzhiyun 				fb_add_string(response, chars_left,
902*4882a593Smuzhiyun 					      "yes", NULL);
903*4882a593Smuzhiyun 			else
904*4882a593Smuzhiyun 				fb_add_string(response, chars_left,
905*4882a593Smuzhiyun 					      "no", NULL);
906*4882a593Smuzhiyun 		} else if (!strcmp(slot_name, "b")) {
907*4882a593Smuzhiyun 			if (ab_info.slots[1].successful_boot)
908*4882a593Smuzhiyun 				fb_add_string(response, chars_left,
909*4882a593Smuzhiyun 					      "yes", NULL);
910*4882a593Smuzhiyun 			else
911*4882a593Smuzhiyun 				fb_add_string(response, chars_left,
912*4882a593Smuzhiyun 					      "no", NULL);
913*4882a593Smuzhiyun 		} else {
914*4882a593Smuzhiyun 			fb_add_string(response, chars_left, "no", NULL);
915*4882a593Smuzhiyun 		}
916*4882a593Smuzhiyun 		break;
917*4882a593Smuzhiyun 	}
918*4882a593Smuzhiyun 	case FB_SLOT_UNBOOTABLE: {
919*4882a593Smuzhiyun 		char *slot_name = cmd;
920*4882a593Smuzhiyun 		AvbABData ab_info;
921*4882a593Smuzhiyun 
922*4882a593Smuzhiyun 		cmd = strsep(&slot_name, ":");
923*4882a593Smuzhiyun 
924*4882a593Smuzhiyun 		if (!cmd || !slot_name) {
925*4882a593Smuzhiyun 			fb_add_string(response, chars_left,
926*4882a593Smuzhiyun 				      "argument Invalid!", NULL);
927*4882a593Smuzhiyun 			ret = -1;
928*4882a593Smuzhiyun 			break;
929*4882a593Smuzhiyun 		}
930*4882a593Smuzhiyun 
931*4882a593Smuzhiyun 		if (rk_avb_get_ab_info(&ab_info) < 0) {
932*4882a593Smuzhiyun 			fb_add_string(response, chars_left,
933*4882a593Smuzhiyun 				      "get ab info failed!", NULL);
934*4882a593Smuzhiyun 			ret = -1;
935*4882a593Smuzhiyun 			break;
936*4882a593Smuzhiyun 		}
937*4882a593Smuzhiyun 
938*4882a593Smuzhiyun 		if (!strcmp(slot_name, "a")) {
939*4882a593Smuzhiyun 			if (!ab_info.slots[0].successful_boot &&
940*4882a593Smuzhiyun 			    !ab_info.slots[0].tries_remaining &&
941*4882a593Smuzhiyun 			    !ab_info.slots[0].priority)
942*4882a593Smuzhiyun 				fb_add_string(response, chars_left,
943*4882a593Smuzhiyun 					      "yes", NULL);
944*4882a593Smuzhiyun 			else
945*4882a593Smuzhiyun 				fb_add_string(response, chars_left, "no", NULL);
946*4882a593Smuzhiyun 		} else if (!strcmp(slot_name, "b")) {
947*4882a593Smuzhiyun 			if (!ab_info.slots[1].successful_boot &&
948*4882a593Smuzhiyun 			    !ab_info.slots[1].tries_remaining &&
949*4882a593Smuzhiyun 			    !ab_info.slots[1].priority)
950*4882a593Smuzhiyun 				fb_add_string(response, chars_left,
951*4882a593Smuzhiyun 					      "yes", NULL);
952*4882a593Smuzhiyun 			else
953*4882a593Smuzhiyun 				fb_add_string(response, chars_left, "no", NULL);
954*4882a593Smuzhiyun 		} else {
955*4882a593Smuzhiyun 			fb_add_string(response, chars_left, "no", NULL);
956*4882a593Smuzhiyun 		}
957*4882a593Smuzhiyun 		break;
958*4882a593Smuzhiyun 	}
959*4882a593Smuzhiyun 	case FB_SLOT_RETRY_COUNT: {
960*4882a593Smuzhiyun 		char *slot_name = cmd;
961*4882a593Smuzhiyun 		AvbABData ab_info;
962*4882a593Smuzhiyun 
963*4882a593Smuzhiyun 		cmd = strsep(&slot_name, ":");
964*4882a593Smuzhiyun 		if (!cmd || !slot_name) {
965*4882a593Smuzhiyun 			fb_add_string(response, chars_left,
966*4882a593Smuzhiyun 				      "argument Invalid!", NULL);
967*4882a593Smuzhiyun 			ret = -1;
968*4882a593Smuzhiyun 			break;
969*4882a593Smuzhiyun 		}
970*4882a593Smuzhiyun 
971*4882a593Smuzhiyun 		if (rk_avb_get_ab_info(&ab_info) < 0) {
972*4882a593Smuzhiyun 			fb_add_string(response, chars_left,
973*4882a593Smuzhiyun 				      "get ab info failed!", NULL);
974*4882a593Smuzhiyun 			ret = -1;
975*4882a593Smuzhiyun 			break;
976*4882a593Smuzhiyun 		}
977*4882a593Smuzhiyun 
978*4882a593Smuzhiyun 		if (!strcmp(slot_name, "a")) {
979*4882a593Smuzhiyun 			fb_add_number(response, chars_left,
980*4882a593Smuzhiyun 				      "%d", ab_info.slots[0].tries_remaining);
981*4882a593Smuzhiyun 		} else if (!strcmp(slot_name, "b")) {
982*4882a593Smuzhiyun 			fb_add_number(response, chars_left, "%d",
983*4882a593Smuzhiyun 				      ab_info.slots[1].tries_remaining);
984*4882a593Smuzhiyun 
985*4882a593Smuzhiyun 		} else {
986*4882a593Smuzhiyun 			strcpy(response, "FAILno");
987*4882a593Smuzhiyun 		}
988*4882a593Smuzhiyun 		break;
989*4882a593Smuzhiyun 	}
990*4882a593Smuzhiyun 	case FB_AT_VBST: {
991*4882a593Smuzhiyun 		char vbst[VBOOT_STATE_SIZE] = {0};
992*4882a593Smuzhiyun 		char *p_vbst;
993*4882a593Smuzhiyun 
994*4882a593Smuzhiyun 		strcpy(response, "INFO");
995*4882a593Smuzhiyun 		rk_avb_get_at_vboot_state(vbst);
996*4882a593Smuzhiyun 		p_vbst = vbst;
997*4882a593Smuzhiyun 		do {
998*4882a593Smuzhiyun 			cmd = strsep(&p_vbst, "\n");
999*4882a593Smuzhiyun 			if (strlen(cmd) > 0) {
1000*4882a593Smuzhiyun 				memcpy(&response[4], cmd, chars_left);
1001*4882a593Smuzhiyun 				fastboot_tx_write_str(response);
1002*4882a593Smuzhiyun 			}
1003*4882a593Smuzhiyun 		} while (strlen(cmd));
1004*4882a593Smuzhiyun 		break;
1005*4882a593Smuzhiyun 	}
1006*4882a593Smuzhiyun 	case FB_SNAPSHOT_STATUS: {
1007*4882a593Smuzhiyun #ifdef CONFIG_ANDROID_AB
1008*4882a593Smuzhiyun 		struct misc_virtual_ab_message state;
1009*4882a593Smuzhiyun 
1010*4882a593Smuzhiyun 		memset(&state, 0x0, sizeof(state));
1011*4882a593Smuzhiyun 		if (read_misc_virtual_ab_message(&state) != 0) {
1012*4882a593Smuzhiyun 			printf("FB_SNAPSHOT_STATUS read_misc_virtual_ab_message failed!\n");
1013*4882a593Smuzhiyun 			fb_add_string(response, chars_left, "get error", NULL);
1014*4882a593Smuzhiyun 			ret = -1;
1015*4882a593Smuzhiyun 		}
1016*4882a593Smuzhiyun 
1017*4882a593Smuzhiyun 		if (state.magic != MISC_VIRTUAL_AB_MAGIC_HEADER) {
1018*4882a593Smuzhiyun 			printf("FB_SNAPSHOT_STATUS not virtual A/B metadata!\n");
1019*4882a593Smuzhiyun 			fb_add_string(response, chars_left, "get error", NULL);
1020*4882a593Smuzhiyun 			ret = -1;
1021*4882a593Smuzhiyun 		}
1022*4882a593Smuzhiyun 
1023*4882a593Smuzhiyun 		if (state.merge_status == ENUM_MERGE_STATUS_MERGING) {
1024*4882a593Smuzhiyun 			fb_add_string(response, chars_left, "merging", NULL);
1025*4882a593Smuzhiyun 		} else if (state.merge_status == ENUM_MERGE_STATUS_SNAPSHOTTED) {
1026*4882a593Smuzhiyun 			fb_add_string(response, chars_left, "snapshotted", NULL);
1027*4882a593Smuzhiyun 		} else {
1028*4882a593Smuzhiyun 			fb_add_string(response, chars_left, "none", NULL);
1029*4882a593Smuzhiyun 		}
1030*4882a593Smuzhiyun #else
1031*4882a593Smuzhiyun 		fb_add_string(response, chars_left, "get error", NULL);
1032*4882a593Smuzhiyun 		ret = -1;
1033*4882a593Smuzhiyun #endif
1034*4882a593Smuzhiyun 		break;
1035*4882a593Smuzhiyun 	}
1036*4882a593Smuzhiyun 
1037*4882a593Smuzhiyun #endif
1038*4882a593Smuzhiyun #ifdef CONFIG_OPTEE_CLIENT
1039*4882a593Smuzhiyun 	case FB_AT_DH: {
1040*4882a593Smuzhiyun 		char dhbuf[ATTEST_DH_SIZE];
1041*4882a593Smuzhiyun 		uint32_t dh_len = ATTEST_DH_SIZE;
1042*4882a593Smuzhiyun 		uint32_t res = trusty_attest_dh((uint8_t *)dhbuf, &dh_len);
1043*4882a593Smuzhiyun 
1044*4882a593Smuzhiyun 		if (res) {
1045*4882a593Smuzhiyun 			fb_add_string(response, chars_left, "dh not set", NULL);
1046*4882a593Smuzhiyun 			ret = -1;
1047*4882a593Smuzhiyun 		} else {
1048*4882a593Smuzhiyun 			fb_add_string(response, chars_left, dhbuf, NULL);
1049*4882a593Smuzhiyun 		}
1050*4882a593Smuzhiyun 		break;
1051*4882a593Smuzhiyun 	}
1052*4882a593Smuzhiyun 	case FB_AT_UUID: {
1053*4882a593Smuzhiyun 		char uuid[ATTEST_UUID_SIZE] = {0};
1054*4882a593Smuzhiyun 		uint32_t uuid_len = ATTEST_UUID_SIZE;
1055*4882a593Smuzhiyun 		uint32_t res = trusty_attest_uuid((uint8_t *)uuid, &uuid_len);
1056*4882a593Smuzhiyun 
1057*4882a593Smuzhiyun 		uuid[ATTEST_UUID_SIZE - 1] = 0;
1058*4882a593Smuzhiyun 		if (res) {
1059*4882a593Smuzhiyun 			fb_add_string(response, chars_left, "dh not set", NULL);
1060*4882a593Smuzhiyun 			ret = -1;
1061*4882a593Smuzhiyun 		} else {
1062*4882a593Smuzhiyun 			fb_add_string(response, chars_left, uuid, NULL);
1063*4882a593Smuzhiyun 		}
1064*4882a593Smuzhiyun 		break;
1065*4882a593Smuzhiyun 	}
1066*4882a593Smuzhiyun #endif
1067*4882a593Smuzhiyun 	default: {
1068*4882a593Smuzhiyun 			char *envstr;
1069*4882a593Smuzhiyun 
1070*4882a593Smuzhiyun 			envstr = malloc(strlen("fastboot.") + strlen(cmd) + 1);
1071*4882a593Smuzhiyun 			if (!envstr) {
1072*4882a593Smuzhiyun 				fb_add_string(response, chars_left,
1073*4882a593Smuzhiyun 					      "malloc error", NULL);
1074*4882a593Smuzhiyun 				ret = -1;
1075*4882a593Smuzhiyun 				break;
1076*4882a593Smuzhiyun 			}
1077*4882a593Smuzhiyun 
1078*4882a593Smuzhiyun 			sprintf(envstr, "fastboot.%s", cmd);
1079*4882a593Smuzhiyun 			s = env_get(envstr);
1080*4882a593Smuzhiyun 			if (s) {
1081*4882a593Smuzhiyun 				strncat(response, s, chars_left);
1082*4882a593Smuzhiyun 			} else {
1083*4882a593Smuzhiyun 				printf("WARNING: unknown variable: %s\n", cmd);
1084*4882a593Smuzhiyun 				fb_add_string(response, chars_left,
1085*4882a593Smuzhiyun 					      "not implemented", NULL);
1086*4882a593Smuzhiyun 			}
1087*4882a593Smuzhiyun 
1088*4882a593Smuzhiyun 			free(envstr);
1089*4882a593Smuzhiyun 			break;
1090*4882a593Smuzhiyun 		}
1091*4882a593Smuzhiyun 	}
1092*4882a593Smuzhiyun 
1093*4882a593Smuzhiyun 	return ret;
1094*4882a593Smuzhiyun }
1095*4882a593Smuzhiyun 
1096*4882a593Smuzhiyun static const struct {
1097*4882a593Smuzhiyun 	/*
1098*4882a593Smuzhiyun 	 *any changes to this array require an update to the corresponding
1099*4882a593Smuzhiyun 	 *enum in fastboot.h
1100*4882a593Smuzhiyun 	 */
1101*4882a593Smuzhiyun 	struct name_string name;
1102*4882a593Smuzhiyun 	fb_getvar_t var;
1103*4882a593Smuzhiyun } getvar_table[] = {
1104*4882a593Smuzhiyun 	{ NAME_NO_ARGS("version"), FB_VERSION},
1105*4882a593Smuzhiyun 	{ NAME_NO_ARGS("version-bootloader"), FB_BOOTLOADER_VERSION},
1106*4882a593Smuzhiyun 	{ NAME_NO_ARGS("version-baseband"), FB_BASEBAND_VERSION},
1107*4882a593Smuzhiyun 	{ NAME_NO_ARGS("product"), FB_PRODUCT},
1108*4882a593Smuzhiyun 	{ NAME_NO_ARGS("serialno"), FB_SERIAL_NO},
1109*4882a593Smuzhiyun 	{ NAME_NO_ARGS("secure"), FB_SECURE},
1110*4882a593Smuzhiyun 	{ NAME_NO_ARGS("max-download-size"), FB_DWNLD_SIZE},
1111*4882a593Smuzhiyun 	{ NAME_NO_ARGS("logical-block-size"), FB_BLK_SIZE},
1112*4882a593Smuzhiyun 	{ NAME_NO_ARGS("erase-block-size"), FB_ERASE_SIZE},
1113*4882a593Smuzhiyun 	{ NAME_ARGS("partition-type", ':'), FB_PART_TYPE},
1114*4882a593Smuzhiyun 	{ NAME_ARGS("partition-size", ':'), FB_PART_SIZE},
1115*4882a593Smuzhiyun 	{ NAME_NO_ARGS("unlocked"), FB_UNLOCKED},
1116*4882a593Smuzhiyun 	{ NAME_NO_ARGS("off-mode-charge"), FB_OFF_MODE_CHARGE},
1117*4882a593Smuzhiyun 	{ NAME_NO_ARGS("battery-voltage"), FB_BATT_VOLTAGE},
1118*4882a593Smuzhiyun 	{ NAME_NO_ARGS("variant"), FB_VARIANT},
1119*4882a593Smuzhiyun 	{ NAME_NO_ARGS("battery-soc-ok"), FB_BATT_SOC_OK},
1120*4882a593Smuzhiyun 	{ NAME_NO_ARGS("is-userspace"), FB_IS_USERSPACE},
1121*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
1122*4882a593Smuzhiyun 	/* Slots related */
1123*4882a593Smuzhiyun 	{ NAME_NO_ARGS("slot-count"), FB_HAS_COUNT},
1124*4882a593Smuzhiyun 	{ NAME_ARGS("has-slot", ':'), FB_HAS_SLOT},
1125*4882a593Smuzhiyun 	{ NAME_NO_ARGS("current-slot"), FB_CURR_SLOT},
1126*4882a593Smuzhiyun 	{ NAME_NO_ARGS("slot-suffixes"), FB_SLOT_SUFFIXES},
1127*4882a593Smuzhiyun 	{ NAME_ARGS("slot-successful", ':'), FB_SLOT_SUCCESSFUL},
1128*4882a593Smuzhiyun 	{ NAME_ARGS("slot-unbootable", ':'), FB_SLOT_UNBOOTABLE},
1129*4882a593Smuzhiyun 	{ NAME_ARGS("slot-retry-count", ':'), FB_SLOT_RETRY_COUNT},
1130*4882a593Smuzhiyun 	{ NAME_NO_ARGS("at-vboot-state"), FB_AT_VBST},
1131*4882a593Smuzhiyun 	{ NAME_NO_ARGS("snapshot-update-status"), FB_SNAPSHOT_STATUS},
1132*4882a593Smuzhiyun #endif
1133*4882a593Smuzhiyun 	/*
1134*4882a593Smuzhiyun 	 * OEM specific :
1135*4882a593Smuzhiyun 	 * Spec says names starting with lowercase letter are reserved.
1136*4882a593Smuzhiyun 	 */
1137*4882a593Smuzhiyun #ifdef CONFIG_OPTEE_CLIENT
1138*4882a593Smuzhiyun 	{ NAME_NO_ARGS("at-attest-dh"), FB_AT_DH},
1139*4882a593Smuzhiyun 	{ NAME_NO_ARGS("at-attest-uuid"), FB_AT_UUID},
1140*4882a593Smuzhiyun #endif
1141*4882a593Smuzhiyun };
1142*4882a593Smuzhiyun 
fb_getvar_single(char * cmd,char * response,size_t chars_left)1143*4882a593Smuzhiyun static int fb_getvar_single(char *cmd, char *response, size_t chars_left)
1144*4882a593Smuzhiyun {
1145*4882a593Smuzhiyun 	int i;
1146*4882a593Smuzhiyun 	size_t match_len = 0;
1147*4882a593Smuzhiyun 	size_t len = strlen(cmd);
1148*4882a593Smuzhiyun 
1149*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(getvar_table); i++) {
1150*4882a593Smuzhiyun 		match_len = name_check_match(cmd, len, &getvar_table[i].name);
1151*4882a593Smuzhiyun 		if (match_len)
1152*4882a593Smuzhiyun 			break;
1153*4882a593Smuzhiyun 	}
1154*4882a593Smuzhiyun 
1155*4882a593Smuzhiyun 	if (match_len == 0) {
1156*4882a593Smuzhiyun 		fb_add_string(response, chars_left, "unknown variable", NULL);
1157*4882a593Smuzhiyun 		return -1;
1158*4882a593Smuzhiyun 	}
1159*4882a593Smuzhiyun 
1160*4882a593Smuzhiyun 	if (fb_read_var(cmd, response, getvar_table[i].var, chars_left) < 0)
1161*4882a593Smuzhiyun 		return -1;
1162*4882a593Smuzhiyun 
1163*4882a593Smuzhiyun 	return 0;
1164*4882a593Smuzhiyun }
1165*4882a593Smuzhiyun 
fb_getvar_all(void)1166*4882a593Smuzhiyun static void fb_getvar_all(void)
1167*4882a593Smuzhiyun {
1168*4882a593Smuzhiyun 	char response[FASTBOOT_RESPONSE_LEN] = {0};
1169*4882a593Smuzhiyun 	char resp_tmp[FASTBOOT_RESPONSE_LEN] = {0};
1170*4882a593Smuzhiyun 	char *actual_resp;
1171*4882a593Smuzhiyun 	size_t chars_left;
1172*4882a593Smuzhiyun 	int i, p;
1173*4882a593Smuzhiyun 	disk_partition_t part_info;
1174*4882a593Smuzhiyun 	struct blk_desc *dev_desc;
1175*4882a593Smuzhiyun 
1176*4882a593Smuzhiyun 	strcpy(response, "INFO");
1177*4882a593Smuzhiyun 	chars_left = sizeof(response) - strlen(response) - 1;
1178*4882a593Smuzhiyun 	actual_resp = response + strlen(response);
1179*4882a593Smuzhiyun 
1180*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(getvar_table); i++) {
1181*4882a593Smuzhiyun 		fb_getvar_t var = getvar_table[i].var;
1182*4882a593Smuzhiyun 
1183*4882a593Smuzhiyun 		switch (var) {
1184*4882a593Smuzhiyun 		case FB_PART_TYPE:
1185*4882a593Smuzhiyun 		case FB_PART_SIZE: {
1186*4882a593Smuzhiyun 			const char *fs_type = NULL;
1187*4882a593Smuzhiyun #ifdef CONFIG_RKIMG_BOOTLOADER
1188*4882a593Smuzhiyun 			dev_desc = rockchip_get_bootdev();
1189*4882a593Smuzhiyun #else
1190*4882a593Smuzhiyun 			dev_desc = NULL;
1191*4882a593Smuzhiyun #endif
1192*4882a593Smuzhiyun 			if (!dev_desc) {
1193*4882a593Smuzhiyun 				fb_add_string(actual_resp, chars_left,
1194*4882a593Smuzhiyun 					      "%s:block device not found",
1195*4882a593Smuzhiyun 					      getvar_table[i].name.str);
1196*4882a593Smuzhiyun 				fastboot_tx_write_str(response);
1197*4882a593Smuzhiyun 				break;
1198*4882a593Smuzhiyun 			}
1199*4882a593Smuzhiyun 
1200*4882a593Smuzhiyun 			for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
1201*4882a593Smuzhiyun 				if (part_get_info(dev_desc, p,
1202*4882a593Smuzhiyun 						  &part_info) < 0) {
1203*4882a593Smuzhiyun 					break;
1204*4882a593Smuzhiyun 				}
1205*4882a593Smuzhiyun 
1206*4882a593Smuzhiyun 				if (var == FB_PART_TYPE) {
1207*4882a593Smuzhiyun 					fs_type = NULL;
1208*4882a593Smuzhiyun 					if (fb_get_fstype("mmc", p,
1209*4882a593Smuzhiyun 							  &fs_type)) {
1210*4882a593Smuzhiyun 						fb_add_string(
1211*4882a593Smuzhiyun 							resp_tmp,
1212*4882a593Smuzhiyun 							FASTBOOT_RESPONSE_LEN,
1213*4882a593Smuzhiyun 							(char *)part_info.type,
1214*4882a593Smuzhiyun 							NULL);
1215*4882a593Smuzhiyun 					} else {
1216*4882a593Smuzhiyun 						fb_add_string(
1217*4882a593Smuzhiyun 							resp_tmp,
1218*4882a593Smuzhiyun 							FASTBOOT_RESPONSE_LEN,
1219*4882a593Smuzhiyun 							fs_type,
1220*4882a593Smuzhiyun 							NULL);
1221*4882a593Smuzhiyun 					}
1222*4882a593Smuzhiyun 
1223*4882a593Smuzhiyun 					snprintf(actual_resp,
1224*4882a593Smuzhiyun 						 chars_left,
1225*4882a593Smuzhiyun 						 "%s:%s:%s",
1226*4882a593Smuzhiyun 						 getvar_table[i].name.str,
1227*4882a593Smuzhiyun 						 part_info.name,
1228*4882a593Smuzhiyun 						 resp_tmp);
1229*4882a593Smuzhiyun 				} else {
1230*4882a593Smuzhiyun 					uint64_t part_size;
1231*4882a593Smuzhiyun 
1232*4882a593Smuzhiyun 					part_size = (uint64_t)part_info.size;
1233*4882a593Smuzhiyun 					snprintf(actual_resp,
1234*4882a593Smuzhiyun 						 chars_left,
1235*4882a593Smuzhiyun 						 "%s:%s:0x%llx",
1236*4882a593Smuzhiyun 						 getvar_table[i].name.str,
1237*4882a593Smuzhiyun 						 part_info.name,
1238*4882a593Smuzhiyun 						 part_size * dev_desc->blksz);
1239*4882a593Smuzhiyun 				}
1240*4882a593Smuzhiyun 				fastboot_tx_write_str(response);
1241*4882a593Smuzhiyun 			}
1242*4882a593Smuzhiyun 			break;
1243*4882a593Smuzhiyun 		}
1244*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
1245*4882a593Smuzhiyun 		case FB_HAS_SLOT: {
1246*4882a593Smuzhiyun 			uchar *ptr_name_tmp;
1247*4882a593Smuzhiyun 			char c = '_';
1248*4882a593Smuzhiyun 			int has_slot = -1;
1249*4882a593Smuzhiyun 
1250*4882a593Smuzhiyun #ifdef CONFIG_RKIMG_BOOTLOADER
1251*4882a593Smuzhiyun 			dev_desc = rockchip_get_bootdev();
1252*4882a593Smuzhiyun #else
1253*4882a593Smuzhiyun 			dev_desc = NULL;
1254*4882a593Smuzhiyun #endif
1255*4882a593Smuzhiyun 			if (!dev_desc) {
1256*4882a593Smuzhiyun 				fb_add_string(actual_resp, chars_left,
1257*4882a593Smuzhiyun 					      "%s:block device not found",
1258*4882a593Smuzhiyun 					      getvar_table[i].name.str);
1259*4882a593Smuzhiyun 				fastboot_tx_write_str(response);
1260*4882a593Smuzhiyun 				break;
1261*4882a593Smuzhiyun 			}
1262*4882a593Smuzhiyun 
1263*4882a593Smuzhiyun 			for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
1264*4882a593Smuzhiyun 				if (part_get_info(dev_desc, p,
1265*4882a593Smuzhiyun 						  &part_info) < 0) {
1266*4882a593Smuzhiyun 					break;
1267*4882a593Smuzhiyun 				} else {
1268*4882a593Smuzhiyun 					ptr_name_tmp = (uchar *)strrchr(
1269*4882a593Smuzhiyun 						(char *)part_info.name, c);
1270*4882a593Smuzhiyun 					if (ptr_name_tmp &&
1271*4882a593Smuzhiyun 					    part_info.name[ptr_name_tmp -
1272*4882a593Smuzhiyun 						part_info.name + 2] == '\0')
1273*4882a593Smuzhiyun 						fb_add_string(
1274*4882a593Smuzhiyun 							resp_tmp,
1275*4882a593Smuzhiyun 							ptr_name_tmp -
1276*4882a593Smuzhiyun 							part_info.name + 1,
1277*4882a593Smuzhiyun 							(char *)part_info.name,
1278*4882a593Smuzhiyun 							NULL);
1279*4882a593Smuzhiyun 					else
1280*4882a593Smuzhiyun 						strcpy(resp_tmp,
1281*4882a593Smuzhiyun 						       (char *)part_info.name);
1282*4882a593Smuzhiyun 
1283*4882a593Smuzhiyun 					has_slot = rk_avb_get_part_has_slot_info(
1284*4882a593Smuzhiyun 						resp_tmp);
1285*4882a593Smuzhiyun 					if (has_slot < 0) {
1286*4882a593Smuzhiyun 						snprintf(actual_resp,
1287*4882a593Smuzhiyun 							 chars_left,
1288*4882a593Smuzhiyun 							 "%s:%s:no",
1289*4882a593Smuzhiyun 							 getvar_table[i].name.str,
1290*4882a593Smuzhiyun 							 resp_tmp);
1291*4882a593Smuzhiyun 					} else {
1292*4882a593Smuzhiyun 						snprintf(actual_resp,
1293*4882a593Smuzhiyun 							 chars_left,
1294*4882a593Smuzhiyun 							 "%s:%s:yes",
1295*4882a593Smuzhiyun 							 getvar_table[i].name.str,
1296*4882a593Smuzhiyun 							 resp_tmp);
1297*4882a593Smuzhiyun 						p++;
1298*4882a593Smuzhiyun 					}
1299*4882a593Smuzhiyun 
1300*4882a593Smuzhiyun 					fastboot_tx_write_str(response);
1301*4882a593Smuzhiyun 				}
1302*4882a593Smuzhiyun 			}
1303*4882a593Smuzhiyun 			break;
1304*4882a593Smuzhiyun 		}
1305*4882a593Smuzhiyun 
1306*4882a593Smuzhiyun 		case FB_SLOT_SUCCESSFUL: {
1307*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
1308*4882a593Smuzhiyun 			AvbABData ab_info;
1309*4882a593Smuzhiyun 
1310*4882a593Smuzhiyun 			if (rk_avb_get_ab_info(&ab_info) < 0) {
1311*4882a593Smuzhiyun 				fb_add_string(actual_resp,
1312*4882a593Smuzhiyun 					      chars_left,
1313*4882a593Smuzhiyun 					      "%s:get ab info failed!",
1314*4882a593Smuzhiyun 					      getvar_table[i].name.str);
1315*4882a593Smuzhiyun 				fastboot_tx_write_str(response);
1316*4882a593Smuzhiyun 				break;
1317*4882a593Smuzhiyun 			}
1318*4882a593Smuzhiyun 
1319*4882a593Smuzhiyun 			if (ab_info.slots[0].successful_boot)
1320*4882a593Smuzhiyun 				fb_add_string(actual_resp, chars_left,
1321*4882a593Smuzhiyun 					      "%s:a:yes",
1322*4882a593Smuzhiyun 					      getvar_table[i].name.str);
1323*4882a593Smuzhiyun 			else
1324*4882a593Smuzhiyun 				fb_add_string(actual_resp, chars_left,
1325*4882a593Smuzhiyun 					      "%s:a:no",
1326*4882a593Smuzhiyun 					      getvar_table[i].name.str);
1327*4882a593Smuzhiyun 			fastboot_tx_write_str(response);
1328*4882a593Smuzhiyun 
1329*4882a593Smuzhiyun 			if (ab_info.slots[1].successful_boot)
1330*4882a593Smuzhiyun 				fb_add_string(actual_resp, chars_left,
1331*4882a593Smuzhiyun 					      "%s:b:yes",
1332*4882a593Smuzhiyun 					      getvar_table[i].name.str);
1333*4882a593Smuzhiyun 			else
1334*4882a593Smuzhiyun 				fb_add_string(actual_resp, chars_left,
1335*4882a593Smuzhiyun 					      "%s:b:no",
1336*4882a593Smuzhiyun 					      getvar_table[i].name.str);
1337*4882a593Smuzhiyun 			fastboot_tx_write_str(response);
1338*4882a593Smuzhiyun #else
1339*4882a593Smuzhiyun 			fb_add_string(actual_resp, chars_left,
1340*4882a593Smuzhiyun 				      "%s:not find ab info!",
1341*4882a593Smuzhiyun 				      getvar_table[i].name.str);
1342*4882a593Smuzhiyun 			fastboot_tx_write_str(response);
1343*4882a593Smuzhiyun #endif
1344*4882a593Smuzhiyun 			break;
1345*4882a593Smuzhiyun 		}
1346*4882a593Smuzhiyun 
1347*4882a593Smuzhiyun 		case FB_SLOT_UNBOOTABLE: {
1348*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
1349*4882a593Smuzhiyun 			AvbABData ab_info;
1350*4882a593Smuzhiyun 
1351*4882a593Smuzhiyun 			if (rk_avb_get_ab_info(&ab_info) < 0) {
1352*4882a593Smuzhiyun 				fb_add_string(actual_resp, chars_left,
1353*4882a593Smuzhiyun 					      "%s:not find ab info!",
1354*4882a593Smuzhiyun 					      getvar_table[i].name.str);
1355*4882a593Smuzhiyun 				fastboot_tx_write_str(response);
1356*4882a593Smuzhiyun 				break;
1357*4882a593Smuzhiyun 			}
1358*4882a593Smuzhiyun 
1359*4882a593Smuzhiyun 			if (!ab_info.slots[0].successful_boot &&
1360*4882a593Smuzhiyun 			    !ab_info.slots[0].tries_remaining &&
1361*4882a593Smuzhiyun 			    !ab_info.slots[0].priority)
1362*4882a593Smuzhiyun 				fb_add_string(actual_resp, chars_left,
1363*4882a593Smuzhiyun 					      "%s:a:yes",
1364*4882a593Smuzhiyun 					      getvar_table[i].name.str);
1365*4882a593Smuzhiyun 			else
1366*4882a593Smuzhiyun 				fb_add_string(actual_resp, chars_left,
1367*4882a593Smuzhiyun 					      "%s:a:no",
1368*4882a593Smuzhiyun 					      getvar_table[i].name.str);
1369*4882a593Smuzhiyun 			fastboot_tx_write_str(response);
1370*4882a593Smuzhiyun 
1371*4882a593Smuzhiyun 			if (!ab_info.slots[1].successful_boot &&
1372*4882a593Smuzhiyun 			    !ab_info.slots[1].tries_remaining &&
1373*4882a593Smuzhiyun 			    !ab_info.slots[1].priority)
1374*4882a593Smuzhiyun 				fb_add_string(actual_resp, chars_left,
1375*4882a593Smuzhiyun 					      "%s:b:yes",
1376*4882a593Smuzhiyun 					      getvar_table[i].name.str);
1377*4882a593Smuzhiyun 			else
1378*4882a593Smuzhiyun 				fb_add_string(actual_resp, chars_left,
1379*4882a593Smuzhiyun 					      "%s:b:no",
1380*4882a593Smuzhiyun 					      getvar_table[i].name.str);
1381*4882a593Smuzhiyun 
1382*4882a593Smuzhiyun 			fastboot_tx_write_str(response);
1383*4882a593Smuzhiyun #else
1384*4882a593Smuzhiyun 			fb_add_string(actual_resp, chars_left,
1385*4882a593Smuzhiyun 				      "%s:not find ab info!",
1386*4882a593Smuzhiyun 				      getvar_table[i].name.str);
1387*4882a593Smuzhiyun 			fastboot_tx_write_str(response);
1388*4882a593Smuzhiyun #endif
1389*4882a593Smuzhiyun 			break;
1390*4882a593Smuzhiyun 		}
1391*4882a593Smuzhiyun 
1392*4882a593Smuzhiyun 		case FB_SLOT_RETRY_COUNT: {
1393*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
1394*4882a593Smuzhiyun 			AvbABData ab_info;
1395*4882a593Smuzhiyun 
1396*4882a593Smuzhiyun 			if (rk_avb_get_ab_info(&ab_info) < 0) {
1397*4882a593Smuzhiyun 				fb_add_string(actual_resp, chars_left,
1398*4882a593Smuzhiyun 					      "%s:not find ab info!",
1399*4882a593Smuzhiyun 					      getvar_table[i].name.str);
1400*4882a593Smuzhiyun 				fastboot_tx_write_str(response);
1401*4882a593Smuzhiyun 				break;
1402*4882a593Smuzhiyun 			}
1403*4882a593Smuzhiyun 
1404*4882a593Smuzhiyun 			snprintf(actual_resp, chars_left, "%s:a:%d",
1405*4882a593Smuzhiyun 				 getvar_table[i].name.str,
1406*4882a593Smuzhiyun 				 ab_info.slots[1].tries_remaining);
1407*4882a593Smuzhiyun 			fastboot_tx_write_str(response);
1408*4882a593Smuzhiyun 			snprintf(actual_resp, chars_left, "%s:b:%d",
1409*4882a593Smuzhiyun 				 getvar_table[i].name.str,
1410*4882a593Smuzhiyun 				 ab_info.slots[1].tries_remaining);
1411*4882a593Smuzhiyun 			fastboot_tx_write_str(response);
1412*4882a593Smuzhiyun #else
1413*4882a593Smuzhiyun 			fb_add_string(actual_resp, chars_left,
1414*4882a593Smuzhiyun 				      "%s:not find ab info!",
1415*4882a593Smuzhiyun 				      getvar_table[i].name.str);
1416*4882a593Smuzhiyun 			fastboot_tx_write_str(response);
1417*4882a593Smuzhiyun #endif
1418*4882a593Smuzhiyun 			break;
1419*4882a593Smuzhiyun 		}
1420*4882a593Smuzhiyun #endif
1421*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
1422*4882a593Smuzhiyun 		case FB_AT_VBST:
1423*4882a593Smuzhiyun 			break;
1424*4882a593Smuzhiyun #endif
1425*4882a593Smuzhiyun 		default:
1426*4882a593Smuzhiyun 			fb_getvar_single((char *)getvar_table[i].name.str,
1427*4882a593Smuzhiyun 					 resp_tmp, FASTBOOT_RESPONSE_LEN);
1428*4882a593Smuzhiyun 			snprintf(actual_resp, chars_left, "%s:%s",
1429*4882a593Smuzhiyun 				 getvar_table[i].name.str, resp_tmp);
1430*4882a593Smuzhiyun 			fastboot_tx_write_str(response);
1431*4882a593Smuzhiyun 		}
1432*4882a593Smuzhiyun 	}
1433*4882a593Smuzhiyun }
1434*4882a593Smuzhiyun 
1435*4882a593Smuzhiyun #ifdef CONFIG_ANDROID_AB
get_current_slot(void)1436*4882a593Smuzhiyun static int get_current_slot(void)
1437*4882a593Smuzhiyun {
1438*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
1439*4882a593Smuzhiyun 	char cmd[8] = {0};
1440*4882a593Smuzhiyun 	unsigned int slot_number = -1;
1441*4882a593Smuzhiyun 
1442*4882a593Smuzhiyun 	memset(cmd, 0x0, sizeof(cmd));
1443*4882a593Smuzhiyun 	rk_avb_get_current_slot(cmd);
1444*4882a593Smuzhiyun 	if (strncmp("_a", cmd, 2) == 0) {
1445*4882a593Smuzhiyun 		slot_number = 0;
1446*4882a593Smuzhiyun 	} else if (strncmp("_b", cmd, 2) == 0) {
1447*4882a593Smuzhiyun 		slot_number = 1;
1448*4882a593Smuzhiyun 	} else {
1449*4882a593Smuzhiyun 		pr_err("%s: FAILunkown slot name\n", __func__);
1450*4882a593Smuzhiyun 		return -1;
1451*4882a593Smuzhiyun 	}
1452*4882a593Smuzhiyun 
1453*4882a593Smuzhiyun 	return slot_number;
1454*4882a593Smuzhiyun #else
1455*4882a593Smuzhiyun 	pr_err("%s: FAILnot implemented\n", __func__);
1456*4882a593Smuzhiyun 	return -1;
1457*4882a593Smuzhiyun #endif
1458*4882a593Smuzhiyun }
1459*4882a593Smuzhiyun 
1460*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_FLASH
should_prevent_userdata_wipe(void)1461*4882a593Smuzhiyun static int should_prevent_userdata_wipe(void)
1462*4882a593Smuzhiyun {
1463*4882a593Smuzhiyun 	struct misc_virtual_ab_message state;
1464*4882a593Smuzhiyun 
1465*4882a593Smuzhiyun 	memset(&state, 0x0, sizeof(state));
1466*4882a593Smuzhiyun 	if (read_misc_virtual_ab_message(&state) != 0) {
1467*4882a593Smuzhiyun 		pr_err("%s: read_misc_virtual_ab_message failed!\n", __func__);
1468*4882a593Smuzhiyun 		return 0;
1469*4882a593Smuzhiyun 	}
1470*4882a593Smuzhiyun 
1471*4882a593Smuzhiyun 	if (state.magic != MISC_VIRTUAL_AB_MAGIC_HEADER) {
1472*4882a593Smuzhiyun 		pr_err("%s: NOT virtual A/B metadata!\n", __func__);
1473*4882a593Smuzhiyun 		return 0;
1474*4882a593Smuzhiyun 	}
1475*4882a593Smuzhiyun 
1476*4882a593Smuzhiyun 	if (state.merge_status == (uint8_t)ENUM_MERGE_STATUS_MERGING ||
1477*4882a593Smuzhiyun 		(state.merge_status == (uint8_t)ENUM_MERGE_STATUS_SNAPSHOTTED &&
1478*4882a593Smuzhiyun 		state.source_slot != get_current_slot())) {
1479*4882a593Smuzhiyun 		return 1;
1480*4882a593Smuzhiyun 	}
1481*4882a593Smuzhiyun 
1482*4882a593Smuzhiyun 	return 0;
1483*4882a593Smuzhiyun }
1484*4882a593Smuzhiyun #endif
1485*4882a593Smuzhiyun 
get_virtual_ab_merge_status(void)1486*4882a593Smuzhiyun static int get_virtual_ab_merge_status(void)
1487*4882a593Smuzhiyun {
1488*4882a593Smuzhiyun 	struct misc_virtual_ab_message state;
1489*4882a593Smuzhiyun 
1490*4882a593Smuzhiyun 	memset(&state, 0x0, sizeof(state));
1491*4882a593Smuzhiyun 	if (read_misc_virtual_ab_message(&state) != 0) {
1492*4882a593Smuzhiyun 		pr_err("%s: read_misc_virtual_ab_message failed!\n", __func__);
1493*4882a593Smuzhiyun 		return -1;
1494*4882a593Smuzhiyun 	}
1495*4882a593Smuzhiyun 
1496*4882a593Smuzhiyun 	if (state.magic != MISC_VIRTUAL_AB_MAGIC_HEADER) {
1497*4882a593Smuzhiyun 		pr_err("%s: NOT virtual A/B metadata!\n", __func__);
1498*4882a593Smuzhiyun 		return -1;
1499*4882a593Smuzhiyun 	}
1500*4882a593Smuzhiyun 
1501*4882a593Smuzhiyun 	return state.merge_status;
1502*4882a593Smuzhiyun }
1503*4882a593Smuzhiyun #endif
1504*4882a593Smuzhiyun 
cb_getvar(struct usb_ep * ep,struct usb_request * req)1505*4882a593Smuzhiyun static void cb_getvar(struct usb_ep *ep, struct usb_request *req)
1506*4882a593Smuzhiyun {
1507*4882a593Smuzhiyun 	char *cmd = req->buf;
1508*4882a593Smuzhiyun 	char response[FASTBOOT_RESPONSE_LEN] = {0};
1509*4882a593Smuzhiyun 	const char *str_read_all = "all";
1510*4882a593Smuzhiyun 	size_t len = 0;
1511*4882a593Smuzhiyun 	size_t chars_left;
1512*4882a593Smuzhiyun 
1513*4882a593Smuzhiyun 	strsep(&cmd, ":");
1514*4882a593Smuzhiyun 	if (!cmd) {
1515*4882a593Smuzhiyun 		pr_err("missing variable");
1516*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILmissing var");
1517*4882a593Smuzhiyun 		return;
1518*4882a593Smuzhiyun 	}
1519*4882a593Smuzhiyun 
1520*4882a593Smuzhiyun 	len = strlen(cmd);
1521*4882a593Smuzhiyun 	if (len == strlen(str_read_all) &&
1522*4882a593Smuzhiyun 	    (strncmp(cmd, str_read_all, len) == 0)) {
1523*4882a593Smuzhiyun 		fb_getvar_all();
1524*4882a593Smuzhiyun 		fastboot_tx_write_str("OKAYDone!");
1525*4882a593Smuzhiyun 	} else {
1526*4882a593Smuzhiyun 		strcpy(response, "OKAY");
1527*4882a593Smuzhiyun 		chars_left = sizeof(response) - strlen(response) - 1;
1528*4882a593Smuzhiyun 
1529*4882a593Smuzhiyun 		if (fb_getvar_single(cmd, &response[strlen(response)],
1530*4882a593Smuzhiyun 				     chars_left) < 0) {
1531*4882a593Smuzhiyun 			strcpy(cmd, "FAILunknown variable");
1532*4882a593Smuzhiyun 			strncat(cmd, &response[strlen(response)], chars_left);
1533*4882a593Smuzhiyun 			fastboot_tx_write_str(cmd);
1534*4882a593Smuzhiyun 			return;
1535*4882a593Smuzhiyun 		}
1536*4882a593Smuzhiyun 		fastboot_tx_write_str(response);
1537*4882a593Smuzhiyun 	}
1538*4882a593Smuzhiyun 
1539*4882a593Smuzhiyun 	return;
1540*4882a593Smuzhiyun }
1541*4882a593Smuzhiyun 
rx_bytes_expected(struct usb_ep * ep)1542*4882a593Smuzhiyun static unsigned int rx_bytes_expected(struct usb_ep *ep)
1543*4882a593Smuzhiyun {
1544*4882a593Smuzhiyun 	int rx_remain = download_size - download_bytes;
1545*4882a593Smuzhiyun 	unsigned int rem;
1546*4882a593Smuzhiyun 	unsigned int maxpacket = ep->maxpacket;
1547*4882a593Smuzhiyun 
1548*4882a593Smuzhiyun 	if (rx_remain <= 0)
1549*4882a593Smuzhiyun 		return 0;
1550*4882a593Smuzhiyun 	else if (rx_remain > EP_BUFFER_SIZE)
1551*4882a593Smuzhiyun 		return EP_BUFFER_SIZE;
1552*4882a593Smuzhiyun 
1553*4882a593Smuzhiyun 	/*
1554*4882a593Smuzhiyun 	 * Some controllers e.g. DWC3 don't like OUT transfers to be
1555*4882a593Smuzhiyun 	 * not ending in maxpacket boundary. So just make them happy by
1556*4882a593Smuzhiyun 	 * always requesting for integral multiple of maxpackets.
1557*4882a593Smuzhiyun 	 * This shouldn't bother controllers that don't care about it.
1558*4882a593Smuzhiyun 	 */
1559*4882a593Smuzhiyun 	rem = rx_remain % maxpacket;
1560*4882a593Smuzhiyun 	if (rem > 0)
1561*4882a593Smuzhiyun 		rx_remain = rx_remain + (maxpacket - rem);
1562*4882a593Smuzhiyun 
1563*4882a593Smuzhiyun 	return rx_remain;
1564*4882a593Smuzhiyun }
1565*4882a593Smuzhiyun 
1566*4882a593Smuzhiyun #define BYTES_PER_DOT	0x20000
rx_handler_dl_image(struct usb_ep * ep,struct usb_request * req)1567*4882a593Smuzhiyun static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
1568*4882a593Smuzhiyun {
1569*4882a593Smuzhiyun 	char response[FASTBOOT_RESPONSE_LEN];
1570*4882a593Smuzhiyun 	unsigned int transfer_size = download_size - download_bytes;
1571*4882a593Smuzhiyun 	const unsigned char *buffer = req->buf;
1572*4882a593Smuzhiyun 	unsigned int buffer_size = req->actual;
1573*4882a593Smuzhiyun 	unsigned int pre_dot_num, now_dot_num;
1574*4882a593Smuzhiyun 
1575*4882a593Smuzhiyun 	if (req->status != 0) {
1576*4882a593Smuzhiyun 		printf("Bad status: %d\n", req->status);
1577*4882a593Smuzhiyun 		return;
1578*4882a593Smuzhiyun 	}
1579*4882a593Smuzhiyun 
1580*4882a593Smuzhiyun 	if (buffer_size < transfer_size)
1581*4882a593Smuzhiyun 		transfer_size = buffer_size;
1582*4882a593Smuzhiyun 
1583*4882a593Smuzhiyun 	memcpy((void *)CONFIG_FASTBOOT_BUF_ADDR + download_bytes,
1584*4882a593Smuzhiyun 	       buffer, transfer_size);
1585*4882a593Smuzhiyun 
1586*4882a593Smuzhiyun 	pre_dot_num = download_bytes / BYTES_PER_DOT;
1587*4882a593Smuzhiyun 	download_bytes += transfer_size;
1588*4882a593Smuzhiyun 	now_dot_num = download_bytes / BYTES_PER_DOT;
1589*4882a593Smuzhiyun 
1590*4882a593Smuzhiyun 	if (pre_dot_num != now_dot_num) {
1591*4882a593Smuzhiyun 		putc('.');
1592*4882a593Smuzhiyun 		if (!(now_dot_num % 74))
1593*4882a593Smuzhiyun 			putc('\n');
1594*4882a593Smuzhiyun 	}
1595*4882a593Smuzhiyun 
1596*4882a593Smuzhiyun 	/* Check if transfer is done */
1597*4882a593Smuzhiyun 	if (download_bytes >= download_size) {
1598*4882a593Smuzhiyun 		/*
1599*4882a593Smuzhiyun 		 * Reset global transfer variable, keep download_bytes because
1600*4882a593Smuzhiyun 		 * it will be used in the next possible flashing command
1601*4882a593Smuzhiyun 		 */
1602*4882a593Smuzhiyun 		download_size = 0;
1603*4882a593Smuzhiyun 		req->complete = rx_handler_command;
1604*4882a593Smuzhiyun 		req->length = EP_BUFFER_SIZE;
1605*4882a593Smuzhiyun 
1606*4882a593Smuzhiyun 		strcpy(response, "OKAY");
1607*4882a593Smuzhiyun 		fastboot_tx_write_str(response);
1608*4882a593Smuzhiyun 
1609*4882a593Smuzhiyun 		printf("\ndownloading of %d bytes finished\n", download_bytes);
1610*4882a593Smuzhiyun 	} else {
1611*4882a593Smuzhiyun 		req->length = rx_bytes_expected(ep);
1612*4882a593Smuzhiyun 	}
1613*4882a593Smuzhiyun 
1614*4882a593Smuzhiyun 	req->actual = 0;
1615*4882a593Smuzhiyun 	usb_ep_queue(ep, req, 0);
1616*4882a593Smuzhiyun }
1617*4882a593Smuzhiyun 
cb_download(struct usb_ep * ep,struct usb_request * req)1618*4882a593Smuzhiyun static void cb_download(struct usb_ep *ep, struct usb_request *req)
1619*4882a593Smuzhiyun {
1620*4882a593Smuzhiyun 	char *cmd = req->buf;
1621*4882a593Smuzhiyun 	char response[FASTBOOT_RESPONSE_LEN];
1622*4882a593Smuzhiyun 
1623*4882a593Smuzhiyun 	strsep(&cmd, ":");
1624*4882a593Smuzhiyun 	download_size = simple_strtoul(cmd, NULL, 16);
1625*4882a593Smuzhiyun 	download_bytes = 0;
1626*4882a593Smuzhiyun 
1627*4882a593Smuzhiyun 	printf("Starting download of %d bytes\n", download_size);
1628*4882a593Smuzhiyun 
1629*4882a593Smuzhiyun 	if (0 == download_size) {
1630*4882a593Smuzhiyun 		strcpy(response, "FAILdata invalid size");
1631*4882a593Smuzhiyun 	} else if (download_size > CONFIG_FASTBOOT_BUF_SIZE) {
1632*4882a593Smuzhiyun 		download_size = 0;
1633*4882a593Smuzhiyun 		strcpy(response, "FAILdata too large");
1634*4882a593Smuzhiyun 	} else {
1635*4882a593Smuzhiyun 		sprintf(response, "DATA%08x", download_size);
1636*4882a593Smuzhiyun 		req->complete = rx_handler_dl_image;
1637*4882a593Smuzhiyun 		req->length = rx_bytes_expected(ep);
1638*4882a593Smuzhiyun 	}
1639*4882a593Smuzhiyun 
1640*4882a593Smuzhiyun 	fastboot_tx_write_str(response);
1641*4882a593Smuzhiyun }
1642*4882a593Smuzhiyun 
tx_handler_ul(struct usb_ep * ep,struct usb_request * req)1643*4882a593Smuzhiyun static void tx_handler_ul(struct usb_ep *ep, struct usb_request *req)
1644*4882a593Smuzhiyun {
1645*4882a593Smuzhiyun 	unsigned int xfer_size = 0;
1646*4882a593Smuzhiyun 	unsigned int pre_dot_num, now_dot_num;
1647*4882a593Smuzhiyun 	unsigned int remain_size = 0;
1648*4882a593Smuzhiyun 	unsigned int transferred_size = req->actual;
1649*4882a593Smuzhiyun 
1650*4882a593Smuzhiyun 	if (req->status != 0) {
1651*4882a593Smuzhiyun 		printf("Bad status: %d\n", req->status);
1652*4882a593Smuzhiyun 		return;
1653*4882a593Smuzhiyun 	}
1654*4882a593Smuzhiyun 
1655*4882a593Smuzhiyun 	if (start_upload) {
1656*4882a593Smuzhiyun 		pre_dot_num = upload_bytes / BYTES_PER_DOT;
1657*4882a593Smuzhiyun 		upload_bytes += transferred_size;
1658*4882a593Smuzhiyun 		now_dot_num = upload_bytes / BYTES_PER_DOT;
1659*4882a593Smuzhiyun 
1660*4882a593Smuzhiyun 		if (pre_dot_num != now_dot_num) {
1661*4882a593Smuzhiyun 			putc('.');
1662*4882a593Smuzhiyun 			if (!(now_dot_num % 74))
1663*4882a593Smuzhiyun 				putc('\n');
1664*4882a593Smuzhiyun 		}
1665*4882a593Smuzhiyun 	}
1666*4882a593Smuzhiyun 
1667*4882a593Smuzhiyun 	remain_size = upload_size - upload_bytes;
1668*4882a593Smuzhiyun 	xfer_size = (remain_size > EP_BUFFER_SIZE) ?
1669*4882a593Smuzhiyun 		    EP_BUFFER_SIZE : remain_size;
1670*4882a593Smuzhiyun 
1671*4882a593Smuzhiyun 	debug("%s: remain_size=%d, transferred_size=%d",
1672*4882a593Smuzhiyun 	      __func__, remain_size, transferred_size);
1673*4882a593Smuzhiyun 	debug("xfer_size=%d, upload_bytes=%d, upload_size=%d!\n",
1674*4882a593Smuzhiyun 	      xfer_size, upload_bytes, upload_size);
1675*4882a593Smuzhiyun 
1676*4882a593Smuzhiyun 	if (remain_size <= 0) {
1677*4882a593Smuzhiyun 		fastboot_func->in_req->complete = fastboot_complete;
1678*4882a593Smuzhiyun 		wakeup_thread();
1679*4882a593Smuzhiyun 		fastboot_tx_write_str("OKAY");
1680*4882a593Smuzhiyun 		printf("\nuploading of %d bytes finished\n", upload_bytes);
1681*4882a593Smuzhiyun 		upload_bytes = 0;
1682*4882a593Smuzhiyun 		upload_size = 0;
1683*4882a593Smuzhiyun 		start_upload = false;
1684*4882a593Smuzhiyun 		return;
1685*4882a593Smuzhiyun 	}
1686*4882a593Smuzhiyun 
1687*4882a593Smuzhiyun 	/* Remove the transfer callback which response the upload */
1688*4882a593Smuzhiyun 	/* request from host */
1689*4882a593Smuzhiyun 	if (!upload_bytes)
1690*4882a593Smuzhiyun 		start_upload = true;
1691*4882a593Smuzhiyun 
1692*4882a593Smuzhiyun 	fastboot_tx_write((char *)((phys_addr_t)CONFIG_FASTBOOT_BUF_ADDR + \
1693*4882a593Smuzhiyun 			  upload_bytes),
1694*4882a593Smuzhiyun 			  xfer_size);
1695*4882a593Smuzhiyun }
1696*4882a593Smuzhiyun 
cb_upload(struct usb_ep * ep,struct usb_request * req)1697*4882a593Smuzhiyun static void cb_upload(struct usb_ep *ep, struct usb_request *req)
1698*4882a593Smuzhiyun {
1699*4882a593Smuzhiyun 	char response[FASTBOOT_RESPONSE_LEN];
1700*4882a593Smuzhiyun 
1701*4882a593Smuzhiyun 	printf("Starting upload of %d bytes\n", upload_size);
1702*4882a593Smuzhiyun 
1703*4882a593Smuzhiyun 	if (0 == upload_size) {
1704*4882a593Smuzhiyun 		strcpy(response, "FAILdata invalid size");
1705*4882a593Smuzhiyun 	} else {
1706*4882a593Smuzhiyun 		start_upload = false;
1707*4882a593Smuzhiyun 		sprintf(response, "DATA%08x", upload_size);
1708*4882a593Smuzhiyun 		fastboot_func->in_req->complete = tx_handler_ul;
1709*4882a593Smuzhiyun 	}
1710*4882a593Smuzhiyun 
1711*4882a593Smuzhiyun 	fastboot_tx_write_str(response);
1712*4882a593Smuzhiyun }
1713*4882a593Smuzhiyun 
do_bootm_on_complete(struct usb_ep * ep,struct usb_request * req)1714*4882a593Smuzhiyun static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req)
1715*4882a593Smuzhiyun {
1716*4882a593Smuzhiyun 	char boot_addr_start[12];
1717*4882a593Smuzhiyun 	char *bootm_args[] = { "bootm", boot_addr_start, NULL };
1718*4882a593Smuzhiyun 
1719*4882a593Smuzhiyun 	puts("Booting kernel..\n");
1720*4882a593Smuzhiyun 
1721*4882a593Smuzhiyun 	sprintf(boot_addr_start, "0x%lx", (long)CONFIG_FASTBOOT_BUF_ADDR);
1722*4882a593Smuzhiyun 	do_bootm(NULL, 0, 2, bootm_args);
1723*4882a593Smuzhiyun 
1724*4882a593Smuzhiyun 	/* This only happens if image is somehow faulty so we start over */
1725*4882a593Smuzhiyun 	do_reset(NULL, 0, 0, NULL);
1726*4882a593Smuzhiyun }
1727*4882a593Smuzhiyun 
cb_boot(struct usb_ep * ep,struct usb_request * req)1728*4882a593Smuzhiyun static void cb_boot(struct usb_ep *ep, struct usb_request *req)
1729*4882a593Smuzhiyun {
1730*4882a593Smuzhiyun 	fastboot_func->in_req->complete = do_bootm_on_complete;
1731*4882a593Smuzhiyun 	fastboot_tx_write_str("OKAY");
1732*4882a593Smuzhiyun }
1733*4882a593Smuzhiyun 
do_exit_on_complete(struct usb_ep * ep,struct usb_request * req)1734*4882a593Smuzhiyun static void do_exit_on_complete(struct usb_ep *ep, struct usb_request *req)
1735*4882a593Smuzhiyun {
1736*4882a593Smuzhiyun 	g_dnl_trigger_detach();
1737*4882a593Smuzhiyun }
1738*4882a593Smuzhiyun 
cb_continue(struct usb_ep * ep,struct usb_request * req)1739*4882a593Smuzhiyun static void cb_continue(struct usb_ep *ep, struct usb_request *req)
1740*4882a593Smuzhiyun {
1741*4882a593Smuzhiyun 	fastboot_func->in_req->complete = do_exit_on_complete;
1742*4882a593Smuzhiyun 	fastboot_tx_write_str("OKAY");
1743*4882a593Smuzhiyun }
1744*4882a593Smuzhiyun 
cb_set_active(struct usb_ep * ep,struct usb_request * req)1745*4882a593Smuzhiyun static void cb_set_active(struct usb_ep *ep, struct usb_request *req)
1746*4882a593Smuzhiyun {
1747*4882a593Smuzhiyun 	char *cmd = req->buf;
1748*4882a593Smuzhiyun 
1749*4882a593Smuzhiyun 	debug("%s: %s\n", __func__, cmd);
1750*4882a593Smuzhiyun 
1751*4882a593Smuzhiyun 	strsep(&cmd, ":");
1752*4882a593Smuzhiyun 	if (!cmd) {
1753*4882a593Smuzhiyun 		pr_err("missing slot name");
1754*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILmissing slot name");
1755*4882a593Smuzhiyun 		return;
1756*4882a593Smuzhiyun 	}
1757*4882a593Smuzhiyun #ifdef CONFIG_ANDROID_AB
1758*4882a593Smuzhiyun 	if (get_virtual_ab_merge_status() == ENUM_MERGE_STATUS_MERGING) {
1759*4882a593Smuzhiyun 		pr_err("virtual A/B is merging, abort the operation");
1760*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILvirtual A/B is merging, abort");
1761*4882a593Smuzhiyun 		return;
1762*4882a593Smuzhiyun 	}
1763*4882a593Smuzhiyun #endif
1764*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
1765*4882a593Smuzhiyun 	unsigned int slot_number;
1766*4882a593Smuzhiyun 	if (strncmp("a", cmd, 1) == 0) {
1767*4882a593Smuzhiyun 		slot_number = 0;
1768*4882a593Smuzhiyun 		rk_avb_set_slot_active(&slot_number);
1769*4882a593Smuzhiyun 	} else if (strncmp("b", cmd, 1) == 0) {
1770*4882a593Smuzhiyun 		slot_number = 1;
1771*4882a593Smuzhiyun 		rk_avb_set_slot_active(&slot_number);
1772*4882a593Smuzhiyun 	} else {
1773*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILunkown slot name");
1774*4882a593Smuzhiyun 		return;
1775*4882a593Smuzhiyun 	}
1776*4882a593Smuzhiyun 
1777*4882a593Smuzhiyun 	fastboot_tx_write_str("OKAY");
1778*4882a593Smuzhiyun 	return;
1779*4882a593Smuzhiyun #else
1780*4882a593Smuzhiyun 	fastboot_tx_write_str("FAILnot implemented");
1781*4882a593Smuzhiyun 	return;
1782*4882a593Smuzhiyun #endif
1783*4882a593Smuzhiyun }
1784*4882a593Smuzhiyun 
1785*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_FLASH
cb_flash(struct usb_ep * ep,struct usb_request * req)1786*4882a593Smuzhiyun static void cb_flash(struct usb_ep *ep, struct usb_request *req)
1787*4882a593Smuzhiyun {
1788*4882a593Smuzhiyun 	char *cmd = req->buf;
1789*4882a593Smuzhiyun 	char response[FASTBOOT_RESPONSE_LEN] = {0};
1790*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
1791*4882a593Smuzhiyun 	uint8_t flash_lock_state;
1792*4882a593Smuzhiyun 
1793*4882a593Smuzhiyun 	if (rk_avb_read_flash_lock_state(&flash_lock_state)) {
1794*4882a593Smuzhiyun 		/* write the device flashing unlock when first read */
1795*4882a593Smuzhiyun 		if (rk_avb_write_flash_lock_state(1)) {
1796*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILflash lock state write failure");
1797*4882a593Smuzhiyun 			return;
1798*4882a593Smuzhiyun 		}
1799*4882a593Smuzhiyun 		if (rk_avb_read_flash_lock_state(&flash_lock_state)) {
1800*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILflash lock state read failure");
1801*4882a593Smuzhiyun 			return;
1802*4882a593Smuzhiyun 		}
1803*4882a593Smuzhiyun 	}
1804*4882a593Smuzhiyun 
1805*4882a593Smuzhiyun 	if (flash_lock_state == 0) {
1806*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILThe device is locked, can not flash!");
1807*4882a593Smuzhiyun 		printf("The device is locked, can not flash!\n");
1808*4882a593Smuzhiyun 		return;
1809*4882a593Smuzhiyun 	}
1810*4882a593Smuzhiyun #endif
1811*4882a593Smuzhiyun 	strsep(&cmd, ":");
1812*4882a593Smuzhiyun 	if (!cmd) {
1813*4882a593Smuzhiyun 		pr_err("missing partition name");
1814*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILmissing partition name");
1815*4882a593Smuzhiyun 		return;
1816*4882a593Smuzhiyun 	}
1817*4882a593Smuzhiyun #ifdef CONFIG_ANDROID_AB
1818*4882a593Smuzhiyun 	if ((strcmp(cmd, PART_USERDATA) == 0) || (strcmp(cmd, PART_METADATA) == 0)) {
1819*4882a593Smuzhiyun 		if (should_prevent_userdata_wipe()) {
1820*4882a593Smuzhiyun 			pr_err("FAILThe virtual A/B merging, can not flash userdata or metadata!\n");
1821*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILvirtual A/B merging,abort flash!");
1822*4882a593Smuzhiyun 			return;
1823*4882a593Smuzhiyun 		}
1824*4882a593Smuzhiyun 	}
1825*4882a593Smuzhiyun #endif
1826*4882a593Smuzhiyun 	fastboot_fail("no flash device defined", response);
1827*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
1828*4882a593Smuzhiyun 	fb_mmc_flash_write(cmd, (void *)CONFIG_FASTBOOT_BUF_ADDR,
1829*4882a593Smuzhiyun 				download_bytes, response);
1830*4882a593Smuzhiyun #endif
1831*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV
1832*4882a593Smuzhiyun 	fb_nand_flash_write(cmd, (void *)CONFIG_FASTBOOT_BUF_ADDR,
1833*4882a593Smuzhiyun 				download_bytes, response);
1834*4882a593Smuzhiyun #endif
1835*4882a593Smuzhiyun 	fastboot_tx_write_str(response);
1836*4882a593Smuzhiyun }
1837*4882a593Smuzhiyun 
cb_flashing(struct usb_ep * ep,struct usb_request * req)1838*4882a593Smuzhiyun static void cb_flashing(struct usb_ep *ep, struct usb_request *req)
1839*4882a593Smuzhiyun {
1840*4882a593Smuzhiyun 	char *cmd = req->buf;
1841*4882a593Smuzhiyun 
1842*4882a593Smuzhiyun 	if (strncmp("lock", cmd + 9, 4) == 0) {
1843*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
1844*4882a593Smuzhiyun 		uint8_t flash_lock_state;
1845*4882a593Smuzhiyun 		flash_lock_state = 0;
1846*4882a593Smuzhiyun 		if (rk_avb_write_flash_lock_state(flash_lock_state))
1847*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILflash lock state"
1848*4882a593Smuzhiyun 					      " write failure");
1849*4882a593Smuzhiyun 		else
1850*4882a593Smuzhiyun 			fastboot_tx_write_str("OKAY");
1851*4882a593Smuzhiyun #else
1852*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILnot implemented");
1853*4882a593Smuzhiyun #endif
1854*4882a593Smuzhiyun 	} else if (strncmp("unlock", cmd + 9, 6) == 0) {
1855*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
1856*4882a593Smuzhiyun 		uint8_t flash_lock_state;
1857*4882a593Smuzhiyun 		flash_lock_state = 1;
1858*4882a593Smuzhiyun 		if (rk_avb_write_flash_lock_state(flash_lock_state))
1859*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILflash lock state"
1860*4882a593Smuzhiyun 					      " write failure");
1861*4882a593Smuzhiyun 		else
1862*4882a593Smuzhiyun 			fastboot_tx_write_str("OKAY");
1863*4882a593Smuzhiyun #else
1864*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILnot implemented");
1865*4882a593Smuzhiyun #endif
1866*4882a593Smuzhiyun 	} else if (strncmp("lock_critical", cmd + 9, 12) == 0) {
1867*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILnot implemented");
1868*4882a593Smuzhiyun 	} else if (strncmp("unlock_critical", cmd + 9, 14) == 0) {
1869*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILnot implemented");
1870*4882a593Smuzhiyun 	} else if (strncmp("get_unlock_ability", cmd + 9, 17) == 0) {
1871*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILnot implemented");
1872*4882a593Smuzhiyun 	} else if (strncmp("get_unlock_bootloader_nonce", cmd + 4, 27) == 0) {
1873*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILnot implemented");
1874*4882a593Smuzhiyun 	} else if (strncmp("unlock_bootloader", cmd + 9, 17) == 0) {
1875*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILnot implemented");
1876*4882a593Smuzhiyun 	} else if (strncmp("lock_bootloader", cmd + 9, 15) == 0) {
1877*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILnot implemented");
1878*4882a593Smuzhiyun 	} else {
1879*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILunknown flashing command");
1880*4882a593Smuzhiyun 	}
1881*4882a593Smuzhiyun }
1882*4882a593Smuzhiyun #endif
1883*4882a593Smuzhiyun 
cb_oem_perm_attr(void)1884*4882a593Smuzhiyun static void cb_oem_perm_attr(void)
1885*4882a593Smuzhiyun {
1886*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
1887*4882a593Smuzhiyun #ifndef CONFIG_ROCKCHIP_PRELOADER_PUB_KEY
1888*4882a593Smuzhiyun 	sha256_context ctx;
1889*4882a593Smuzhiyun 	uint8_t digest[SHA256_SUM_LEN] = {0};
1890*4882a593Smuzhiyun 	uint8_t digest_temp[SHA256_SUM_LEN] = {0};
1891*4882a593Smuzhiyun 	uint8_t perm_attr_temp[PERM_ATTR_TOTAL_SIZE] = {0};
1892*4882a593Smuzhiyun 	uint8_t flag = 0;
1893*4882a593Smuzhiyun #endif
1894*4882a593Smuzhiyun 	if (PERM_ATTR_TOTAL_SIZE != download_bytes) {
1895*4882a593Smuzhiyun 		printf("Permanent attribute size is not equal!\n");
1896*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILincorrect perm attribute size");
1897*4882a593Smuzhiyun 		return;
1898*4882a593Smuzhiyun 	}
1899*4882a593Smuzhiyun #ifndef CONFIG_ROCKCHIP_PRELOADER_PUB_KEY
1900*4882a593Smuzhiyun 	if (rk_avb_read_perm_attr_flag(&flag)) {
1901*4882a593Smuzhiyun 		printf("rk_avb_read_perm_attr_flag error!\n");
1902*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILperm attr read failed");
1903*4882a593Smuzhiyun 		return;
1904*4882a593Smuzhiyun 	}
1905*4882a593Smuzhiyun 
1906*4882a593Smuzhiyun 	if (flag == PERM_ATTR_SUCCESS_FLAG) {
1907*4882a593Smuzhiyun 		if (rk_avb_read_attribute_hash(digest_temp,
1908*4882a593Smuzhiyun 					       SHA256_SUM_LEN)) {
1909*4882a593Smuzhiyun 			printf("The efuse IO can not be used!\n");
1910*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILefuse IO can not be used");
1911*4882a593Smuzhiyun 			return;
1912*4882a593Smuzhiyun 		}
1913*4882a593Smuzhiyun 
1914*4882a593Smuzhiyun 		if (memcmp(digest, digest_temp, SHA256_SUM_LEN) != 0) {
1915*4882a593Smuzhiyun 			if (rk_avb_read_permanent_attributes(perm_attr_temp,
1916*4882a593Smuzhiyun 							     PERM_ATTR_TOTAL_SIZE)) {
1917*4882a593Smuzhiyun 				printf("rk_avb_write_permanent_attributes error!\n");
1918*4882a593Smuzhiyun 				fastboot_tx_write_str("FAILread perm attr error");
1919*4882a593Smuzhiyun 				return;
1920*4882a593Smuzhiyun 			}
1921*4882a593Smuzhiyun 
1922*4882a593Smuzhiyun 			sha256_starts(&ctx);
1923*4882a593Smuzhiyun 			sha256_update(&ctx,
1924*4882a593Smuzhiyun 				      (const uint8_t *)perm_attr_temp,
1925*4882a593Smuzhiyun 				      PERM_ATTR_TOTAL_SIZE);
1926*4882a593Smuzhiyun 			sha256_finish(&ctx, digest);
1927*4882a593Smuzhiyun 			if (memcmp(digest, digest_temp, SHA256_SUM_LEN) == 0) {
1928*4882a593Smuzhiyun 				printf("The hash has been written!\n");
1929*4882a593Smuzhiyun 				fastboot_tx_write_str("OKAY");
1930*4882a593Smuzhiyun 				return;
1931*4882a593Smuzhiyun 			}
1932*4882a593Smuzhiyun 		}
1933*4882a593Smuzhiyun 
1934*4882a593Smuzhiyun 		if (rk_avb_write_perm_attr_flag(0)) {
1935*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILperm attr flag write failure");
1936*4882a593Smuzhiyun 			return;
1937*4882a593Smuzhiyun 		}
1938*4882a593Smuzhiyun 	}
1939*4882a593Smuzhiyun #endif
1940*4882a593Smuzhiyun 	if (rk_avb_write_permanent_attributes((uint8_t *)
1941*4882a593Smuzhiyun 					      CONFIG_FASTBOOT_BUF_ADDR,
1942*4882a593Smuzhiyun 					      download_bytes)) {
1943*4882a593Smuzhiyun 		if (rk_avb_write_perm_attr_flag(0)) {
1944*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILperm attr flag write failure");
1945*4882a593Smuzhiyun 			return;
1946*4882a593Smuzhiyun 		}
1947*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILperm attr write failed");
1948*4882a593Smuzhiyun 		return;
1949*4882a593Smuzhiyun 	}
1950*4882a593Smuzhiyun #ifndef CONFIG_ROCKCHIP_PRELOADER_PUB_KEY
1951*4882a593Smuzhiyun 	memset(digest, 0, SHA256_SUM_LEN);
1952*4882a593Smuzhiyun 	sha256_starts(&ctx);
1953*4882a593Smuzhiyun 	sha256_update(&ctx, (const uint8_t *)CONFIG_FASTBOOT_BUF_ADDR,
1954*4882a593Smuzhiyun 		      PERM_ATTR_TOTAL_SIZE);
1955*4882a593Smuzhiyun 	sha256_finish(&ctx, digest);
1956*4882a593Smuzhiyun 
1957*4882a593Smuzhiyun 	if (rk_avb_write_attribute_hash((uint8_t *)digest,
1958*4882a593Smuzhiyun 					SHA256_SUM_LEN)) {
1959*4882a593Smuzhiyun 		if (rk_avb_read_attribute_hash(digest_temp,
1960*4882a593Smuzhiyun 						SHA256_SUM_LEN)) {
1961*4882a593Smuzhiyun 			printf("The efuse IO can not be used!\n");
1962*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILefuse IO can not be used");
1963*4882a593Smuzhiyun 			return;
1964*4882a593Smuzhiyun 		}
1965*4882a593Smuzhiyun 		if (memcmp(digest, digest_temp, SHA256_SUM_LEN) != 0) {
1966*4882a593Smuzhiyun 			if (rk_avb_write_perm_attr_flag(0)) {
1967*4882a593Smuzhiyun 				fastboot_tx_write_str("FAILperm attr flag write failure");
1968*4882a593Smuzhiyun 				return;
1969*4882a593Smuzhiyun 			}
1970*4882a593Smuzhiyun 			printf("The hash has been written, but is different!\n");
1971*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILhash comparison failure");
1972*4882a593Smuzhiyun 			return;
1973*4882a593Smuzhiyun 		}
1974*4882a593Smuzhiyun 	}
1975*4882a593Smuzhiyun #endif
1976*4882a593Smuzhiyun 	if (rk_avb_write_perm_attr_flag(PERM_ATTR_SUCCESS_FLAG)) {
1977*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILperm attr flag write failure");
1978*4882a593Smuzhiyun 		return;
1979*4882a593Smuzhiyun 	}
1980*4882a593Smuzhiyun 
1981*4882a593Smuzhiyun 	fastboot_tx_write_str("OKAY");
1982*4882a593Smuzhiyun #else
1983*4882a593Smuzhiyun 	fastboot_tx_write_str("FAILnot implemented");
1984*4882a593Smuzhiyun #endif
1985*4882a593Smuzhiyun }
1986*4882a593Smuzhiyun 
cb_oem_perm_attr_rsa_cer(void)1987*4882a593Smuzhiyun static void cb_oem_perm_attr_rsa_cer(void)
1988*4882a593Smuzhiyun {
1989*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
1990*4882a593Smuzhiyun 	if (download_bytes != 256) {
1991*4882a593Smuzhiyun 		printf("Permanent attribute rsahash size is not equal!\n");
1992*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILperm attribute rsahash size error");
1993*4882a593Smuzhiyun 		return;
1994*4882a593Smuzhiyun 	}
1995*4882a593Smuzhiyun 
1996*4882a593Smuzhiyun 	if (rk_avb_set_perm_attr_cer((uint8_t *)CONFIG_FASTBOOT_BUF_ADDR,
1997*4882a593Smuzhiyun 				     download_bytes)) {
1998*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILSet perm attr cer fail!");
1999*4882a593Smuzhiyun 		return;
2000*4882a593Smuzhiyun 	}
2001*4882a593Smuzhiyun 
2002*4882a593Smuzhiyun 	fastboot_tx_write_str("OKAY");
2003*4882a593Smuzhiyun #else
2004*4882a593Smuzhiyun 	fastboot_tx_write_str("FAILnot implemented");
2005*4882a593Smuzhiyun #endif
2006*4882a593Smuzhiyun }
2007*4882a593Smuzhiyun 
cb_oem(struct usb_ep * ep,struct usb_request * req)2008*4882a593Smuzhiyun static void cb_oem(struct usb_ep *ep, struct usb_request *req)
2009*4882a593Smuzhiyun {
2010*4882a593Smuzhiyun 	char *cmd = req->buf;
2011*4882a593Smuzhiyun 
2012*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
2013*4882a593Smuzhiyun 	if (strncmp("format", cmd + 4, 6) == 0) {
2014*4882a593Smuzhiyun 		char cmdbuf[32];
2015*4882a593Smuzhiyun 		sprintf(cmdbuf, "gpt write mmc %x $partitions",
2016*4882a593Smuzhiyun 			CONFIG_FASTBOOT_FLASH_MMC_DEV);
2017*4882a593Smuzhiyun #ifdef CONFIG_ANDROID_AB
2018*4882a593Smuzhiyun 		if (should_prevent_userdata_wipe()) {
2019*4882a593Smuzhiyun 			printf("FAILThe virtual A/B merging, can not format!\n");
2020*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILvirtual A/B merging,abort format!");
2021*4882a593Smuzhiyun 		} else {
2022*4882a593Smuzhiyun 			if (run_command(cmdbuf, 0))
2023*4882a593Smuzhiyun 				fastboot_tx_write_str("FAILmmc write failure");
2024*4882a593Smuzhiyun 			else
2025*4882a593Smuzhiyun 				fastboot_tx_write_str("OKAY");
2026*4882a593Smuzhiyun 		}
2027*4882a593Smuzhiyun #else
2028*4882a593Smuzhiyun 	if (run_command(cmdbuf, 0))
2029*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILmmc write failure");
2030*4882a593Smuzhiyun 	else
2031*4882a593Smuzhiyun 		fastboot_tx_write_str("OKAY");
2032*4882a593Smuzhiyun #endif
2033*4882a593Smuzhiyun 	} else
2034*4882a593Smuzhiyun #endif
2035*4882a593Smuzhiyun 	if (strncmp("unlock", cmd + 4, 8) == 0) {
2036*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_OEM_UNLOCK
2037*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
2038*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILnot implemented");
2039*4882a593Smuzhiyun 		return;
2040*4882a593Smuzhiyun #else
2041*4882a593Smuzhiyun 		uint8_t unlock = 0;
2042*4882a593Smuzhiyun 		TEEC_Result result;
2043*4882a593Smuzhiyun 		debug("oem unlock\n");
2044*4882a593Smuzhiyun 		result = trusty_read_oem_unlock(&unlock);
2045*4882a593Smuzhiyun 		if (result) {
2046*4882a593Smuzhiyun 			printf("read oem unlock status with error : 0x%x\n", result);
2047*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILRead oem unlock status failed");
2048*4882a593Smuzhiyun 			return;
2049*4882a593Smuzhiyun 		}
2050*4882a593Smuzhiyun 		if (unlock) {
2051*4882a593Smuzhiyun 			printf("oem unlock ignored, device already unlocked\n");
2052*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILalready unlocked");
2053*4882a593Smuzhiyun 			return;
2054*4882a593Smuzhiyun 		}
2055*4882a593Smuzhiyun 		printf("oem unlock requested:\n");
2056*4882a593Smuzhiyun 		printf("\tUnlocking forces a factory reset and could\n");
2057*4882a593Smuzhiyun 		printf("\topen your device up to a world of hurt.  If you\n");
2058*4882a593Smuzhiyun 		printf("\tare sure you know what you're doing, then accept\n");
2059*4882a593Smuzhiyun 		printf("\tvia 'fastboot oem unlock_accept'.\n");
2060*4882a593Smuzhiyun 		env_set("unlock", "unlock");
2061*4882a593Smuzhiyun 		fastboot_tx_write_str("OKAY");
2062*4882a593Smuzhiyun #endif
2063*4882a593Smuzhiyun #else
2064*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILnot implemented");
2065*4882a593Smuzhiyun 		return;
2066*4882a593Smuzhiyun #endif
2067*4882a593Smuzhiyun 	} else if (strncmp("unlock_accept", cmd + 4, 13) == 0) {
2068*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_OEM_UNLOCK
2069*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
2070*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILnot implemented");
2071*4882a593Smuzhiyun 		return;
2072*4882a593Smuzhiyun #else
2073*4882a593Smuzhiyun 		char *unlock = env_get("unlock");
2074*4882a593Smuzhiyun 		TEEC_Result result;
2075*4882a593Smuzhiyun 		debug("oem unlock_accept\n");
2076*4882a593Smuzhiyun 		if (unlock == NULL || strncmp("unlock", unlock, 6) != 0) {
2077*4882a593Smuzhiyun 			printf("oem unlock_accept ignored, not pending\n");
2078*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILoem unlock not requested");
2079*4882a593Smuzhiyun 			return;
2080*4882a593Smuzhiyun 		}
2081*4882a593Smuzhiyun 		env_set("unlock", "");
2082*4882a593Smuzhiyun 		printf("Erasing userdata partition\n");
2083*4882a593Smuzhiyun 		struct blk_desc *dev_desc;
2084*4882a593Smuzhiyun 		disk_partition_t part_info;
2085*4882a593Smuzhiyun 		dev_desc = rockchip_get_bootdev();
2086*4882a593Smuzhiyun 		if (!dev_desc) {
2087*4882a593Smuzhiyun 			printf("%s: dev_desc is NULL!\n", __func__);
2088*4882a593Smuzhiyun 			return;
2089*4882a593Smuzhiyun 		}
2090*4882a593Smuzhiyun 		int ret = part_get_info_by_name(dev_desc, "userdata",
2091*4882a593Smuzhiyun 				&part_info);
2092*4882a593Smuzhiyun 		if (ret < 0) {
2093*4882a593Smuzhiyun 			printf("not found userdata partition");
2094*4882a593Smuzhiyun 			printf("Erase failed with error %d\n", ret);
2095*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILErasing userdata failed");
2096*4882a593Smuzhiyun 			return;
2097*4882a593Smuzhiyun 		}
2098*4882a593Smuzhiyun 		ret = blk_derase(dev_desc, part_info.start, part_info.size);
2099*4882a593Smuzhiyun 		if (ret != part_info.size) {
2100*4882a593Smuzhiyun 			printf("Erase failed with error %d\n", ret);
2101*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILErasing userdata failed");
2102*4882a593Smuzhiyun 			return;
2103*4882a593Smuzhiyun 		}
2104*4882a593Smuzhiyun 		printf("Erasing succeeded\n");
2105*4882a593Smuzhiyun 
2106*4882a593Smuzhiyun 		result = trusty_write_oem_unlock(1);
2107*4882a593Smuzhiyun 		if (result) {
2108*4882a593Smuzhiyun 			printf("write oem unlock status with error : 0x%x\n", result);
2109*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILWrite oem unlock status failed");
2110*4882a593Smuzhiyun 			return;
2111*4882a593Smuzhiyun 		}
2112*4882a593Smuzhiyun 		fastboot_tx_write_str("OKAY");
2113*4882a593Smuzhiyun 
2114*4882a593Smuzhiyun 		/*
2115*4882a593Smuzhiyun 		 * now reboot into recovery to do a format of the
2116*4882a593Smuzhiyun 		 * userdata partition so it's ready to use on next boot
2117*4882a593Smuzhiyun 		 */
2118*4882a593Smuzhiyun 		board_run_recovery_wipe_data();
2119*4882a593Smuzhiyun #endif
2120*4882a593Smuzhiyun #else
2121*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILnot implemented");
2122*4882a593Smuzhiyun 		return;
2123*4882a593Smuzhiyun #endif
2124*4882a593Smuzhiyun 	} else if (strncmp("lock", cmd + 4, 8) == 0) {
2125*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_OEM_UNLOCK
2126*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
2127*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILnot implemented");
2128*4882a593Smuzhiyun 		return;
2129*4882a593Smuzhiyun #else
2130*4882a593Smuzhiyun 		TEEC_Result result;
2131*4882a593Smuzhiyun 		uint8_t unlock = 0;
2132*4882a593Smuzhiyun 		trusty_read_oem_unlock(&unlock);
2133*4882a593Smuzhiyun 		if (!unlock) {
2134*4882a593Smuzhiyun 			printf("oem lock ignored, already locked\n");
2135*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILalready locked");
2136*4882a593Smuzhiyun 			return;
2137*4882a593Smuzhiyun 		}
2138*4882a593Smuzhiyun 
2139*4882a593Smuzhiyun 		result = trusty_write_oem_unlock(0);
2140*4882a593Smuzhiyun 		if (result) {
2141*4882a593Smuzhiyun 			printf("write oem unlock status with error : 0x%x\n", result);
2142*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILWrite oem unlock status failed");
2143*4882a593Smuzhiyun 			return;
2144*4882a593Smuzhiyun 		}
2145*4882a593Smuzhiyun 		fastboot_tx_write_str("OKAY");
2146*4882a593Smuzhiyun #endif
2147*4882a593Smuzhiyun #else
2148*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILnot implemented");
2149*4882a593Smuzhiyun 		return;
2150*4882a593Smuzhiyun #endif
2151*4882a593Smuzhiyun 	} else if (strncmp("at-get-ca-request", cmd + 4, 17) == 0) {
2152*4882a593Smuzhiyun #ifdef CONFIG_OPTEE_CLIENT
2153*4882a593Smuzhiyun 		uint8_t out[ATTEST_CA_OUT_SIZE];
2154*4882a593Smuzhiyun 		uint32_t operation_size = download_bytes;
2155*4882a593Smuzhiyun 		uint32_t out_len = ATTEST_CA_OUT_SIZE;
2156*4882a593Smuzhiyun 		uint32_t res = 0;
2157*4882a593Smuzhiyun 
2158*4882a593Smuzhiyun 		res = trusty_attest_get_ca((uint8_t *)CONFIG_FASTBOOT_BUF_ADDR,
2159*4882a593Smuzhiyun 					   &operation_size, out, &out_len);
2160*4882a593Smuzhiyun 		if (res) {
2161*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILtrusty_attest_get_ca failed");
2162*4882a593Smuzhiyun 			return;
2163*4882a593Smuzhiyun 		}
2164*4882a593Smuzhiyun 		upload_size = out_len;
2165*4882a593Smuzhiyun 		memcpy((void *)CONFIG_FASTBOOT_BUF_ADDR, out, out_len);
2166*4882a593Smuzhiyun 		fastboot_tx_write_str("OKAY");
2167*4882a593Smuzhiyun #else
2168*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILnot implemented");
2169*4882a593Smuzhiyun 		return;
2170*4882a593Smuzhiyun #endif
2171*4882a593Smuzhiyun 	} else if (strncmp("at-set-ca-response", cmd + 4, 18) == 0) {
2172*4882a593Smuzhiyun #ifdef CONFIG_OPTEE_CLIENT
2173*4882a593Smuzhiyun 		uint32_t ca_response_size = download_bytes;
2174*4882a593Smuzhiyun 		uint32_t res = 0;
2175*4882a593Smuzhiyun 
2176*4882a593Smuzhiyun 		res = trusty_attest_set_ca((uint8_t *)CONFIG_FASTBOOT_BUF_ADDR,
2177*4882a593Smuzhiyun 					   &ca_response_size);
2178*4882a593Smuzhiyun 		if (res)
2179*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILtrusty_attest_set_ca failed");
2180*4882a593Smuzhiyun 		else
2181*4882a593Smuzhiyun 			fastboot_tx_write_str("OKAY");
2182*4882a593Smuzhiyun #else
2183*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILnot implemented");
2184*4882a593Smuzhiyun 		return;
2185*4882a593Smuzhiyun #endif
2186*4882a593Smuzhiyun 	} else if (strncmp("at-get-vboot-unlock-challenge", cmd + 4, 29) == 0) {
2187*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
2188*4882a593Smuzhiyun 		uint32_t challenge_len = 0;
2189*4882a593Smuzhiyun 		int ret = 0;
2190*4882a593Smuzhiyun 
2191*4882a593Smuzhiyun 		ret = rk_generate_unlock_challenge((void *)CONFIG_FASTBOOT_BUF_ADDR, &challenge_len);
2192*4882a593Smuzhiyun 		if (ret == 0) {
2193*4882a593Smuzhiyun 			upload_size = challenge_len;
2194*4882a593Smuzhiyun 			fastboot_tx_write_str("OKAY");
2195*4882a593Smuzhiyun 		} else {
2196*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILgenerate unlock challenge fail!");
2197*4882a593Smuzhiyun 		}
2198*4882a593Smuzhiyun #else
2199*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILnot implemented");
2200*4882a593Smuzhiyun 		return;
2201*4882a593Smuzhiyun #endif
2202*4882a593Smuzhiyun 	} else if (strncmp("at-lock-vboot", cmd + 4, 13) == 0) {
2203*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
2204*4882a593Smuzhiyun 		uint8_t lock_state;
2205*4882a593Smuzhiyun 		lock_state = 0;
2206*4882a593Smuzhiyun 		if (rk_avb_write_lock_state(lock_state))
2207*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILwrite lock state failed");
2208*4882a593Smuzhiyun 		else
2209*4882a593Smuzhiyun 			fastboot_tx_write_str("OKAY");
2210*4882a593Smuzhiyun #else
2211*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILnot implemented");
2212*4882a593Smuzhiyun #endif
2213*4882a593Smuzhiyun 	} else if (strncmp("at-unlock-vboot", cmd + 4, 15) == 0) {
2214*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
2215*4882a593Smuzhiyun 		uint8_t lock_state;
2216*4882a593Smuzhiyun 		char out_is_trusted = true;
2217*4882a593Smuzhiyun 
2218*4882a593Smuzhiyun 		if (rk_avb_read_lock_state(&lock_state))
2219*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILlock sate read failure");
2220*4882a593Smuzhiyun 		if (lock_state >> 1 == 1) {
2221*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILThe vboot is disable!");
2222*4882a593Smuzhiyun 		} else {
2223*4882a593Smuzhiyun 			lock_state = 1;
2224*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_ENABLE_ATH_UNLOCK
2225*4882a593Smuzhiyun 			if (rk_auth_unlock((void *)CONFIG_FASTBOOT_BUF_ADDR,
2226*4882a593Smuzhiyun 					   &out_is_trusted)) {
2227*4882a593Smuzhiyun 				printf("rk_auth_unlock ops error!\n");
2228*4882a593Smuzhiyun 				fastboot_tx_write_str("FAILrk_auth_unlock ops error!");
2229*4882a593Smuzhiyun 				return;
2230*4882a593Smuzhiyun 			}
2231*4882a593Smuzhiyun #endif
2232*4882a593Smuzhiyun 			if (out_is_trusted == true) {
2233*4882a593Smuzhiyun 				if (rk_avb_write_lock_state(lock_state))
2234*4882a593Smuzhiyun 					fastboot_tx_write_str("FAILwrite lock state failed");
2235*4882a593Smuzhiyun 				else
2236*4882a593Smuzhiyun 					fastboot_tx_write_str("OKAY");
2237*4882a593Smuzhiyun 			} else {
2238*4882a593Smuzhiyun 				fastboot_tx_write_str("FAILauthenticated unlock fail");
2239*4882a593Smuzhiyun 			}
2240*4882a593Smuzhiyun 		}
2241*4882a593Smuzhiyun #else
2242*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILnot implemented");
2243*4882a593Smuzhiyun #endif
2244*4882a593Smuzhiyun 	} else if (strncmp("fuse at-perm-attr", cmd + 4, 16) == 0) {
2245*4882a593Smuzhiyun 		cb_oem_perm_attr();
2246*4882a593Smuzhiyun 	} else if (strncmp("fuse at-rsa-perm-attr", cmd + 4, 25) == 0) {
2247*4882a593Smuzhiyun 		cb_oem_perm_attr_rsa_cer();
2248*4882a593Smuzhiyun 	} else if (strncmp("fuse at-bootloader-vboot-key", cmd + 4, 27) == 0) {
2249*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
2250*4882a593Smuzhiyun 		sha256_context ctx;
2251*4882a593Smuzhiyun 		uint8_t digest[SHA256_SUM_LEN];
2252*4882a593Smuzhiyun 
2253*4882a593Smuzhiyun 		if (download_bytes != VBOOT_KEY_HASH_SIZE) {
2254*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILinvalid vboot key length");
2255*4882a593Smuzhiyun 			printf("The vboot key size error!\n");
2256*4882a593Smuzhiyun 			return;
2257*4882a593Smuzhiyun 		}
2258*4882a593Smuzhiyun 
2259*4882a593Smuzhiyun 		sha256_starts(&ctx);
2260*4882a593Smuzhiyun 		sha256_update(&ctx, (const uint8_t *)CONFIG_FASTBOOT_BUF_ADDR,
2261*4882a593Smuzhiyun 			      VBOOT_KEY_SIZE);
2262*4882a593Smuzhiyun 		sha256_finish(&ctx, digest);
2263*4882a593Smuzhiyun 
2264*4882a593Smuzhiyun 		if (rk_avb_write_vbootkey_hash((uint8_t *)digest,
2265*4882a593Smuzhiyun 					       SHA256_SUM_LEN)) {
2266*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILvbootkey hash write failure");
2267*4882a593Smuzhiyun 			return;
2268*4882a593Smuzhiyun 		}
2269*4882a593Smuzhiyun 		fastboot_tx_write_str("OKAY");
2270*4882a593Smuzhiyun #else
2271*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILnot implemented");
2272*4882a593Smuzhiyun #endif
2273*4882a593Smuzhiyun 	} else if (strncmp("init-ab-metadata", cmd + 4, 16) == 0) {
2274*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
2275*4882a593Smuzhiyun 		if (rk_avb_init_ab_metadata()) {
2276*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILinit ab data fail!");
2277*4882a593Smuzhiyun 			return;
2278*4882a593Smuzhiyun 		}
2279*4882a593Smuzhiyun 		fastboot_tx_write_str("OKAY");
2280*4882a593Smuzhiyun #else
2281*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILnot implemented");
2282*4882a593Smuzhiyun #endif
2283*4882a593Smuzhiyun 	} else {
2284*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILunknown oem command");
2285*4882a593Smuzhiyun 	}
2286*4882a593Smuzhiyun }
2287*4882a593Smuzhiyun 
2288*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_FLASH
cb_erase(struct usb_ep * ep,struct usb_request * req)2289*4882a593Smuzhiyun static void cb_erase(struct usb_ep *ep, struct usb_request *req)
2290*4882a593Smuzhiyun {
2291*4882a593Smuzhiyun 	char *cmd = req->buf;
2292*4882a593Smuzhiyun 	char response[FASTBOOT_RESPONSE_LEN] = {0};
2293*4882a593Smuzhiyun 
2294*4882a593Smuzhiyun 	strsep(&cmd, ":");
2295*4882a593Smuzhiyun 	if (!cmd) {
2296*4882a593Smuzhiyun 		pr_err("missing partition name");
2297*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILmissing partition name");
2298*4882a593Smuzhiyun 		return;
2299*4882a593Smuzhiyun 	}
2300*4882a593Smuzhiyun #ifdef CONFIG_ANDROID_AB
2301*4882a593Smuzhiyun 	if ((strcmp(cmd, PART_USERDATA) == 0) || (strcmp(cmd, PART_METADATA) == 0)) {
2302*4882a593Smuzhiyun 		if (should_prevent_userdata_wipe()) {
2303*4882a593Smuzhiyun 			pr_err("virtual A/B merging, can not erase userdata or metadata!\n");
2304*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILvirtual A/B merging,abort erase!");
2305*4882a593Smuzhiyun 			return;
2306*4882a593Smuzhiyun 		}
2307*4882a593Smuzhiyun 	}
2308*4882a593Smuzhiyun #endif
2309*4882a593Smuzhiyun 	fastboot_fail("no flash device defined", response);
2310*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
2311*4882a593Smuzhiyun 	fb_mmc_erase(cmd, response);
2312*4882a593Smuzhiyun #endif
2313*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV
2314*4882a593Smuzhiyun 	fb_nand_erase(cmd, response);
2315*4882a593Smuzhiyun #endif
2316*4882a593Smuzhiyun 	fastboot_tx_write_str(response);
2317*4882a593Smuzhiyun }
2318*4882a593Smuzhiyun #endif
2319*4882a593Smuzhiyun 
2320*4882a593Smuzhiyun struct cmd_dispatch_info {
2321*4882a593Smuzhiyun 	char *cmd;
2322*4882a593Smuzhiyun 	void (*cb)(struct usb_ep *ep, struct usb_request *req);
2323*4882a593Smuzhiyun };
2324*4882a593Smuzhiyun 
2325*4882a593Smuzhiyun static const struct cmd_dispatch_info cmd_dispatch_info[] = {
2326*4882a593Smuzhiyun 	{
2327*4882a593Smuzhiyun 		.cmd = "reboot",
2328*4882a593Smuzhiyun 		.cb = cb_reboot,
2329*4882a593Smuzhiyun 	}, {
2330*4882a593Smuzhiyun 		.cmd = "getvar:",
2331*4882a593Smuzhiyun 		.cb = cb_getvar,
2332*4882a593Smuzhiyun 	}, {
2333*4882a593Smuzhiyun 		.cmd = "download:",
2334*4882a593Smuzhiyun 		.cb = cb_download,
2335*4882a593Smuzhiyun 	}, {
2336*4882a593Smuzhiyun 		.cmd = "upload",
2337*4882a593Smuzhiyun 		.cb = cb_upload,
2338*4882a593Smuzhiyun 	}, {
2339*4882a593Smuzhiyun 		.cmd = "boot",
2340*4882a593Smuzhiyun 		.cb = cb_boot,
2341*4882a593Smuzhiyun 	}, {
2342*4882a593Smuzhiyun 		.cmd = "continue",
2343*4882a593Smuzhiyun 		.cb = cb_continue,
2344*4882a593Smuzhiyun 	}, {
2345*4882a593Smuzhiyun 		.cmd = "set_active",
2346*4882a593Smuzhiyun 		.cb = cb_set_active,
2347*4882a593Smuzhiyun 	},
2348*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_FLASH
2349*4882a593Smuzhiyun 	{
2350*4882a593Smuzhiyun 		.cmd = "flashing",
2351*4882a593Smuzhiyun 		.cb = cb_flashing,
2352*4882a593Smuzhiyun 	},
2353*4882a593Smuzhiyun 	{
2354*4882a593Smuzhiyun 		.cmd = "flash",
2355*4882a593Smuzhiyun 		.cb = cb_flash,
2356*4882a593Smuzhiyun 	}, {
2357*4882a593Smuzhiyun 		.cmd = "erase",
2358*4882a593Smuzhiyun 		.cb = cb_erase,
2359*4882a593Smuzhiyun 	},
2360*4882a593Smuzhiyun #endif
2361*4882a593Smuzhiyun 	{
2362*4882a593Smuzhiyun 		.cmd = "oem",
2363*4882a593Smuzhiyun 		.cb = cb_oem,
2364*4882a593Smuzhiyun 	},
2365*4882a593Smuzhiyun };
2366*4882a593Smuzhiyun 
rx_handler_command(struct usb_ep * ep,struct usb_request * req)2367*4882a593Smuzhiyun static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
2368*4882a593Smuzhiyun {
2369*4882a593Smuzhiyun 	char *cmdbuf = req->buf;
2370*4882a593Smuzhiyun 	void (*func_cb)(struct usb_ep *ep, struct usb_request *req) = NULL;
2371*4882a593Smuzhiyun 	int i;
2372*4882a593Smuzhiyun 
2373*4882a593Smuzhiyun 	if (req->status != 0 || req->length == 0)
2374*4882a593Smuzhiyun 		return;
2375*4882a593Smuzhiyun 
2376*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) {
2377*4882a593Smuzhiyun 		if (!strcmp_l1(cmd_dispatch_info[i].cmd, cmdbuf)) {
2378*4882a593Smuzhiyun 			func_cb = cmd_dispatch_info[i].cb;
2379*4882a593Smuzhiyun 			break;
2380*4882a593Smuzhiyun 		}
2381*4882a593Smuzhiyun 	}
2382*4882a593Smuzhiyun 
2383*4882a593Smuzhiyun 	if (!func_cb) {
2384*4882a593Smuzhiyun 		pr_err("unknown command: %.*s", req->actual, cmdbuf);
2385*4882a593Smuzhiyun 		fastboot_tx_write_str("FAILunknown command");
2386*4882a593Smuzhiyun 	} else {
2387*4882a593Smuzhiyun 		if (req->actual < req->length) {
2388*4882a593Smuzhiyun 			u8 *buf = (u8 *)req->buf;
2389*4882a593Smuzhiyun 			buf[req->actual] = 0;
2390*4882a593Smuzhiyun 			func_cb(ep, req);
2391*4882a593Smuzhiyun 		} else {
2392*4882a593Smuzhiyun 			pr_err("buffer overflow");
2393*4882a593Smuzhiyun 			fastboot_tx_write_str("FAILbuffer overflow");
2394*4882a593Smuzhiyun 		}
2395*4882a593Smuzhiyun 	}
2396*4882a593Smuzhiyun 
2397*4882a593Smuzhiyun 	*cmdbuf = '\0';
2398*4882a593Smuzhiyun 	req->actual = 0;
2399*4882a593Smuzhiyun 	usb_ep_queue(ep, req, 0);
2400*4882a593Smuzhiyun }
2401