xref: /rk3399_rockchip-uboot/drivers/usb/gadget/f_rockusb.c (revision ca42250799bf3f1fa3a9302c7c000a66e7d9d0a9)
1f16e43f8SFrank Wang /*
2f16e43f8SFrank Wang  * Copyright 2017 Rockchip Electronics Co., Ltd
3f16e43f8SFrank Wang  * Frank Wang <frank.wang@rock-chips.com>
4f16e43f8SFrank Wang  *
5f16e43f8SFrank Wang  * SPDX-License-Identifier:	GPL-2.0+
6f16e43f8SFrank Wang  */
7f16e43f8SFrank Wang 
8866d7966SJoseph Chen #include <asm/io.h>
9866d7966SJoseph Chen #include <asm/arch/boot_mode.h>
10829f2b85SFrank Wang #include <asm/arch/chip_info.h>
11dfbf26e8STony Xu #include <write_keybox.h>
12e66d4537SJon Lin #include <linux/mtd/mtd.h>
130d0c3248SFrank Wang 
140d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
150d0c3248SFrank Wang #include <asm/arch/vendor.h>
160d0c3248SFrank Wang #endif
170d0c3248SFrank Wang 
18f16e43f8SFrank Wang #include <rockusb.h>
19f16e43f8SFrank Wang 
20f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_CLASS	0xff
21f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_SUB_CLASS	0x06
22f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_PROTOCOL	0x05
23f16e43f8SFrank Wang 
24e66d4537SJon Lin #define ROCKCHIP_FLASH_BLOCK_SIZE	1024
25e66d4537SJon Lin #define ROCKCHIP_FLASH_PAGE_SIZE	4
26e66d4537SJon Lin 
27f16e43f8SFrank Wang static struct usb_interface_descriptor rkusb_intf_desc = {
28f16e43f8SFrank Wang 	.bLength		= USB_DT_INTERFACE_SIZE,
29f16e43f8SFrank Wang 	.bDescriptorType	= USB_DT_INTERFACE,
30f16e43f8SFrank Wang 	.bInterfaceNumber	= 0x00,
31f16e43f8SFrank Wang 	.bAlternateSetting	= 0x00,
32f16e43f8SFrank Wang 	.bNumEndpoints		= 0x02,
33f16e43f8SFrank Wang 	.bInterfaceClass	= ROCKUSB_INTERFACE_CLASS,
34f16e43f8SFrank Wang 	.bInterfaceSubClass	= ROCKUSB_INTERFACE_SUB_CLASS,
35f16e43f8SFrank Wang 	.bInterfaceProtocol	= ROCKUSB_INTERFACE_PROTOCOL,
36f16e43f8SFrank Wang };
37f16e43f8SFrank Wang 
38f16e43f8SFrank Wang static struct usb_descriptor_header *rkusb_fs_function[] = {
39f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&rkusb_intf_desc,
40f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&fsg_fs_bulk_in_desc,
41f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&fsg_fs_bulk_out_desc,
42f16e43f8SFrank Wang 	NULL,
43f16e43f8SFrank Wang };
44f16e43f8SFrank Wang 
45f16e43f8SFrank Wang static struct usb_descriptor_header *rkusb_hs_function[] = {
46f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&rkusb_intf_desc,
47f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&fsg_hs_bulk_in_desc,
48f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&fsg_hs_bulk_out_desc,
49f16e43f8SFrank Wang 	NULL,
50f16e43f8SFrank Wang };
51f16e43f8SFrank Wang 
5226dd3474SWilliam Wu static struct usb_descriptor_header *rkusb_ss_function[] = {
5326dd3474SWilliam Wu 	(struct usb_descriptor_header *)&rkusb_intf_desc,
5426dd3474SWilliam Wu 	(struct usb_descriptor_header *)&fsg_ss_bulk_in_desc,
5526dd3474SWilliam Wu 	(struct usb_descriptor_header *)&fsg_ss_bulk_in_comp_desc,
5626dd3474SWilliam Wu 	(struct usb_descriptor_header *)&fsg_ss_bulk_out_desc,
5726dd3474SWilliam Wu 	(struct usb_descriptor_header *)&fsg_ss_bulk_out_comp_desc,
5826dd3474SWilliam Wu 	NULL,
5926dd3474SWilliam Wu };
6026dd3474SWilliam Wu 
61f16e43f8SFrank Wang struct rk_flash_info {
62f16e43f8SFrank Wang 	u32	flash_size;
63f16e43f8SFrank Wang 	u16	block_size;
64f16e43f8SFrank Wang 	u8	page_size;
65f16e43f8SFrank Wang 	u8	ecc_bits;
66f16e43f8SFrank Wang 	u8	access_time;
67f16e43f8SFrank Wang 	u8	manufacturer;
68f16e43f8SFrank Wang 	u8	flash_mask;
69f16e43f8SFrank Wang } __packed;
70f16e43f8SFrank Wang 
715b081643SFrank Wang static int rkusb_rst_code; /* The subcode in reset command (0xFF) */
725b081643SFrank Wang 
73f16e43f8SFrank Wang int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
74f16e43f8SFrank Wang {
75ba437c8cSFrank Wang 	if (IS_RKUSB_UMS_DNL(name)) {
76c0acb0f2SFrank Wang 		/* Fix to Rockchip's VID and PID */
77ba437c8cSFrank Wang 		dev->idVendor  = __constant_cpu_to_le16(0x2207);
78ba437c8cSFrank Wang 		dev->idProduct = __constant_cpu_to_le16(CONFIG_ROCKUSB_G_DNL_PID);
79ba437c8cSFrank Wang 
80f16e43f8SFrank Wang 		/* Enumerate as a loader device */
8195424692SJoseph Chen #if defined(CONFIG_SUPPORT_USBPLUG)
8295424692SJoseph Chen 		dev->bcdUSB = cpu_to_le16(0x0200);
8395424692SJoseph Chen #else
84f16e43f8SFrank Wang 		dev->bcdUSB = cpu_to_le16(0x0201);
8595424692SJoseph Chen #endif
86c0acb0f2SFrank Wang 	} else if (!strncmp(name, "usb_dnl_fastboot", 16)) {
87c0acb0f2SFrank Wang 		/* Fix to Google's VID and PID */
88c0acb0f2SFrank Wang 		dev->idVendor  = __constant_cpu_to_le16(0x18d1);
89c0acb0f2SFrank Wang 		dev->idProduct = __constant_cpu_to_le16(0xd00d);
90*ca422507SYifeng Zhao 	} else if (!strncmp(name, "usb_dnl_dfu", 11)) {
91*ca422507SYifeng Zhao 		/* Fix to Rockchip's VID and PID for DFU */
92*ca422507SYifeng Zhao 		dev->idVendor  = cpu_to_le16(0x2207);
93*ca422507SYifeng Zhao 		dev->idProduct = cpu_to_le16(0x0107);
94ba437c8cSFrank Wang 	}
95f16e43f8SFrank Wang 
96f16e43f8SFrank Wang 	return 0;
97f16e43f8SFrank Wang }
98f16e43f8SFrank Wang 
99f16e43f8SFrank Wang __maybe_unused
100f16e43f8SFrank Wang static inline void dump_cbw(struct fsg_bulk_cb_wrap *cbw)
101f16e43f8SFrank Wang {
102f16e43f8SFrank Wang 	assert(!cbw);
103f16e43f8SFrank Wang 
104f16e43f8SFrank Wang 	debug("%s:\n", __func__);
105f16e43f8SFrank Wang 	debug("Signature %x\n", cbw->Signature);
106f16e43f8SFrank Wang 	debug("Tag %x\n", cbw->Tag);
107f16e43f8SFrank Wang 	debug("DataTransferLength %x\n", cbw->DataTransferLength);
108f16e43f8SFrank Wang 	debug("Flags %x\n", cbw->Flags);
109f16e43f8SFrank Wang 	debug("LUN %x\n", cbw->Lun);
110f16e43f8SFrank Wang 	debug("Length %x\n", cbw->Length);
111f16e43f8SFrank Wang 	debug("OptionCode %x\n", cbw->CDB[0]);
112f16e43f8SFrank Wang 	debug("SubCode %x\n", cbw->CDB[1]);
113f16e43f8SFrank Wang 	debug("SectorAddr %x\n", get_unaligned_be32(&cbw->CDB[2]));
114f16e43f8SFrank Wang 	debug("BlkSectors %x\n\n", get_unaligned_be16(&cbw->CDB[7]));
115f16e43f8SFrank Wang }
116f16e43f8SFrank Wang 
117f16e43f8SFrank Wang static int rkusb_check_lun(struct fsg_common *common)
118f16e43f8SFrank Wang {
119f16e43f8SFrank Wang 	struct fsg_lun *curlun;
120f16e43f8SFrank Wang 
121f16e43f8SFrank Wang 	/* Check the LUN */
122f16e43f8SFrank Wang 	if (common->lun >= 0 && common->lun < common->nluns) {
123f16e43f8SFrank Wang 		curlun = &common->luns[common->lun];
124f16e43f8SFrank Wang 		if (common->cmnd[0] != SC_REQUEST_SENSE) {
125f16e43f8SFrank Wang 			curlun->sense_data = SS_NO_SENSE;
126f16e43f8SFrank Wang 			curlun->info_valid = 0;
127f16e43f8SFrank Wang 		}
128f16e43f8SFrank Wang 	} else {
129f16e43f8SFrank Wang 		curlun = NULL;
130f16e43f8SFrank Wang 		common->bad_lun_okay = 0;
131f16e43f8SFrank Wang 
132f16e43f8SFrank Wang 		/*
133f16e43f8SFrank Wang 		 * INQUIRY and REQUEST SENSE commands are explicitly allowed
134f16e43f8SFrank Wang 		 * to use unsupported LUNs; all others may not.
135f16e43f8SFrank Wang 		 */
136f16e43f8SFrank Wang 		if (common->cmnd[0] != SC_INQUIRY &&
137f16e43f8SFrank Wang 		    common->cmnd[0] != SC_REQUEST_SENSE) {
138f16e43f8SFrank Wang 			debug("unsupported LUN %d\n", common->lun);
139f16e43f8SFrank Wang 			return -EINVAL;
140f16e43f8SFrank Wang 		}
141f16e43f8SFrank Wang 	}
142f16e43f8SFrank Wang 
143f16e43f8SFrank Wang 	return 0;
144f16e43f8SFrank Wang }
145f16e43f8SFrank Wang 
146f16e43f8SFrank Wang static void __do_reset(struct usb_ep *ep, struct usb_request *req)
147f16e43f8SFrank Wang {
1485b081643SFrank Wang 	u32 boot_flag = BOOT_NORMAL;
1495b081643SFrank Wang 
1505b081643SFrank Wang 	if (rkusb_rst_code == 0x03)
1515b081643SFrank Wang 		boot_flag = BOOT_BROM_DOWNLOAD;
1525b081643SFrank Wang 
1535b081643SFrank Wang 	rkusb_rst_code = 0; /* restore to default */
1545b081643SFrank Wang 	writel(boot_flag, (void *)CONFIG_ROCKCHIP_BOOT_MODE_REG);
155866d7966SJoseph Chen 
156f16e43f8SFrank Wang 	do_reset(NULL, 0, 0, NULL);
157f16e43f8SFrank Wang }
158f16e43f8SFrank Wang 
159f16e43f8SFrank Wang static int rkusb_do_reset(struct fsg_common *common,
160f16e43f8SFrank Wang 			  struct fsg_buffhd *bh)
161f16e43f8SFrank Wang {
162f16e43f8SFrank Wang 	common->data_size_from_cmnd = common->cmnd[4];
163f16e43f8SFrank Wang 	common->residue = 0;
164f16e43f8SFrank Wang 	bh->inreq->complete = __do_reset;
165f16e43f8SFrank Wang 	bh->state = BUF_STATE_EMPTY;
166f16e43f8SFrank Wang 
1675b081643SFrank Wang 	rkusb_rst_code = !common->cmnd[1] ? 0xff : common->cmnd[1];
168f16e43f8SFrank Wang 	return 0;
169f16e43f8SFrank Wang }
170f16e43f8SFrank Wang 
171f16e43f8SFrank Wang static int rkusb_do_test_unit_ready(struct fsg_common *common,
172f16e43f8SFrank Wang 				    struct fsg_buffhd *bh)
173f16e43f8SFrank Wang {
174f16e43f8SFrank Wang 	common->residue = 0x06 << 24; /* Max block xfer support from host */
175f16e43f8SFrank Wang 	common->data_dir = DATA_DIR_NONE;
176f16e43f8SFrank Wang 	bh->state = BUF_STATE_EMPTY;
177f16e43f8SFrank Wang 
178f16e43f8SFrank Wang 	return 0;
179f16e43f8SFrank Wang }
180f16e43f8SFrank Wang 
181f16e43f8SFrank Wang static int rkusb_do_read_flash_id(struct fsg_common *common,
182f16e43f8SFrank Wang 				  struct fsg_buffhd *bh)
183f16e43f8SFrank Wang {
184f16e43f8SFrank Wang 	u8 *buf = (u8 *)bh->buf;
185e0023032SKever Yang 	u32 len = 5;
186d7386f60SFrank Wang 	enum if_type type = ums[common->lun].block_dev.if_type;
187f16e43f8SFrank Wang 
188d7386f60SFrank Wang 	if (type == IF_TYPE_MMC)
189f16e43f8SFrank Wang 		memcpy((void *)&buf[0], "EMMC ", 5);
190d7386f60SFrank Wang 	else if (type == IF_TYPE_RKNAND)
191d7386f60SFrank Wang 		memcpy((void *)&buf[0], "NAND ", 5);
192d7386f60SFrank Wang 	else
193d7386f60SFrank Wang 		memcpy((void *)&buf[0], "UNKN ", 5); /* unknown */
194f16e43f8SFrank Wang 
195f16e43f8SFrank Wang 	/* Set data xfer size */
196f16e43f8SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
197e0023032SKever Yang 	common->data_size = len;
198f16e43f8SFrank Wang 
199f16e43f8SFrank Wang 	return len;
200f16e43f8SFrank Wang }
201f16e43f8SFrank Wang 
202f16e43f8SFrank Wang static int rkusb_do_test_bad_block(struct fsg_common *common,
203f16e43f8SFrank Wang 				   struct fsg_buffhd *bh)
204f16e43f8SFrank Wang {
205f16e43f8SFrank Wang 	u8 *buf = (u8 *)bh->buf;
206e0023032SKever Yang 	u32 len = 64;
207f16e43f8SFrank Wang 
208f16e43f8SFrank Wang 	memset((void *)&buf[0], 0, len);
209f16e43f8SFrank Wang 
210f16e43f8SFrank Wang 	/* Set data xfer size */
211f16e43f8SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
212e0023032SKever Yang 	common->data_size = len;
213f16e43f8SFrank Wang 
214f16e43f8SFrank Wang 	return len;
215f16e43f8SFrank Wang }
216f16e43f8SFrank Wang 
217f16e43f8SFrank Wang static int rkusb_do_read_flash_info(struct fsg_common *common,
218f16e43f8SFrank Wang 				    struct fsg_buffhd *bh)
219f16e43f8SFrank Wang {
220e66d4537SJon Lin 	struct blk_desc *desc = &ums[common->lun].block_dev;
221f16e43f8SFrank Wang 	u8 *buf = (u8 *)bh->buf;
222d23ec8c4SKever Yang 	u32 len = sizeof(struct rk_flash_info);
223f16e43f8SFrank Wang 	struct rk_flash_info finfo = {
224e66d4537SJon Lin 		.block_size = ROCKCHIP_FLASH_BLOCK_SIZE,
225f16e43f8SFrank Wang 		.ecc_bits = 0,
226e66d4537SJon Lin 		.page_size = ROCKCHIP_FLASH_PAGE_SIZE,
227f16e43f8SFrank Wang 		.access_time = 40,
228f16e43f8SFrank Wang 		.manufacturer = 0,
229f16e43f8SFrank Wang 		.flash_mask = 0
230f16e43f8SFrank Wang 	};
231f16e43f8SFrank Wang 
232e66d4537SJon Lin 	finfo.flash_size = (u32)desc->lba;
233e66d4537SJon Lin 
234e66d4537SJon Lin 	if (desc->if_type == IF_TYPE_MTD &&
235e66d4537SJon Lin 	    (desc->devnum == BLK_MTD_NAND ||
236e66d4537SJon Lin 	    desc->devnum == BLK_MTD_SPI_NAND)) {
237e66d4537SJon Lin 		struct mtd_info *mtd = (struct mtd_info *)desc->bdev->priv;
238e66d4537SJon Lin 
239e66d4537SJon Lin 		if (mtd) {
240e66d4537SJon Lin 			finfo.block_size = mtd->erasesize >> 9;
241e66d4537SJon Lin 			finfo.page_size = mtd->writesize >> 9;
242e66d4537SJon Lin 		}
243e66d4537SJon Lin 	}
244e66d4537SJon Lin 
245e66d4537SJon Lin 	debug("Flash info: block_size= %x page_size= %x\n", finfo.block_size,
246e66d4537SJon Lin 	      finfo.page_size);
247e66d4537SJon Lin 
248f16e43f8SFrank Wang 	if (finfo.flash_size)
249f16e43f8SFrank Wang 		finfo.flash_mask = 1;
250f16e43f8SFrank Wang 
251f16e43f8SFrank Wang 	memset((void *)&buf[0], 0, len);
252f16e43f8SFrank Wang 	memcpy((void *)&buf[0], (void *)&finfo, len);
253f16e43f8SFrank Wang 
254f16e43f8SFrank Wang 	/* Set data xfer size */
255f16e43f8SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
256d23ec8c4SKever Yang         /* legacy upgrade_tool does not set correct transfer size */
257d23ec8c4SKever Yang 	common->data_size = len;
258f16e43f8SFrank Wang 
259f16e43f8SFrank Wang 	return len;
260f16e43f8SFrank Wang }
261f16e43f8SFrank Wang 
262829f2b85SFrank Wang static int rkusb_do_get_chip_info(struct fsg_common *common,
263829f2b85SFrank Wang 				  struct fsg_buffhd *bh)
264829f2b85SFrank Wang {
265829f2b85SFrank Wang 	u8 *buf = (u8 *)bh->buf;
266829f2b85SFrank Wang 	u32 len = common->data_size;
267829f2b85SFrank Wang 	u32 chip_info[4];
268829f2b85SFrank Wang 
269829f2b85SFrank Wang 	memset((void *)chip_info, 0, sizeof(chip_info));
270829f2b85SFrank Wang 	rockchip_rockusb_get_chip_info(chip_info);
271829f2b85SFrank Wang 
272829f2b85SFrank Wang 	memset((void *)&buf[0], 0, len);
273829f2b85SFrank Wang 	memcpy((void *)&buf[0], (void *)chip_info, len);
274829f2b85SFrank Wang 
275829f2b85SFrank Wang 	/* Set data xfer size */
276829f2b85SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
277829f2b85SFrank Wang 
278829f2b85SFrank Wang 	return len;
279829f2b85SFrank Wang }
280829f2b85SFrank Wang 
281f16e43f8SFrank Wang static int rkusb_do_lba_erase(struct fsg_common *common,
282f16e43f8SFrank Wang 			      struct fsg_buffhd *bh)
283f16e43f8SFrank Wang {
284f16e43f8SFrank Wang 	struct fsg_lun *curlun = &common->luns[common->lun];
285f16e43f8SFrank Wang 	u32 lba, amount;
286f16e43f8SFrank Wang 	loff_t file_offset;
287f16e43f8SFrank Wang 	int rc;
288f16e43f8SFrank Wang 
289f16e43f8SFrank Wang 	lba = get_unaligned_be32(&common->cmnd[2]);
290f16e43f8SFrank Wang 	if (lba >= curlun->num_sectors) {
291f16e43f8SFrank Wang 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
292f16e43f8SFrank Wang 		rc = -EINVAL;
293f16e43f8SFrank Wang 		goto out;
294f16e43f8SFrank Wang 	}
295f16e43f8SFrank Wang 
296f16e43f8SFrank Wang 	file_offset = ((loff_t) lba) << 9;
297f16e43f8SFrank Wang 	amount = get_unaligned_be16(&common->cmnd[7]) << 9;
298f16e43f8SFrank Wang 	if (unlikely(amount == 0)) {
299f16e43f8SFrank Wang 		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
300f16e43f8SFrank Wang 		rc = -EIO;
301f16e43f8SFrank Wang 		goto out;
302f16e43f8SFrank Wang 	}
303f16e43f8SFrank Wang 
304f16e43f8SFrank Wang 	/* Perform the erase */
305f16e43f8SFrank Wang 	rc = ums[common->lun].erase_sector(&ums[common->lun],
306f16e43f8SFrank Wang 			       file_offset / SECTOR_SIZE,
307f16e43f8SFrank Wang 			       amount / SECTOR_SIZE);
308f16e43f8SFrank Wang 	if (!rc) {
309f16e43f8SFrank Wang 		curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
310f16e43f8SFrank Wang 		rc = -EIO;
311f16e43f8SFrank Wang 	}
312f16e43f8SFrank Wang 
313f16e43f8SFrank Wang out:
314f16e43f8SFrank Wang 	common->data_dir = DATA_DIR_NONE;
315f16e43f8SFrank Wang 	bh->state = BUF_STATE_EMPTY;
316f16e43f8SFrank Wang 
317f16e43f8SFrank Wang 	return rc;
318f16e43f8SFrank Wang }
319f16e43f8SFrank Wang 
320e66d4537SJon Lin static int rkusb_do_erase_force(struct fsg_common *common,
321e66d4537SJon Lin 				struct fsg_buffhd *bh)
322e66d4537SJon Lin {
323e66d4537SJon Lin 	struct blk_desc *desc = &ums[common->lun].block_dev;
324e66d4537SJon Lin 	struct fsg_lun *curlun = &common->luns[common->lun];
325e66d4537SJon Lin 	u16 block_size = ROCKCHIP_FLASH_BLOCK_SIZE;
326e66d4537SJon Lin 	u32 lba, amount;
327e66d4537SJon Lin 	loff_t file_offset;
328e66d4537SJon Lin 	int rc;
329e66d4537SJon Lin 
330e66d4537SJon Lin 	lba = get_unaligned_be32(&common->cmnd[2]);
331e66d4537SJon Lin 	if (lba >= curlun->num_sectors) {
332e66d4537SJon Lin 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
333e66d4537SJon Lin 		rc = -EINVAL;
334e66d4537SJon Lin 		goto out;
335e66d4537SJon Lin 	}
336e66d4537SJon Lin 
337e66d4537SJon Lin 	if (desc->if_type == IF_TYPE_MTD &&
338e66d4537SJon Lin 	    (desc->devnum == BLK_MTD_NAND ||
339e66d4537SJon Lin 	    desc->devnum == BLK_MTD_SPI_NAND)) {
340e66d4537SJon Lin 		struct mtd_info *mtd = (struct mtd_info *)desc->bdev->priv;
341e66d4537SJon Lin 
342e66d4537SJon Lin 		if (mtd)
343e66d4537SJon Lin 			block_size = mtd->erasesize >> 9;
344e66d4537SJon Lin 	}
345e66d4537SJon Lin 
346e66d4537SJon Lin 	file_offset = ((loff_t)lba) * block_size;
347e66d4537SJon Lin 	amount = get_unaligned_be16(&common->cmnd[7]) * block_size;
348e66d4537SJon Lin 
349e66d4537SJon Lin 	debug("%s lba= %x, nsec= %x\n", __func__, lba,
350e66d4537SJon Lin 	      (u32)get_unaligned_be16(&common->cmnd[7]));
351e66d4537SJon Lin 
352e66d4537SJon Lin 	if (unlikely(amount == 0)) {
353e66d4537SJon Lin 		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
354e66d4537SJon Lin 		rc = -EIO;
355e66d4537SJon Lin 		goto out;
356e66d4537SJon Lin 	}
357e66d4537SJon Lin 
358e66d4537SJon Lin 	/* Perform the erase */
359e66d4537SJon Lin 	rc = ums[common->lun].erase_sector(&ums[common->lun],
360e66d4537SJon Lin 					   file_offset,
361e66d4537SJon Lin 					   amount);
362e66d4537SJon Lin 	if (!rc) {
363e66d4537SJon Lin 		curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
364e66d4537SJon Lin 		rc = -EIO;
365e66d4537SJon Lin 	}
366e66d4537SJon Lin 
367e66d4537SJon Lin out:
368e66d4537SJon Lin 	common->data_dir = DATA_DIR_NONE;
369e66d4537SJon Lin 	bh->state = BUF_STATE_EMPTY;
370e66d4537SJon Lin 
371e66d4537SJon Lin 	return rc;
372e66d4537SJon Lin }
373e66d4537SJon Lin 
3740d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
3750d0c3248SFrank Wang static int rkusb_do_vs_write(struct fsg_common *common)
3760d0c3248SFrank Wang {
3770d0c3248SFrank Wang 	struct fsg_lun		*curlun = &common->luns[common->lun];
3780d0c3248SFrank Wang 	u16			type = get_unaligned_be16(&common->cmnd[4]);
3790d0c3248SFrank Wang 	struct vendor_item	*vhead;
3800d0c3248SFrank Wang 	struct fsg_buffhd	*bh;
3810d0c3248SFrank Wang 	void			*data;
3820d0c3248SFrank Wang 	int			rc;
3830d0c3248SFrank Wang 
3840d0c3248SFrank Wang 	if (common->data_size >= (u32)65536) {
3850d0c3248SFrank Wang 		/* _MUST_ small than 64K */
3860d0c3248SFrank Wang 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
3870d0c3248SFrank Wang 		return -EINVAL;
3880d0c3248SFrank Wang 	}
3890d0c3248SFrank Wang 
3900d0c3248SFrank Wang 	common->residue         = common->data_size;
3910d0c3248SFrank Wang 	common->usb_amount_left = common->data_size;
3920d0c3248SFrank Wang 
3930d0c3248SFrank Wang 	/* Carry out the file writes */
3940d0c3248SFrank Wang 	if (unlikely(common->data_size == 0))
3950d0c3248SFrank Wang 		return -EIO; /* No data to write */
3960d0c3248SFrank Wang 
3970d0c3248SFrank Wang 	for (;;) {
3980d0c3248SFrank Wang 		if (common->usb_amount_left > 0) {
3990d0c3248SFrank Wang 			/* Wait for the next buffer to become available */
4000d0c3248SFrank Wang 			bh = common->next_buffhd_to_fill;
4010d0c3248SFrank Wang 			if (bh->state != BUF_STATE_EMPTY)
4020d0c3248SFrank Wang 				goto wait;
4030d0c3248SFrank Wang 
4040d0c3248SFrank Wang 			/* Request the next buffer */
4050d0c3248SFrank Wang 			common->usb_amount_left      -= common->data_size;
4060d0c3248SFrank Wang 			bh->outreq->length	     = common->data_size;
4070d0c3248SFrank Wang 			bh->bulk_out_intended_length = common->data_size;
4080d0c3248SFrank Wang 			bh->outreq->short_not_ok     = 1;
4090d0c3248SFrank Wang 
4100d0c3248SFrank Wang 			START_TRANSFER_OR(common, bulk_out, bh->outreq,
4110d0c3248SFrank Wang 					  &bh->outreq_busy, &bh->state)
4120d0c3248SFrank Wang 				/*
4130d0c3248SFrank Wang 				 * Don't know what to do if
4140d0c3248SFrank Wang 				 * common->fsg is NULL
4150d0c3248SFrank Wang 				 */
4160d0c3248SFrank Wang 				return -EIO;
4170d0c3248SFrank Wang 			common->next_buffhd_to_fill = bh->next;
4180d0c3248SFrank Wang 		} else {
4190d0c3248SFrank Wang 			/* Then, wait for the data to become available */
4200d0c3248SFrank Wang 			bh = common->next_buffhd_to_drain;
4210d0c3248SFrank Wang 			if (bh->state != BUF_STATE_FULL)
4220d0c3248SFrank Wang 				goto wait;
4230d0c3248SFrank Wang 
4240d0c3248SFrank Wang 			common->next_buffhd_to_drain = bh->next;
4250d0c3248SFrank Wang 			bh->state = BUF_STATE_EMPTY;
4260d0c3248SFrank Wang 
4270d0c3248SFrank Wang 			/* Did something go wrong with the transfer? */
4280d0c3248SFrank Wang 			if (bh->outreq->status != 0) {
4290d0c3248SFrank Wang 				curlun->sense_data = SS_COMMUNICATION_FAILURE;
4300d0c3248SFrank Wang 				curlun->info_valid = 1;
4310d0c3248SFrank Wang 				break;
4320d0c3248SFrank Wang 			}
4330d0c3248SFrank Wang 
4340d0c3248SFrank Wang 			/* Perform the write */
4350d0c3248SFrank Wang 			vhead = (struct vendor_item *)bh->buf;
4360d0c3248SFrank Wang 			data  = bh->buf + sizeof(struct vendor_item);
4370d0c3248SFrank Wang 
4380d0c3248SFrank Wang 			if (!type) {
4390d0c3248SFrank Wang 				/* Vendor storage */
4400d0c3248SFrank Wang 				rc = vendor_storage_write(vhead->id,
4410d0c3248SFrank Wang 							  (char __user *)data,
4420d0c3248SFrank Wang 							  vhead->size);
44319652be0SFrank Wang 				if (rc < 0) {
44419652be0SFrank Wang 					curlun->sense_data = SS_WRITE_ERROR;
4450d0c3248SFrank Wang 					return -EIO;
44619652be0SFrank Wang 				}
4470d0c3248SFrank Wang 			} else {
4480d0c3248SFrank Wang 				/* RPMB */
4496f0347c8Stony.xu 				rc =
4506f0347c8Stony.xu 				write_keybox_to_secure_storage((u8 *)data,
4516f0347c8Stony.xu 							       vhead->size);
45219652be0SFrank Wang 				if (rc < 0) {
45319652be0SFrank Wang 					curlun->sense_data = SS_WRITE_ERROR;
4546f0347c8Stony.xu 					return -EIO;
4550d0c3248SFrank Wang 				}
45619652be0SFrank Wang 			}
4570d0c3248SFrank Wang 
4580d0c3248SFrank Wang 			common->residue -= common->data_size;
4590d0c3248SFrank Wang 
4600d0c3248SFrank Wang 			/* Did the host decide to stop early? */
4610d0c3248SFrank Wang 			if (bh->outreq->actual != bh->outreq->length)
4620d0c3248SFrank Wang 				common->short_packet_received = 1;
4630d0c3248SFrank Wang 			break; /* Command done */
4640d0c3248SFrank Wang 		}
4650d0c3248SFrank Wang wait:
4660d0c3248SFrank Wang 		/* Wait for something to happen */
4670d0c3248SFrank Wang 		rc = sleep_thread(common);
4680d0c3248SFrank Wang 		if (rc)
4690d0c3248SFrank Wang 			return rc;
4700d0c3248SFrank Wang 	}
4710d0c3248SFrank Wang 
4720d0c3248SFrank Wang 	return -EIO; /* No default reply */
4730d0c3248SFrank Wang }
4740d0c3248SFrank Wang 
4750d0c3248SFrank Wang static int rkusb_do_vs_read(struct fsg_common *common)
4760d0c3248SFrank Wang {
4770d0c3248SFrank Wang 	struct fsg_lun		*curlun = &common->luns[common->lun];
4780d0c3248SFrank Wang 	u16			type = get_unaligned_be16(&common->cmnd[4]);
4790d0c3248SFrank Wang 	struct vendor_item	*vhead;
4800d0c3248SFrank Wang 	struct fsg_buffhd	*bh;
4810d0c3248SFrank Wang 	void			*data;
4820d0c3248SFrank Wang 	int			rc;
4830d0c3248SFrank Wang 
4840d0c3248SFrank Wang 	if (common->data_size >= (u32)65536) {
4850d0c3248SFrank Wang 		/* _MUST_ small than 64K */
4860d0c3248SFrank Wang 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
4870d0c3248SFrank Wang 		return -EINVAL;
4880d0c3248SFrank Wang 	}
4890d0c3248SFrank Wang 
4900d0c3248SFrank Wang 	common->residue         = common->data_size;
4910d0c3248SFrank Wang 	common->usb_amount_left = common->data_size;
4920d0c3248SFrank Wang 
4930d0c3248SFrank Wang 	/* Carry out the file reads */
4940d0c3248SFrank Wang 	if (unlikely(common->data_size == 0))
4950d0c3248SFrank Wang 		return -EIO; /* No default reply */
4960d0c3248SFrank Wang 
4970d0c3248SFrank Wang 	for (;;) {
4980d0c3248SFrank Wang 		/* Wait for the next buffer to become available */
4990d0c3248SFrank Wang 		bh = common->next_buffhd_to_fill;
5000d0c3248SFrank Wang 		while (bh->state != BUF_STATE_EMPTY) {
5010d0c3248SFrank Wang 			rc = sleep_thread(common);
5020d0c3248SFrank Wang 			if (rc)
5030d0c3248SFrank Wang 				return rc;
5040d0c3248SFrank Wang 		}
5050d0c3248SFrank Wang 
5060d0c3248SFrank Wang 		memset(bh->buf, 0, FSG_BUFLEN);
5070d0c3248SFrank Wang 		vhead = (struct vendor_item *)bh->buf;
5080d0c3248SFrank Wang 		data  = bh->buf + sizeof(struct vendor_item);
5090d0c3248SFrank Wang 		vhead->id = get_unaligned_be16(&common->cmnd[2]);
5100d0c3248SFrank Wang 
5110d0c3248SFrank Wang 		if (!type) {
5120d0c3248SFrank Wang 			/* Vendor storage */
5130d0c3248SFrank Wang 			rc = vendor_storage_read(vhead->id,
5140d0c3248SFrank Wang 						 (char __user *)data,
5150d0c3248SFrank Wang 						 common->data_size);
51619652be0SFrank Wang 			if (!rc) {
51719652be0SFrank Wang 				curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
5180d0c3248SFrank Wang 				return -EIO;
51919652be0SFrank Wang 			}
5200d0c3248SFrank Wang 			vhead->size = rc;
5210d0c3248SFrank Wang 		} else {
5220d0c3248SFrank Wang 			/* RPMB */
523700a3668STony Xu 			rc =
524700a3668STony Xu 			read_raw_data_from_secure_storage((u8 *)data,
525700a3668STony Xu 							  common->data_size);
52619652be0SFrank Wang 			if (!rc) {
52719652be0SFrank Wang 				curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
528700a3668STony Xu 				return -EIO;
52919652be0SFrank Wang 			}
530700a3668STony Xu 			vhead->size = rc;
5310d0c3248SFrank Wang 		}
5320d0c3248SFrank Wang 
5330d0c3248SFrank Wang 		common->residue   -= common->data_size;
5340d0c3248SFrank Wang 		bh->inreq->length = common->data_size;
5350d0c3248SFrank Wang 		bh->state         = BUF_STATE_FULL;
5360d0c3248SFrank Wang 
5370d0c3248SFrank Wang 		break; /* No more left to read */
5380d0c3248SFrank Wang 	}
5390d0c3248SFrank Wang 
5400d0c3248SFrank Wang 	return -EIO; /* No default reply */
5410d0c3248SFrank Wang }
5420d0c3248SFrank Wang #endif
5430d0c3248SFrank Wang 
544f16e43f8SFrank Wang static int rkusb_do_read_capacity(struct fsg_common *common,
545f16e43f8SFrank Wang 				  struct fsg_buffhd *bh)
546f16e43f8SFrank Wang {
547f16e43f8SFrank Wang 	u8 *buf = (u8 *)bh->buf;
548f16e43f8SFrank Wang 	u32 len = common->data_size;
549d015bf41SFrank Wang 	enum if_type type = ums[common->lun].block_dev.if_type;
550e66d4537SJon Lin 	int devnum = ums[common->lun].block_dev.devnum;
551f16e43f8SFrank Wang 
552f16e43f8SFrank Wang 	/*
553f16e43f8SFrank Wang 	 * bit[0]: Direct LBA, 0: Disabled;
5540d0c3248SFrank Wang 	 * bit[1]: Vendor Storage API, 0: Disabed (default);
555d015bf41SFrank Wang 	 * bit[2]: First 4M Access, 0: Disabled;
5560d0c3248SFrank Wang 	 * bit[3]: Read LBA On, 0: Disabed (default);
5570d0c3248SFrank Wang 	 * bit[4]: New Vendor Storage API, 0: Disabed;
5580d0c3248SFrank Wang 	 * bit[5:63}: Reserved.
559f16e43f8SFrank Wang 	 */
560f16e43f8SFrank Wang 	memset((void *)&buf[0], 0, len);
561af5a2012SJason Zhu 	if (type == IF_TYPE_MMC || type == IF_TYPE_SD)
5620d0c3248SFrank Wang 		buf[0] = BIT(0) | BIT(2) | BIT(4);
5630d0c3248SFrank Wang 	else
5640d0c3248SFrank Wang 		buf[0] = BIT(0) | BIT(4);
565f16e43f8SFrank Wang 
566e66d4537SJon Lin 	if (type == IF_TYPE_MTD &&
567e66d4537SJon Lin 	    (devnum == BLK_MTD_NAND ||
568e66d4537SJon Lin 	    devnum == BLK_MTD_SPI_NAND))
569e66d4537SJon Lin 		buf[0] |= (1 << 6);
570e66d4537SJon Lin 
571007849d8SYifeng Zhao #if defined(CONFIG_ROCKCHIP_RK3568)
572007849d8SYifeng Zhao 	buf[1] = BIT(0);
573007849d8SYifeng Zhao #endif
574f16e43f8SFrank Wang 	/* Set data xfer size */
575e66d4537SJon Lin 	common->residue = len;
576e66d4537SJon Lin 	common->data_size_from_cmnd = len;
577f16e43f8SFrank Wang 
578f16e43f8SFrank Wang 	return len;
579f16e43f8SFrank Wang }
580f16e43f8SFrank Wang 
581d23ec8c4SKever Yang static void rkusb_fixup_cbwcb(struct fsg_common *common,
582d23ec8c4SKever Yang 			      struct fsg_buffhd *bh)
583d23ec8c4SKever Yang {
584d23ec8c4SKever Yang 	struct usb_request      *req = bh->outreq;
585d23ec8c4SKever Yang 	struct fsg_bulk_cb_wrap *cbw = req->buf;
586d23ec8c4SKever Yang 
587d23ec8c4SKever Yang 	/* FIXME cbw.DataTransferLength was not set by Upgrade Tool */
588d23ec8c4SKever Yang 	common->data_size = le32_to_cpu(cbw->DataTransferLength);
589d23ec8c4SKever Yang 	if (common->data_size == 0) {
590d23ec8c4SKever Yang 		common->data_size =
591d23ec8c4SKever Yang 		get_unaligned_be16(&common->cmnd[7]) << 9;
592d23ec8c4SKever Yang 		printf("Trasfer Length NOT set, please use new version tool\n");
593d23ec8c4SKever Yang 		debug("%s %d, cmnd1 %x\n", __func__,
594d23ec8c4SKever Yang 		      get_unaligned_be16(&common->cmnd[7]),
595d23ec8c4SKever Yang 		      get_unaligned_be16(&common->cmnd[1]));
596d23ec8c4SKever Yang 	}
597d23ec8c4SKever Yang 	if (cbw->Flags & USB_BULK_IN_FLAG)
598d23ec8c4SKever Yang 		common->data_dir = DATA_DIR_TO_HOST;
599d23ec8c4SKever Yang 	else
600d23ec8c4SKever Yang 		common->data_dir = DATA_DIR_FROM_HOST;
601d23ec8c4SKever Yang 
602d23ec8c4SKever Yang 	/* Not support */
603d23ec8c4SKever Yang 	common->cmnd[1] = 0;
604d23ec8c4SKever Yang }
605d23ec8c4SKever Yang 
606f16e43f8SFrank Wang static int rkusb_cmd_process(struct fsg_common *common,
607f16e43f8SFrank Wang 			     struct fsg_buffhd *bh, int *reply)
608f16e43f8SFrank Wang {
609f16e43f8SFrank Wang 	struct usb_request	*req = bh->outreq;
610f16e43f8SFrank Wang 	struct fsg_bulk_cb_wrap	*cbw = req->buf;
611f16e43f8SFrank Wang 	int rc;
612f16e43f8SFrank Wang 
613f16e43f8SFrank Wang 	dump_cbw(cbw);
614f16e43f8SFrank Wang 
615f16e43f8SFrank Wang 	if (rkusb_check_lun(common)) {
616f16e43f8SFrank Wang 		*reply = -EINVAL;
617f16e43f8SFrank Wang 		return RKUSB_RC_ERROR;
618f16e43f8SFrank Wang 	}
619f16e43f8SFrank Wang 
620f16e43f8SFrank Wang 	switch (common->cmnd[0]) {
621f16e43f8SFrank Wang 	case RKUSB_TEST_UNIT_READY:
622f16e43f8SFrank Wang 		*reply = rkusb_do_test_unit_ready(common, bh);
623f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
624f16e43f8SFrank Wang 		break;
625f16e43f8SFrank Wang 
626f16e43f8SFrank Wang 	case RKUSB_READ_FLASH_ID:
627f16e43f8SFrank Wang 		*reply = rkusb_do_read_flash_id(common, bh);
628f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
629f16e43f8SFrank Wang 		break;
630f16e43f8SFrank Wang 
631f16e43f8SFrank Wang 	case RKUSB_TEST_BAD_BLOCK:
632f16e43f8SFrank Wang 		*reply = rkusb_do_test_bad_block(common, bh);
633f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
634f16e43f8SFrank Wang 		break;
635f16e43f8SFrank Wang 
636e66d4537SJon Lin 	case RKUSB_ERASE_10_FORCE:
637e66d4537SJon Lin 		*reply = rkusb_do_erase_force(common, bh);
638e66d4537SJon Lin 		rc = RKUSB_RC_FINISHED;
639e66d4537SJon Lin 		break;
640e66d4537SJon Lin 
641f16e43f8SFrank Wang 	case RKUSB_LBA_READ_10:
6425fb597c2SKever Yang 		rkusb_fixup_cbwcb(common, bh);
643f16e43f8SFrank Wang 		common->cmnd[0] = SC_READ_10;
644f16e43f8SFrank Wang 		common->cmnd[1] = 0; /* Not support */
645f16e43f8SFrank Wang 		rc = RKUSB_RC_CONTINUE;
646f16e43f8SFrank Wang 		break;
647f16e43f8SFrank Wang 
648f16e43f8SFrank Wang 	case RKUSB_LBA_WRITE_10:
6495fb597c2SKever Yang 		rkusb_fixup_cbwcb(common, bh);
650f16e43f8SFrank Wang 		common->cmnd[0] = SC_WRITE_10;
651f16e43f8SFrank Wang 		common->cmnd[1] = 0; /* Not support */
652f16e43f8SFrank Wang 		rc = RKUSB_RC_CONTINUE;
653f16e43f8SFrank Wang 		break;
654f16e43f8SFrank Wang 
655f16e43f8SFrank Wang 	case RKUSB_READ_FLASH_INFO:
656f16e43f8SFrank Wang 		*reply = rkusb_do_read_flash_info(common, bh);
657f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
658f16e43f8SFrank Wang 		break;
659f16e43f8SFrank Wang 
660829f2b85SFrank Wang 	case RKUSB_GET_CHIP_VER:
661829f2b85SFrank Wang 		*reply = rkusb_do_get_chip_info(common, bh);
662829f2b85SFrank Wang 		rc = RKUSB_RC_FINISHED;
663829f2b85SFrank Wang 		break;
664829f2b85SFrank Wang 
665f16e43f8SFrank Wang 	case RKUSB_LBA_ERASE:
666f16e43f8SFrank Wang 		*reply = rkusb_do_lba_erase(common, bh);
667f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
668f16e43f8SFrank Wang 		break;
669f16e43f8SFrank Wang 
6700d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
6710d0c3248SFrank Wang 	case RKUSB_VS_WRITE:
6720d0c3248SFrank Wang 		*reply = rkusb_do_vs_write(common);
6730d0c3248SFrank Wang 		rc = RKUSB_RC_FINISHED;
6740d0c3248SFrank Wang 		break;
6750d0c3248SFrank Wang 
6760d0c3248SFrank Wang 	case RKUSB_VS_READ:
6770d0c3248SFrank Wang 		*reply = rkusb_do_vs_read(common);
6780d0c3248SFrank Wang 		rc = RKUSB_RC_FINISHED;
6790d0c3248SFrank Wang 		break;
6800d0c3248SFrank Wang #endif
6810d0c3248SFrank Wang 
682f16e43f8SFrank Wang 	case RKUSB_READ_CAPACITY:
683f16e43f8SFrank Wang 		*reply = rkusb_do_read_capacity(common, bh);
684f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
685f16e43f8SFrank Wang 		break;
686f16e43f8SFrank Wang 
687f16e43f8SFrank Wang 	case RKUSB_RESET:
688f16e43f8SFrank Wang 		*reply = rkusb_do_reset(common, bh);
689f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
690f16e43f8SFrank Wang 		break;
691f16e43f8SFrank Wang 
692f16e43f8SFrank Wang 	case RKUSB_READ_10:
693f16e43f8SFrank Wang 	case RKUSB_WRITE_10:
694e0023032SKever Yang 		printf("CMD Not support, pls use new version Tool\n");
695e0023032SKever Yang 	case RKUSB_SET_DEVICE_ID:
696f16e43f8SFrank Wang 	case RKUSB_ERASE_10:
697f16e43f8SFrank Wang 	case RKUSB_WRITE_SPARE:
698f16e43f8SFrank Wang 	case RKUSB_READ_SPARE:
699f16e43f8SFrank Wang 	case RKUSB_GET_VERSION:
700f16e43f8SFrank Wang 	case RKUSB_ERASE_SYS_DISK:
701f16e43f8SFrank Wang 	case RKUSB_SDRAM_READ_10:
702f16e43f8SFrank Wang 	case RKUSB_SDRAM_WRITE_10:
703f16e43f8SFrank Wang 	case RKUSB_SDRAM_EXECUTE:
704f16e43f8SFrank Wang 	case RKUSB_LOW_FORMAT:
705f16e43f8SFrank Wang 	case RKUSB_SET_RESET_FLAG:
706f16e43f8SFrank Wang 	case RKUSB_SPI_READ_10:
707f16e43f8SFrank Wang 	case RKUSB_SPI_WRITE_10:
708f16e43f8SFrank Wang 	case RKUSB_SESSION:
709f16e43f8SFrank Wang 		/* Fall through */
710f16e43f8SFrank Wang 	default:
711f16e43f8SFrank Wang 		rc = RKUSB_RC_UNKNOWN_CMND;
712f16e43f8SFrank Wang 		break;
713f16e43f8SFrank Wang 	}
714f16e43f8SFrank Wang 
715f16e43f8SFrank Wang 	return rc;
716f16e43f8SFrank Wang }
717f16e43f8SFrank Wang 
718f16e43f8SFrank Wang DECLARE_GADGET_BIND_CALLBACK(rkusb_ums_dnl, fsg_add);
719