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