1f4f71536SSimon Glass /*
2f4f71536SSimon Glass * (C) Copyright 2015 Google, Inc
3f4f71536SSimon Glass * Written by Simon Glass <sjg@chromium.org>
4f4f71536SSimon Glass *
5f4f71536SSimon Glass * SPDX-License-Identifier: GPL-2.0+
6f4f71536SSimon Glass */
7f4f71536SSimon Glass
8f4f71536SSimon Glass #include <common.h>
9f4f71536SSimon Glass #include <dm.h>
10f4f71536SSimon Glass #include <os.h>
11f4f71536SSimon Glass #include <scsi.h>
12f4f71536SSimon Glass #include <usb.h>
13f4f71536SSimon Glass
14f4f71536SSimon Glass DECLARE_GLOBAL_DATA_PTR;
15f4f71536SSimon Glass
16f4f71536SSimon Glass /*
17f4f71536SSimon Glass * This driver emulates a flash stick using the UFI command specification and
18f4f71536SSimon Glass * the BBB (bulk/bulk/bulk) protocol. It supports only a single logical unit
19f4f71536SSimon Glass * number (LUN 0).
20f4f71536SSimon Glass */
21f4f71536SSimon Glass
22f4f71536SSimon Glass enum {
23f4f71536SSimon Glass SANDBOX_FLASH_EP_OUT = 1, /* endpoints */
24f4f71536SSimon Glass SANDBOX_FLASH_EP_IN = 2,
25f4f71536SSimon Glass SANDBOX_FLASH_BLOCK_LEN = 512,
26f4f71536SSimon Glass };
27f4f71536SSimon Glass
28f4f71536SSimon Glass enum cmd_phase {
29f4f71536SSimon Glass PHASE_START,
30f4f71536SSimon Glass PHASE_DATA,
31f4f71536SSimon Glass PHASE_STATUS,
32f4f71536SSimon Glass };
33f4f71536SSimon Glass
34c4876320SSimon Glass enum {
35c4876320SSimon Glass STRINGID_MANUFACTURER = 1,
36c4876320SSimon Glass STRINGID_PRODUCT,
37c4876320SSimon Glass STRINGID_SERIAL,
38c4876320SSimon Glass
39c4876320SSimon Glass STRINGID_COUNT,
40c4876320SSimon Glass };
41c4876320SSimon Glass
42f4f71536SSimon Glass /**
43f4f71536SSimon Glass * struct sandbox_flash_priv - private state for this driver
44f4f71536SSimon Glass *
45f4f71536SSimon Glass * @error: true if there is an error condition
46f4f71536SSimon Glass * @alloc_len: Allocation length from the last incoming command
47f4f71536SSimon Glass * @transfer_len: Transfer length from CBW header
48f4f71536SSimon Glass * @read_len: Number of blocks of data left in the current read command
49f4f71536SSimon Glass * @tag: Tag value from last command
50f4f71536SSimon Glass * @fd: File descriptor of backing file
51f4f71536SSimon Glass * @file_size: Size of file in bytes
52f4f71536SSimon Glass * @status_buff: Data buffer for outgoing status
53f4f71536SSimon Glass * @buff_used: Number of bytes ready to transfer back to host
54f4f71536SSimon Glass * @buff: Data buffer for outgoing data
55f4f71536SSimon Glass */
56f4f71536SSimon Glass struct sandbox_flash_priv {
57f4f71536SSimon Glass bool error;
58f4f71536SSimon Glass int alloc_len;
59f4f71536SSimon Glass int transfer_len;
60f4f71536SSimon Glass int read_len;
61f4f71536SSimon Glass enum cmd_phase phase;
62f4f71536SSimon Glass u32 tag;
63f4f71536SSimon Glass int fd;
64f4f71536SSimon Glass loff_t file_size;
65f4f71536SSimon Glass struct umass_bbb_csw status;
66f4f71536SSimon Glass int buff_used;
67f4f71536SSimon Glass u8 buff[512];
68f4f71536SSimon Glass };
69f4f71536SSimon Glass
70f4f71536SSimon Glass struct sandbox_flash_plat {
71f4f71536SSimon Glass const char *pathname;
72c4876320SSimon Glass struct usb_string flash_strings[STRINGID_COUNT];
73f4f71536SSimon Glass };
74f4f71536SSimon Glass
75f4f71536SSimon Glass struct scsi_inquiry_resp {
76f4f71536SSimon Glass u8 type;
77f4f71536SSimon Glass u8 flags;
78f4f71536SSimon Glass u8 version;
79f4f71536SSimon Glass u8 data_format;
80f4f71536SSimon Glass u8 additional_len;
81f4f71536SSimon Glass u8 spare[3];
82f4f71536SSimon Glass char vendor[8];
83f4f71536SSimon Glass char product[16];
84f4f71536SSimon Glass char revision[4];
85f4f71536SSimon Glass };
86f4f71536SSimon Glass
87f4f71536SSimon Glass struct scsi_read_capacity_resp {
88f4f71536SSimon Glass u32 last_block_addr;
89f4f71536SSimon Glass u32 block_len;
90f4f71536SSimon Glass };
91f4f71536SSimon Glass
92f4f71536SSimon Glass struct __packed scsi_read10_req {
93f4f71536SSimon Glass u8 cmd;
94f4f71536SSimon Glass u8 lun_flags;
95f4f71536SSimon Glass u32 lba;
96f4f71536SSimon Glass u8 spare;
97f4f71536SSimon Glass u16 transfer_len;
98f4f71536SSimon Glass u8 spare2[3];
99f4f71536SSimon Glass };
100f4f71536SSimon Glass
101f4f71536SSimon Glass static struct usb_device_descriptor flash_device_desc = {
102f4f71536SSimon Glass .bLength = sizeof(flash_device_desc),
103f4f71536SSimon Glass .bDescriptorType = USB_DT_DEVICE,
104f4f71536SSimon Glass
105f4f71536SSimon Glass .bcdUSB = __constant_cpu_to_le16(0x0200),
106f4f71536SSimon Glass
107f4f71536SSimon Glass .bDeviceClass = 0,
108f4f71536SSimon Glass .bDeviceSubClass = 0,
109f4f71536SSimon Glass .bDeviceProtocol = 0,
110f4f71536SSimon Glass
111f4f71536SSimon Glass .idVendor = __constant_cpu_to_le16(0x1234),
112f4f71536SSimon Glass .idProduct = __constant_cpu_to_le16(0x5678),
113f4f71536SSimon Glass .iManufacturer = STRINGID_MANUFACTURER,
114f4f71536SSimon Glass .iProduct = STRINGID_PRODUCT,
115f4f71536SSimon Glass .iSerialNumber = STRINGID_SERIAL,
116f4f71536SSimon Glass .bNumConfigurations = 1,
117f4f71536SSimon Glass };
118f4f71536SSimon Glass
119f4f71536SSimon Glass static struct usb_config_descriptor flash_config0 = {
120f4f71536SSimon Glass .bLength = sizeof(flash_config0),
121f4f71536SSimon Glass .bDescriptorType = USB_DT_CONFIG,
122f4f71536SSimon Glass
123f4f71536SSimon Glass /* wTotalLength is set up by usb-emul-uclass */
124f4f71536SSimon Glass .bNumInterfaces = 1,
125f4f71536SSimon Glass .bConfigurationValue = 0,
126f4f71536SSimon Glass .iConfiguration = 0,
127f4f71536SSimon Glass .bmAttributes = 1 << 7,
128f4f71536SSimon Glass .bMaxPower = 50,
129f4f71536SSimon Glass };
130f4f71536SSimon Glass
131f4f71536SSimon Glass static struct usb_interface_descriptor flash_interface0 = {
132f4f71536SSimon Glass .bLength = sizeof(flash_interface0),
133f4f71536SSimon Glass .bDescriptorType = USB_DT_INTERFACE,
134f4f71536SSimon Glass
135f4f71536SSimon Glass .bInterfaceNumber = 0,
136f4f71536SSimon Glass .bAlternateSetting = 0,
137f4f71536SSimon Glass .bNumEndpoints = 2,
138f4f71536SSimon Glass .bInterfaceClass = USB_CLASS_MASS_STORAGE,
139f4f71536SSimon Glass .bInterfaceSubClass = US_SC_UFI,
140f4f71536SSimon Glass .bInterfaceProtocol = US_PR_BULK,
141f4f71536SSimon Glass .iInterface = 0,
142f4f71536SSimon Glass };
143f4f71536SSimon Glass
144f4f71536SSimon Glass static struct usb_endpoint_descriptor flash_endpoint0_out = {
145f4f71536SSimon Glass .bLength = USB_DT_ENDPOINT_SIZE,
146f4f71536SSimon Glass .bDescriptorType = USB_DT_ENDPOINT,
147f4f71536SSimon Glass
148f4f71536SSimon Glass .bEndpointAddress = SANDBOX_FLASH_EP_OUT,
149f4f71536SSimon Glass .bmAttributes = USB_ENDPOINT_XFER_BULK,
150f4f71536SSimon Glass .wMaxPacketSize = __constant_cpu_to_le16(1024),
151f4f71536SSimon Glass .bInterval = 0,
152f4f71536SSimon Glass };
153f4f71536SSimon Glass
154f4f71536SSimon Glass static struct usb_endpoint_descriptor flash_endpoint1_in = {
155f4f71536SSimon Glass .bLength = USB_DT_ENDPOINT_SIZE,
156f4f71536SSimon Glass .bDescriptorType = USB_DT_ENDPOINT,
157f4f71536SSimon Glass
158f4f71536SSimon Glass .bEndpointAddress = SANDBOX_FLASH_EP_IN | USB_ENDPOINT_DIR_MASK,
159f4f71536SSimon Glass .bmAttributes = USB_ENDPOINT_XFER_BULK,
160f4f71536SSimon Glass .wMaxPacketSize = __constant_cpu_to_le16(1024),
161f4f71536SSimon Glass .bInterval = 0,
162f4f71536SSimon Glass };
163f4f71536SSimon Glass
164f4f71536SSimon Glass static void *flash_desc_list[] = {
165f4f71536SSimon Glass &flash_device_desc,
166f4f71536SSimon Glass &flash_config0,
167f4f71536SSimon Glass &flash_interface0,
168f4f71536SSimon Glass &flash_endpoint0_out,
169f4f71536SSimon Glass &flash_endpoint1_in,
170f4f71536SSimon Glass NULL,
171f4f71536SSimon Glass };
172f4f71536SSimon Glass
sandbox_flash_control(struct udevice * dev,struct usb_device * udev,unsigned long pipe,void * buff,int len,struct devrequest * setup)173f4f71536SSimon Glass static int sandbox_flash_control(struct udevice *dev, struct usb_device *udev,
174f4f71536SSimon Glass unsigned long pipe, void *buff, int len,
175f4f71536SSimon Glass struct devrequest *setup)
176f4f71536SSimon Glass {
177f4f71536SSimon Glass struct sandbox_flash_priv *priv = dev_get_priv(dev);
178f4f71536SSimon Glass
179f4f71536SSimon Glass if (pipe == usb_rcvctrlpipe(udev, 0)) {
180f4f71536SSimon Glass switch (setup->request) {
181f4f71536SSimon Glass case US_BBB_RESET:
182f4f71536SSimon Glass priv->error = false;
183f4f71536SSimon Glass return 0;
184f4f71536SSimon Glass case US_BBB_GET_MAX_LUN:
185f4f71536SSimon Glass *(char *)buff = '\0';
186f4f71536SSimon Glass return 1;
187f4f71536SSimon Glass default:
188f4f71536SSimon Glass debug("request=%x\n", setup->request);
189f4f71536SSimon Glass break;
190f4f71536SSimon Glass }
191f4f71536SSimon Glass }
192f4f71536SSimon Glass debug("pipe=%lx\n", pipe);
193f4f71536SSimon Glass
194f4f71536SSimon Glass return -EIO;
195f4f71536SSimon Glass }
196f4f71536SSimon Glass
setup_fail_response(struct sandbox_flash_priv * priv)197f4f71536SSimon Glass static void setup_fail_response(struct sandbox_flash_priv *priv)
198f4f71536SSimon Glass {
199f4f71536SSimon Glass struct umass_bbb_csw *csw = &priv->status;
200f4f71536SSimon Glass
201f4f71536SSimon Glass csw->dCSWSignature = CSWSIGNATURE;
202f4f71536SSimon Glass csw->dCSWTag = priv->tag;
203f4f71536SSimon Glass csw->dCSWDataResidue = 0;
204f4f71536SSimon Glass csw->bCSWStatus = CSWSTATUS_FAILED;
205f4f71536SSimon Glass priv->buff_used = 0;
206f4f71536SSimon Glass }
207f4f71536SSimon Glass
208f4f71536SSimon Glass /**
209f4f71536SSimon Glass * setup_response() - set up a response to send back to the host
210f4f71536SSimon Glass *
211f4f71536SSimon Glass * @priv: Sandbox flash private data
212f4f71536SSimon Glass * @resp: Response to send, or NULL if none
213f4f71536SSimon Glass * @size: Size of response
214f4f71536SSimon Glass */
setup_response(struct sandbox_flash_priv * priv,void * resp,int size)215f4f71536SSimon Glass static void setup_response(struct sandbox_flash_priv *priv, void *resp,
216f4f71536SSimon Glass int size)
217f4f71536SSimon Glass {
218f4f71536SSimon Glass struct umass_bbb_csw *csw = &priv->status;
219f4f71536SSimon Glass
220f4f71536SSimon Glass csw->dCSWSignature = CSWSIGNATURE;
221f4f71536SSimon Glass csw->dCSWTag = priv->tag;
222f4f71536SSimon Glass csw->dCSWDataResidue = 0;
223f4f71536SSimon Glass csw->bCSWStatus = CSWSTATUS_GOOD;
224f4f71536SSimon Glass
225f4f71536SSimon Glass assert(!resp || resp == priv->buff);
226f4f71536SSimon Glass priv->buff_used = size;
227f4f71536SSimon Glass }
228f4f71536SSimon Glass
handle_read(struct sandbox_flash_priv * priv,ulong lba,ulong transfer_len)229f4f71536SSimon Glass static void handle_read(struct sandbox_flash_priv *priv, ulong lba,
230f4f71536SSimon Glass ulong transfer_len)
231f4f71536SSimon Glass {
232f4f71536SSimon Glass debug("%s: lba=%lx, transfer_len=%lx\n", __func__, lba, transfer_len);
233f4f71536SSimon Glass if (priv->fd != -1) {
234f4f71536SSimon Glass os_lseek(priv->fd, lba * SANDBOX_FLASH_BLOCK_LEN, OS_SEEK_SET);
235f4f71536SSimon Glass priv->read_len = transfer_len;
236f4f71536SSimon Glass setup_response(priv, priv->buff,
237f4f71536SSimon Glass transfer_len * SANDBOX_FLASH_BLOCK_LEN);
238f4f71536SSimon Glass } else {
239f4f71536SSimon Glass setup_fail_response(priv);
240f4f71536SSimon Glass }
241f4f71536SSimon Glass }
242f4f71536SSimon Glass
handle_ufi_command(struct sandbox_flash_plat * plat,struct sandbox_flash_priv * priv,const void * buff,int len)243c4876320SSimon Glass static int handle_ufi_command(struct sandbox_flash_plat *plat,
244c4876320SSimon Glass struct sandbox_flash_priv *priv, const void *buff,
245f4f71536SSimon Glass int len)
246f4f71536SSimon Glass {
247aae5ec34SSimon Glass const struct scsi_cmd *req = buff;
248f4f71536SSimon Glass
249f4f71536SSimon Glass switch (*req->cmd) {
250f4f71536SSimon Glass case SCSI_INQUIRY: {
251f4f71536SSimon Glass struct scsi_inquiry_resp *resp = (void *)priv->buff;
252f4f71536SSimon Glass
253f4f71536SSimon Glass priv->alloc_len = req->cmd[4];
254f4f71536SSimon Glass memset(resp, '\0', sizeof(*resp));
255f4f71536SSimon Glass resp->data_format = 1;
256f4f71536SSimon Glass resp->additional_len = 0x1f;
257f4f71536SSimon Glass strncpy(resp->vendor,
258c4876320SSimon Glass plat->flash_strings[STRINGID_MANUFACTURER - 1].s,
259f4f71536SSimon Glass sizeof(resp->vendor));
260c4876320SSimon Glass strncpy(resp->product,
261c4876320SSimon Glass plat->flash_strings[STRINGID_PRODUCT - 1].s,
262f4f71536SSimon Glass sizeof(resp->product));
263f4f71536SSimon Glass strncpy(resp->revision, "1.0", sizeof(resp->revision));
264f4f71536SSimon Glass setup_response(priv, resp, sizeof(*resp));
265f4f71536SSimon Glass break;
266f4f71536SSimon Glass }
267f4f71536SSimon Glass case SCSI_TST_U_RDY:
268f4f71536SSimon Glass setup_response(priv, NULL, 0);
269f4f71536SSimon Glass break;
270f4f71536SSimon Glass case SCSI_RD_CAPAC: {
271f4f71536SSimon Glass struct scsi_read_capacity_resp *resp = (void *)priv->buff;
272f4f71536SSimon Glass uint blocks;
273f4f71536SSimon Glass
274f4f71536SSimon Glass if (priv->file_size)
275f4f71536SSimon Glass blocks = priv->file_size / SANDBOX_FLASH_BLOCK_LEN - 1;
276f4f71536SSimon Glass else
277f4f71536SSimon Glass blocks = 0;
278f4f71536SSimon Glass resp->last_block_addr = cpu_to_be32(blocks);
279f4f71536SSimon Glass resp->block_len = cpu_to_be32(SANDBOX_FLASH_BLOCK_LEN);
280f4f71536SSimon Glass setup_response(priv, resp, sizeof(*resp));
281f4f71536SSimon Glass break;
282f4f71536SSimon Glass }
283f4f71536SSimon Glass case SCSI_READ10: {
284f4f71536SSimon Glass struct scsi_read10_req *req = (void *)buff;
285f4f71536SSimon Glass
286f4f71536SSimon Glass handle_read(priv, be32_to_cpu(req->lba),
287f4f71536SSimon Glass be16_to_cpu(req->transfer_len));
288f4f71536SSimon Glass break;
289f4f71536SSimon Glass }
290f4f71536SSimon Glass default:
291f4f71536SSimon Glass debug("Command not supported: %x\n", req->cmd[0]);
292f4f71536SSimon Glass return -EPROTONOSUPPORT;
293f4f71536SSimon Glass }
294f4f71536SSimon Glass
295f4f71536SSimon Glass priv->phase = priv->transfer_len ? PHASE_DATA : PHASE_STATUS;
296f4f71536SSimon Glass return 0;
297f4f71536SSimon Glass }
298f4f71536SSimon Glass
sandbox_flash_bulk(struct udevice * dev,struct usb_device * udev,unsigned long pipe,void * buff,int len)299f4f71536SSimon Glass static int sandbox_flash_bulk(struct udevice *dev, struct usb_device *udev,
300f4f71536SSimon Glass unsigned long pipe, void *buff, int len)
301f4f71536SSimon Glass {
302c4876320SSimon Glass struct sandbox_flash_plat *plat = dev_get_platdata(dev);
303f4f71536SSimon Glass struct sandbox_flash_priv *priv = dev_get_priv(dev);
304f4f71536SSimon Glass int ep = usb_pipeendpoint(pipe);
305f4f71536SSimon Glass struct umass_bbb_cbw *cbw = buff;
306f4f71536SSimon Glass
307f4f71536SSimon Glass debug("%s: dev=%s, pipe=%lx, ep=%x, len=%x, phase=%d\n", __func__,
308f4f71536SSimon Glass dev->name, pipe, ep, len, priv->phase);
309f4f71536SSimon Glass switch (ep) {
310f4f71536SSimon Glass case SANDBOX_FLASH_EP_OUT:
311f4f71536SSimon Glass switch (priv->phase) {
312f4f71536SSimon Glass case PHASE_START:
313f4f71536SSimon Glass priv->alloc_len = 0;
314f4f71536SSimon Glass priv->read_len = 0;
315f4f71536SSimon Glass if (priv->error || len != UMASS_BBB_CBW_SIZE ||
316f4f71536SSimon Glass cbw->dCBWSignature != CBWSIGNATURE)
317f4f71536SSimon Glass goto err;
318f4f71536SSimon Glass if ((cbw->bCBWFlags & CBWFLAGS_SBZ) ||
319f4f71536SSimon Glass cbw->bCBWLUN != 0)
320f4f71536SSimon Glass goto err;
321f4f71536SSimon Glass if (cbw->bCDBLength < 1 || cbw->bCDBLength >= 0x10)
322f4f71536SSimon Glass goto err;
323f4f71536SSimon Glass priv->transfer_len = cbw->dCBWDataTransferLength;
324f4f71536SSimon Glass priv->tag = cbw->dCBWTag;
325c4876320SSimon Glass return handle_ufi_command(plat, priv, cbw->CBWCDB,
326f4f71536SSimon Glass cbw->bCDBLength);
327f4f71536SSimon Glass case PHASE_DATA:
328f4f71536SSimon Glass debug("data out\n");
329f4f71536SSimon Glass break;
330f4f71536SSimon Glass default:
331f4f71536SSimon Glass break;
332f4f71536SSimon Glass }
333f4f71536SSimon Glass case SANDBOX_FLASH_EP_IN:
334f4f71536SSimon Glass switch (priv->phase) {
335f4f71536SSimon Glass case PHASE_DATA:
336f4f71536SSimon Glass debug("data in, len=%x, alloc_len=%x, priv->read_len=%x\n",
337f4f71536SSimon Glass len, priv->alloc_len, priv->read_len);
338f4f71536SSimon Glass if (priv->read_len) {
339f4f71536SSimon Glass ulong bytes_read;
340f4f71536SSimon Glass
341f4f71536SSimon Glass bytes_read = os_read(priv->fd, buff, len);
342f4f71536SSimon Glass if (bytes_read != len)
343f4f71536SSimon Glass return -EIO;
344f4f71536SSimon Glass priv->read_len -= len / SANDBOX_FLASH_BLOCK_LEN;
345f4f71536SSimon Glass if (!priv->read_len)
346f4f71536SSimon Glass priv->phase = PHASE_STATUS;
347f4f71536SSimon Glass } else {
348f4f71536SSimon Glass if (priv->alloc_len && len > priv->alloc_len)
349f4f71536SSimon Glass len = priv->alloc_len;
350f4f71536SSimon Glass memcpy(buff, priv->buff, len);
351f4f71536SSimon Glass priv->phase = PHASE_STATUS;
352f4f71536SSimon Glass }
353f4f71536SSimon Glass return len;
354f4f71536SSimon Glass case PHASE_STATUS:
355f4f71536SSimon Glass debug("status in, len=%x\n", len);
356f4f71536SSimon Glass if (len > sizeof(priv->status))
357f4f71536SSimon Glass len = sizeof(priv->status);
358f4f71536SSimon Glass memcpy(buff, &priv->status, len);
359f4f71536SSimon Glass priv->phase = PHASE_START;
360f4f71536SSimon Glass return len;
361f4f71536SSimon Glass default:
362f4f71536SSimon Glass break;
363f4f71536SSimon Glass }
364f4f71536SSimon Glass }
365f4f71536SSimon Glass err:
366f4f71536SSimon Glass priv->error = true;
367f4f71536SSimon Glass debug("%s: Detected transfer error\n", __func__);
368f4f71536SSimon Glass return 0;
369f4f71536SSimon Glass }
370f4f71536SSimon Glass
sandbox_flash_ofdata_to_platdata(struct udevice * dev)371f4f71536SSimon Glass static int sandbox_flash_ofdata_to_platdata(struct udevice *dev)
372f4f71536SSimon Glass {
373f4f71536SSimon Glass struct sandbox_flash_plat *plat = dev_get_platdata(dev);
374f4f71536SSimon Glass
375a1e4adeeSSimon Glass plat->pathname = dev_read_string(dev, "sandbox,filepath");
376f4f71536SSimon Glass
377f4f71536SSimon Glass return 0;
378f4f71536SSimon Glass }
379f4f71536SSimon Glass
sandbox_flash_bind(struct udevice * dev)380f4f71536SSimon Glass static int sandbox_flash_bind(struct udevice *dev)
381f4f71536SSimon Glass {
382c4876320SSimon Glass struct sandbox_flash_plat *plat = dev_get_platdata(dev);
383c4876320SSimon Glass struct usb_string *fs;
384c4876320SSimon Glass
385c4876320SSimon Glass fs = plat->flash_strings;
386c4876320SSimon Glass fs[0].id = STRINGID_MANUFACTURER;
387c4876320SSimon Glass fs[0].s = "sandbox";
388c4876320SSimon Glass fs[1].id = STRINGID_PRODUCT;
389c4876320SSimon Glass fs[1].s = "flash";
390c4876320SSimon Glass fs[2].id = STRINGID_SERIAL;
391c4876320SSimon Glass fs[2].s = dev->name;
392c4876320SSimon Glass
393*879f76fcSBin Meng return usb_emul_setup_device(dev, plat->flash_strings, flash_desc_list);
394f4f71536SSimon Glass }
395f4f71536SSimon Glass
sandbox_flash_probe(struct udevice * dev)396f4f71536SSimon Glass static int sandbox_flash_probe(struct udevice *dev)
397f4f71536SSimon Glass {
398f4f71536SSimon Glass struct sandbox_flash_plat *plat = dev_get_platdata(dev);
399f4f71536SSimon Glass struct sandbox_flash_priv *priv = dev_get_priv(dev);
400f4f71536SSimon Glass
401f4f71536SSimon Glass priv->fd = os_open(plat->pathname, OS_O_RDONLY);
402f4f71536SSimon Glass if (priv->fd != -1)
403f4f71536SSimon Glass return os_get_filesize(plat->pathname, &priv->file_size);
404f4f71536SSimon Glass
405f4f71536SSimon Glass return 0;
406f4f71536SSimon Glass }
407f4f71536SSimon Glass
408f4f71536SSimon Glass static const struct dm_usb_ops sandbox_usb_flash_ops = {
409f4f71536SSimon Glass .control = sandbox_flash_control,
410f4f71536SSimon Glass .bulk = sandbox_flash_bulk,
411f4f71536SSimon Glass };
412f4f71536SSimon Glass
413f4f71536SSimon Glass static const struct udevice_id sandbox_usb_flash_ids[] = {
414f4f71536SSimon Glass { .compatible = "sandbox,usb-flash" },
415f4f71536SSimon Glass { }
416f4f71536SSimon Glass };
417f4f71536SSimon Glass
418f4f71536SSimon Glass U_BOOT_DRIVER(usb_sandbox_flash) = {
419f4f71536SSimon Glass .name = "usb_sandbox_flash",
420f4f71536SSimon Glass .id = UCLASS_USB_EMUL,
421f4f71536SSimon Glass .of_match = sandbox_usb_flash_ids,
422f4f71536SSimon Glass .bind = sandbox_flash_bind,
423f4f71536SSimon Glass .probe = sandbox_flash_probe,
424f4f71536SSimon Glass .ofdata_to_platdata = sandbox_flash_ofdata_to_platdata,
425f4f71536SSimon Glass .ops = &sandbox_usb_flash_ops,
426f4f71536SSimon Glass .priv_auto_alloc_size = sizeof(struct sandbox_flash_priv),
427f4f71536SSimon Glass .platdata_auto_alloc_size = sizeof(struct sandbox_flash_plat),
428f4f71536SSimon Glass };
429