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 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 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 */ 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 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 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 { 247f4f71536SSimon Glass const struct SCSI_cmd_block *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 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 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 375*a1e4adeeSSimon Glass plat->pathname = dev_read_string(dev, "sandbox,filepath"); 376f4f71536SSimon Glass 377f4f71536SSimon Glass return 0; 378f4f71536SSimon Glass } 379f4f71536SSimon Glass 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 393c4876320SSimon Glass return usb_emul_setup_device(dev, PACKET_SIZE_64, plat->flash_strings, 394f4f71536SSimon Glass flash_desc_list); 395f4f71536SSimon Glass } 396f4f71536SSimon Glass 397f4f71536SSimon Glass static int sandbox_flash_probe(struct udevice *dev) 398f4f71536SSimon Glass { 399f4f71536SSimon Glass struct sandbox_flash_plat *plat = dev_get_platdata(dev); 400f4f71536SSimon Glass struct sandbox_flash_priv *priv = dev_get_priv(dev); 401f4f71536SSimon Glass 402f4f71536SSimon Glass priv->fd = os_open(plat->pathname, OS_O_RDONLY); 403f4f71536SSimon Glass if (priv->fd != -1) 404f4f71536SSimon Glass return os_get_filesize(plat->pathname, &priv->file_size); 405f4f71536SSimon Glass 406f4f71536SSimon Glass return 0; 407f4f71536SSimon Glass } 408f4f71536SSimon Glass 409f4f71536SSimon Glass static const struct dm_usb_ops sandbox_usb_flash_ops = { 410f4f71536SSimon Glass .control = sandbox_flash_control, 411f4f71536SSimon Glass .bulk = sandbox_flash_bulk, 412f4f71536SSimon Glass }; 413f4f71536SSimon Glass 414f4f71536SSimon Glass static const struct udevice_id sandbox_usb_flash_ids[] = { 415f4f71536SSimon Glass { .compatible = "sandbox,usb-flash" }, 416f4f71536SSimon Glass { } 417f4f71536SSimon Glass }; 418f4f71536SSimon Glass 419f4f71536SSimon Glass U_BOOT_DRIVER(usb_sandbox_flash) = { 420f4f71536SSimon Glass .name = "usb_sandbox_flash", 421f4f71536SSimon Glass .id = UCLASS_USB_EMUL, 422f4f71536SSimon Glass .of_match = sandbox_usb_flash_ids, 423f4f71536SSimon Glass .bind = sandbox_flash_bind, 424f4f71536SSimon Glass .probe = sandbox_flash_probe, 425f4f71536SSimon Glass .ofdata_to_platdata = sandbox_flash_ofdata_to_platdata, 426f4f71536SSimon Glass .ops = &sandbox_usb_flash_ops, 427f4f71536SSimon Glass .priv_auto_alloc_size = sizeof(struct sandbox_flash_priv), 428f4f71536SSimon Glass .platdata_auto_alloc_size = sizeof(struct sandbox_flash_plat), 429f4f71536SSimon Glass }; 430