dev-storage.c 18.7 KB
Newer Older
1
/*
P
pbrook 已提交
2 3 4 5 6
 * USB Mass Storage Device emulation
 *
 * Copyright (c) 2006 CodeSourcery.
 * Written by Paul Brook
 *
M
Matthew Fernandez 已提交
7
 * This code is licensed under the LGPL.
P
pbrook 已提交
8 9
 */

P
pbrook 已提交
10
#include "qemu-common.h"
11 12
#include "qemu-option.h"
#include "qemu-config.h"
G
Gerd Hoffmann 已提交
13 14 15
#include "hw/usb.h"
#include "hw/usb/desc.h"
#include "hw/scsi.h"
16
#include "console.h"
17
#include "monitor.h"
18
#include "sysemu.h"
B
Blue Swirl 已提交
19
#include "blockdev.h"
P
pbrook 已提交
20 21 22 23

//#define DEBUG_MSD

#ifdef DEBUG_MSD
24 25
#define DPRINTF(fmt, ...) \
do { printf("usb-msd: " fmt , ## __VA_ARGS__); } while (0)
P
pbrook 已提交
26
#else
27
#define DPRINTF(fmt, ...) do {} while(0)
P
pbrook 已提交
28 29 30 31 32 33 34 35
#endif

/* USB requests.  */
#define MassStorageReset  0xff
#define GetMaxLun         0xfe

enum USBMSDMode {
    USB_MSDM_CBW, /* Command Block.  */
B
Brad Hards 已提交
36
    USB_MSDM_DATAOUT, /* Transfer data to device.  */
P
pbrook 已提交
37 38 39 40
    USB_MSDM_DATAIN, /* Transfer data from device.  */
    USB_MSDM_CSW /* Command Status.  */
};

41 42 43 44 45 46 47
struct usb_msd_csw {
    uint32_t sig;
    uint32_t tag;
    uint32_t residue;
    uint8_t status;
};

P
pbrook 已提交
48 49 50
typedef struct {
    USBDevice dev;
    enum USBMSDMode mode;
51
    uint32_t scsi_off;
P
pbrook 已提交
52
    uint32_t scsi_len;
P
pbrook 已提交
53
    uint32_t data_len;
54
    struct usb_msd_csw csw;
55
    SCSIRequest *req;
56
    SCSIBus bus;
57
    BlockConf conf;
58
    char *serial;
P
pbrook 已提交
59
    SCSIDevice *scsi_dev;
60
    uint32_t removable;
P
pbrook 已提交
61 62
    /* For async completion.  */
    USBPacket *packet;
P
pbrook 已提交
63 64
} MSDState;

P
pbrook 已提交
65 66 67 68 69 70 71 72 73 74
struct usb_msd_cbw {
    uint32_t sig;
    uint32_t tag;
    uint32_t data_len;
    uint8_t flags;
    uint8_t lun;
    uint8_t cmd_len;
    uint8_t cmd[16];
};

75 76 77 78
enum {
    STR_MANUFACTURER = 1,
    STR_PRODUCT,
    STR_SERIALNUMBER,
G
Gerd Hoffmann 已提交
79 80
    STR_CONFIG_FULL,
    STR_CONFIG_HIGH,
P
pbrook 已提交
81 82
};

83
static const USBDescStrings desc_strings = {
84
    [STR_MANUFACTURER] = "QEMU",
85 86
    [STR_PRODUCT]      = "QEMU USB HARDDRIVE",
    [STR_SERIALNUMBER] = "1",
G
Gerd Hoffmann 已提交
87 88
    [STR_CONFIG_FULL]  = "Full speed config (usb 1.1)",
    [STR_CONFIG_HIGH]  = "High speed config (usb 2.0)",
89 90
};

G
Gerd Hoffmann 已提交
91
static const USBDescIface desc_iface_full = {
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
    .bInterfaceNumber              = 0,
    .bNumEndpoints                 = 2,
    .bInterfaceClass               = USB_CLASS_MASS_STORAGE,
    .bInterfaceSubClass            = 0x06, /* SCSI */
    .bInterfaceProtocol            = 0x50, /* Bulk */
    .eps = (USBDescEndpoint[]) {
        {
            .bEndpointAddress      = USB_DIR_IN | 0x01,
            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
            .wMaxPacketSize        = 64,
        },{
            .bEndpointAddress      = USB_DIR_OUT | 0x02,
            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
            .wMaxPacketSize        = 64,
        },
    }
};

G
Gerd Hoffmann 已提交
110 111
static const USBDescDevice desc_device_full = {
    .bcdUSB                        = 0x0200,
112 113 114 115 116 117
    .bMaxPacketSize0               = 8,
    .bNumConfigurations            = 1,
    .confs = (USBDescConfig[]) {
        {
            .bNumInterfaces        = 1,
            .bConfigurationValue   = 1,
G
Gerd Hoffmann 已提交
118
            .iConfiguration        = STR_CONFIG_FULL,
119
            .bmAttributes          = 0xc0,
120
            .nif = 1,
G
Gerd Hoffmann 已提交
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
            .ifs = &desc_iface_full,
        },
    },
};

static const USBDescIface desc_iface_high = {
    .bInterfaceNumber              = 0,
    .bNumEndpoints                 = 2,
    .bInterfaceClass               = USB_CLASS_MASS_STORAGE,
    .bInterfaceSubClass            = 0x06, /* SCSI */
    .bInterfaceProtocol            = 0x50, /* Bulk */
    .eps = (USBDescEndpoint[]) {
        {
            .bEndpointAddress      = USB_DIR_IN | 0x01,
            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
            .wMaxPacketSize        = 512,
        },{
            .bEndpointAddress      = USB_DIR_OUT | 0x02,
            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
            .wMaxPacketSize        = 512,
        },
    }
};

static const USBDescDevice desc_device_high = {
    .bcdUSB                        = 0x0200,
    .bMaxPacketSize0               = 64,
    .bNumConfigurations            = 1,
    .confs = (USBDescConfig[]) {
        {
            .bNumInterfaces        = 1,
            .bConfigurationValue   = 1,
            .iConfiguration        = STR_CONFIG_HIGH,
            .bmAttributes          = 0xc0,
155
            .nif = 1,
G
Gerd Hoffmann 已提交
156
            .ifs = &desc_iface_high,
157 158 159 160 161 162
        },
    },
};

static const USBDesc desc = {
    .id = {
163 164
        .idVendor          = 0x46f4, /* CRC16() of "QEMU" */
        .idProduct         = 0x0001,
165 166 167 168 169
        .bcdDevice         = 0,
        .iManufacturer     = STR_MANUFACTURER,
        .iProduct          = STR_PRODUCT,
        .iSerialNumber     = STR_SERIALNUMBER,
    },
G
Gerd Hoffmann 已提交
170 171
    .full = &desc_device_full,
    .high = &desc_device_high,
172
    .str  = desc_strings,
P
pbrook 已提交
173 174
};

G
Gerd Hoffmann 已提交
175
static void usb_msd_copy_data(MSDState *s, USBPacket *p)
P
pbrook 已提交
176 177
{
    uint32_t len;
G
Gerd Hoffmann 已提交
178
    len = p->iov.size - p->result;
P
pbrook 已提交
179 180
    if (len > s->scsi_len)
        len = s->scsi_len;
181
    usb_packet_copy(p, scsi_req_get_buf(s->req) + s->scsi_off, len);
P
pbrook 已提交
182
    s->scsi_len -= len;
183
    s->scsi_off += len;
P
pbrook 已提交
184
    s->data_len -= len;
185
    if (s->scsi_len == 0 || s->data_len == 0) {
186
        scsi_req_continue(s->req);
P
pbrook 已提交
187 188 189
    }
}

190
static void usb_msd_send_status(MSDState *s, USBPacket *p)
P
pbrook 已提交
191
{
192
    int len;
P
pbrook 已提交
193

194
    DPRINTF("Command status %d tag 0x%x, len %zd\n",
195
            s->csw.status, le32_to_cpu(s->csw.tag), p->iov.size);
196

197
    assert(s->csw.sig == cpu_to_le32(0x53425355));
198 199 200
    len = MIN(sizeof(s->csw), p->iov.size);
    usb_packet_copy(p, &s->csw, len);
    memset(&s->csw, 0, sizeof(s->csw));
P
pbrook 已提交
201 202
}

203 204 205 206 207 208 209 210 211 212 213 214
static void usb_msd_packet_complete(MSDState *s)
{
    USBPacket *p = s->packet;

    /* Set s->packet to NULL before calling usb_packet_complete
       because another request may be issued before
       usb_packet_complete returns.  */
    DPRINTF("Packet complete %p\n", p);
    s->packet = NULL;
    usb_packet_complete(&s->dev, p);
}

215
static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
P
pbrook 已提交
216
{
217
    MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
P
pbrook 已提交
218
    USBPacket *p = s->packet;
P
pbrook 已提交
219

220
    assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV));
221
    s->scsi_len = len;
222
    s->scsi_off = 0;
P
pbrook 已提交
223
    if (p) {
G
Gerd Hoffmann 已提交
224 225 226
        usb_msd_copy_data(s, p);
        p = s->packet;
        if (p && p->result == p->iov.size) {
227
            usb_msd_packet_complete(s);
P
pbrook 已提交
228
        }
P
pbrook 已提交
229
    }
P
pbrook 已提交
230 231
}

232
static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, size_t resid)
233 234 235 236
{
    MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
    USBPacket *p = s->packet;

237
    DPRINTF("Command complete %d tag 0x%x\n", status, req->tag);
238 239

    s->csw.sig = cpu_to_le32(0x53425355);
240
    s->csw.tag = cpu_to_le32(req->tag);
241
    s->csw.residue = cpu_to_le32(s->data_len);
242
    s->csw.status = status != 0;
243

244 245 246 247 248 249 250 251
    if (s->packet) {
        if (s->data_len == 0 && s->mode == USB_MSDM_DATAOUT) {
            /* A deferred packet with no write data remaining must be
               the status read packet.  */
            usb_msd_send_status(s, p);
            s->mode = USB_MSDM_CBW;
        } else {
            if (s->data_len) {
G
Gerd Hoffmann 已提交
252 253 254
                int len = (p->iov.size - p->result);
                usb_packet_skip(p, len);
                s->data_len -= len;
255 256 257 258 259
            }
            if (s->data_len == 0) {
                s->mode = USB_MSDM_CSW;
            }
        }
260
        usb_msd_packet_complete(s);
261 262 263 264 265 266 267
    } else if (s->data_len == 0) {
        s->mode = USB_MSDM_CSW;
    }
    scsi_req_unref(req);
    s->req = NULL;
}

P
Paolo Bonzini 已提交
268 269 270 271 272 273 274 275 276 277 278
static void usb_msd_request_cancelled(SCSIRequest *req)
{
    MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);

    if (req == s->req) {
        scsi_req_unref(s->req);
        s->req = NULL;
        s->scsi_len = 0;
    }
}

B
bellard 已提交
279
static void usb_msd_handle_reset(USBDevice *dev)
P
pbrook 已提交
280 281 282 283
{
    MSDState *s = (MSDState *)dev;

    DPRINTF("Reset\n");
G
Gerd Hoffmann 已提交
284 285 286 287 288 289
    if (s->req) {
        scsi_req_cancel(s->req);
    }
    assert(s->req == NULL);

    if (s->packet) {
290 291
        s->packet->result = USB_RET_STALL;
        usb_msd_packet_complete(s);
G
Gerd Hoffmann 已提交
292 293
    }

P
pbrook 已提交
294 295 296
    s->mode = USB_MSDM_CBW;
}

297 298
static int usb_msd_handle_control(USBDevice *dev, USBPacket *p,
               int request, int value, int index, int length, uint8_t *data)
P
pbrook 已提交
299 300
{
    MSDState *s = (MSDState *)dev;
301
    int ret;
P
pbrook 已提交
302

303
    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
304 305 306 307 308
    if (ret >= 0) {
        return ret;
    }

    ret = 0;
P
pbrook 已提交
309 310
    switch (request) {
    case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
311 312
        ret = 0;
        break;
P
pbrook 已提交
313
        /* Class specific requests.  */
314
    case ClassInterfaceOutRequest | MassStorageReset:
P
pbrook 已提交
315 316 317 318
        /* Reset state ready for the next CBW.  */
        s->mode = USB_MSDM_CBW;
        ret = 0;
        break;
319
    case ClassInterfaceRequest | GetMaxLun:
P
pbrook 已提交
320 321 322 323 324 325 326 327 328 329
        data[0] = 0;
        ret = 1;
        break;
    default:
        ret = USB_RET_STALL;
        break;
    }
    return ret;
}

330
static void usb_msd_cancel_io(USBDevice *dev, USBPacket *p)
P
pbrook 已提交
331
{
332
    MSDState *s = DO_UPCAST(MSDState, dev, dev);
333

334 335 336
    assert(s->packet == p);
    s->packet = NULL;

337 338 339
    if (s->req) {
        scsi_req_cancel(s->req);
    }
P
pbrook 已提交
340 341 342
}

static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
P
pbrook 已提交
343 344
{
    MSDState *s = (MSDState *)dev;
345
    uint32_t tag;
P
pbrook 已提交
346 347
    int ret = 0;
    struct usb_msd_cbw cbw;
348
    uint8_t devep = p->ep->nr;
P
pbrook 已提交
349

P
pbrook 已提交
350
    switch (p->pid) {
P
pbrook 已提交
351 352 353 354 355 356
    case USB_TOKEN_OUT:
        if (devep != 2)
            goto fail;

        switch (s->mode) {
        case USB_MSDM_CBW:
G
Gerd Hoffmann 已提交
357
            if (p->iov.size != 31) {
P
pbrook 已提交
358 359 360
                fprintf(stderr, "usb-msd: Bad CBW size");
                goto fail;
            }
G
Gerd Hoffmann 已提交
361
            usb_packet_copy(p, &cbw, 31);
P
pbrook 已提交
362 363 364 365 366 367 368 369 370 371
            if (le32_to_cpu(cbw.sig) != 0x43425355) {
                fprintf(stderr, "usb-msd: Bad signature %08x\n",
                        le32_to_cpu(cbw.sig));
                goto fail;
            }
            DPRINTF("Command on LUN %d\n", cbw.lun);
            if (cbw.lun != 0) {
                fprintf(stderr, "usb-msd: Bad LUN %d\n", cbw.lun);
                goto fail;
            }
372
            tag = le32_to_cpu(cbw.tag);
P
pbrook 已提交
373 374 375 376 377 378 379 380 381
            s->data_len = le32_to_cpu(cbw.data_len);
            if (s->data_len == 0) {
                s->mode = USB_MSDM_CSW;
            } else if (cbw.flags & 0x80) {
                s->mode = USB_MSDM_DATAIN;
            } else {
                s->mode = USB_MSDM_DATAOUT;
            }
            DPRINTF("Command tag 0x%x flags %08x len %d data %d\n",
382
                    tag, cbw.flags, cbw.cmd_len, s->data_len);
383
            assert(le32_to_cpu(s->csw.residue) == 0);
G
Gerd Hoffmann 已提交
384
            s->scsi_len = 0;
385
            s->req = scsi_req_new(s->scsi_dev, tag, 0, cbw.cmd, NULL);
386 387 388
#ifdef DEBUG_MSD
            scsi_req_print(s->req);
#endif
389
            scsi_req_enqueue(s->req);
390
            if (s->req && s->req->cmd.xfer != SCSI_XFER_NONE) {
391
                scsi_req_continue(s->req);
P
pbrook 已提交
392
            }
G
Gerd Hoffmann 已提交
393
            ret = p->result;
P
pbrook 已提交
394 395 396
            break;

        case USB_MSDM_DATAOUT:
G
Gerd Hoffmann 已提交
397 398
            DPRINTF("Data out %zd/%d\n", p->iov.size, s->data_len);
            if (p->iov.size > s->data_len) {
P
pbrook 已提交
399
                goto fail;
G
Gerd Hoffmann 已提交
400
            }
P
pbrook 已提交
401

P
pbrook 已提交
402
            if (s->scsi_len) {
G
Gerd Hoffmann 已提交
403
                usb_msd_copy_data(s, p);
P
pbrook 已提交
404
            }
405
            if (le32_to_cpu(s->csw.residue)) {
G
Gerd Hoffmann 已提交
406 407 408 409 410 411 412 413
                int len = p->iov.size - p->result;
                if (len) {
                    usb_packet_skip(p, len);
                    s->data_len -= len;
                    if (s->data_len == 0) {
                        s->mode = USB_MSDM_CSW;
                    }
                }
P
pbrook 已提交
414
            }
G
Gerd Hoffmann 已提交
415
            if (p->result < p->iov.size) {
416
                DPRINTF("Deferring packet %p [wait data-out]\n", p);
P
pbrook 已提交
417 418
                s->packet = p;
                ret = USB_RET_ASYNC;
P
pbrook 已提交
419
            } else {
G
Gerd Hoffmann 已提交
420
                ret = p->result;
P
pbrook 已提交
421
            }
P
pbrook 已提交
422 423 424
            break;

        default:
G
Gerd Hoffmann 已提交
425
            DPRINTF("Unexpected write (len %zd)\n", p->iov.size);
P
pbrook 已提交
426 427 428 429 430 431 432 433 434
            goto fail;
        }
        break;

    case USB_TOKEN_IN:
        if (devep != 1)
            goto fail;

        switch (s->mode) {
P
pbrook 已提交
435
        case USB_MSDM_DATAOUT:
G
Gerd Hoffmann 已提交
436
            if (s->data_len != 0 || p->iov.size < 13) {
P
pbrook 已提交
437
                goto fail;
G
Gerd Hoffmann 已提交
438
            }
P
pbrook 已提交
439 440 441 442 443
            /* Waiting for SCSI write to complete.  */
            s->packet = p;
            ret = USB_RET_ASYNC;
            break;

P
pbrook 已提交
444
        case USB_MSDM_CSW:
G
Gerd Hoffmann 已提交
445
            if (p->iov.size < 13) {
P
pbrook 已提交
446
                goto fail;
G
Gerd Hoffmann 已提交
447
            }
P
pbrook 已提交
448

449 450
            if (s->req) {
                /* still in flight */
451
                DPRINTF("Deferring packet %p [wait status]\n", p);
452 453 454 455 456 457 458
                s->packet = p;
                ret = USB_RET_ASYNC;
            } else {
                usb_msd_send_status(s, p);
                s->mode = USB_MSDM_CBW;
                ret = 13;
            }
P
pbrook 已提交
459 460 461
            break;

        case USB_MSDM_DATAIN:
G
Gerd Hoffmann 已提交
462 463
            DPRINTF("Data in %zd/%d, scsi_len %d\n",
                    p->iov.size, s->data_len, s->scsi_len);
P
pbrook 已提交
464
            if (s->scsi_len) {
G
Gerd Hoffmann 已提交
465
                usb_msd_copy_data(s, p);
P
pbrook 已提交
466
            }
467
            if (le32_to_cpu(s->csw.residue)) {
G
Gerd Hoffmann 已提交
468 469 470 471 472 473 474 475
                int len = p->iov.size - p->result;
                if (len) {
                    usb_packet_skip(p, len);
                    s->data_len -= len;
                    if (s->data_len == 0) {
                        s->mode = USB_MSDM_CSW;
                    }
                }
P
pbrook 已提交
476
            }
G
Gerd Hoffmann 已提交
477
            if (p->result < p->iov.size) {
478
                DPRINTF("Deferring packet %p [wait data-in]\n", p);
P
pbrook 已提交
479 480
                s->packet = p;
                ret = USB_RET_ASYNC;
P
pbrook 已提交
481
            } else {
G
Gerd Hoffmann 已提交
482
                ret = p->result;
P
pbrook 已提交
483
            }
P
pbrook 已提交
484 485 486
            break;

        default:
G
Gerd Hoffmann 已提交
487
            DPRINTF("Unexpected read (len %zd)\n", p->iov.size);
P
pbrook 已提交
488 489 490 491 492 493 494 495 496 497 498 499 500 501
            goto fail;
        }
        break;

    default:
        DPRINTF("Bad token\n");
    fail:
        ret = USB_RET_STALL;
        break;
    }

    return ret;
}

502 503 504 505 506
static void usb_msd_password_cb(void *opaque, int err)
{
    MSDState *s = opaque;

    if (!err)
507 508 509
        err = usb_device_attach(&s->dev);

    if (err)
510
        qdev_unplug(&s->dev.qdev, NULL);
511 512
}

G
Gerd Hoffmann 已提交
513 514 515 516 517 518 519 520 521 522 523
static void *usb_msd_load_request(QEMUFile *f, SCSIRequest *req)
{
    MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);

    /* nothing to load, just store req in our state struct */
    assert(s->req == NULL);
    scsi_req_ref(req);
    s->req = req;
    return NULL;
}

524 525
static const struct SCSIBusInfo usb_msd_scsi_info = {
    .tcq = false,
P
Paolo Bonzini 已提交
526 527
    .max_target = 0,
    .max_lun = 0,
528

529
    .transfer_data = usb_msd_transfer_data,
P
Paolo Bonzini 已提交
530
    .complete = usb_msd_command_complete,
G
Gerd Hoffmann 已提交
531 532
    .cancel = usb_msd_request_cancelled,
    .load_request = usb_msd_load_request,
P
Paolo Bonzini 已提交
533 534
};

535 536 537
static int usb_msd_initfn(USBDevice *dev)
{
    MSDState *s = DO_UPCAST(MSDState, dev, dev);
538
    BlockDriverState *bs = s->conf.bs;
539

540
    if (!bs) {
541
        error_report("drive property not set");
542 543 544
        return -1;
    }

545 546
    blkconf_serial(&s->conf, &s->serial);

547 548 549
    /*
     * Hack alert: this pretends to be a block device, but it's really
     * a SCSI bus that can serve only a single device, which it
550 551 552
     * creates automatically.  But first it needs to detach from its
     * blockdev, or else scsi_bus_legacy_add_drive() dies when it
     * attaches again.
553 554 555
     *
     * The hack is probably a bad idea.
     */
556
    bdrv_detach_dev(bs, &s->dev.qdev);
557
    s->conf.bs = NULL;
558

559 560
    if (s->serial) {
        usb_desc_set_string(dev, STR_SERIALNUMBER, s->serial);
G
Gerd Hoffmann 已提交
561 562
    } else {
        usb_desc_create_serial(dev);
563 564
    }

565
    usb_desc_init(dev);
566
    scsi_bus_new(&s->bus, &s->dev.qdev, &usb_msd_scsi_info);
567 568
    s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable,
                                            s->conf.bootindex);
569 570 571
    if (!s->scsi_dev) {
        return -1;
    }
G
Gerd Hoffmann 已提交
572
    s->bus.qbus.allow_hotplug = 0;
573
    usb_msd_handle_reset(dev);
574

575
    if (bdrv_key_required(bs)) {
576
        if (cur_mon) {
577
            monitor_read_bdrv_key_start(cur_mon, bs, usb_msd_password_cb, s);
578 579 580 581 582 583
            s->dev.auto_attach = 0;
        } else {
            autostart = 0;
        }
    }

584 585 586
    return 0;
}

587
static USBDevice *usb_msd_init(USBBus *bus, const char *filename)
P
pbrook 已提交
588
{
589 590 591 592
    static int nr=0;
    char id[8];
    QemuOpts *opts;
    DriveInfo *dinfo;
593
    USBDevice *dev;
594 595 596
    const char *p1;
    char fmt[32];

597 598
    /* parse -usbdevice disk: syntax into drive opts */
    snprintf(id, sizeof(id), "usb%d", nr++);
599
    opts = qemu_opts_create(qemu_find_opts("drive"), id, 0, NULL);
600

601 602 603 604 605 606 607
    p1 = strchr(filename, ':');
    if (p1++) {
        const char *p2;

        if (strstart(filename, "format=", &p2)) {
            int len = MIN(p1 - p2, sizeof(fmt));
            pstrcpy(fmt, len, p2);
608
            qemu_opt_set(opts, "format", fmt);
609 610 611 612 613 614 615 616 617 618
        } else if (*filename != ':') {
            printf("unrecognized USB mass-storage option %s\n", filename);
            return NULL;
        }
        filename = p1;
    }
    if (!*filename) {
        printf("block device specification needed\n");
        return NULL;
    }
619 620
    qemu_opt_set(opts, "file", filename);
    qemu_opt_set(opts, "if", "none");
P
pbrook 已提交
621

622
    /* create host drive */
623
    dinfo = drive_init(opts, 0);
624 625
    if (!dinfo) {
        qemu_opts_del(opts);
626
        return NULL;
627
    }
P
pbrook 已提交
628

629
    /* create guest device */
630
    dev = usb_create(bus, "usb-storage");
P
Paul Brook 已提交
631 632 633
    if (!dev) {
        return NULL;
    }
634 635 636 637
    if (qdev_prop_set_drive(&dev->qdev, "drive", dinfo->bdrv) < 0) {
        qdev_free(&dev->qdev);
        return NULL;
    }
638 639
    if (qdev_init(&dev->qdev) < 0)
        return NULL;
640

641
    return dev;
P
pbrook 已提交
642
}
643

644 645 646 647 648 649
static const VMStateDescription vmstate_usb_msd = {
    .name = "usb-storage",
    .version_id = 1,
    .minimum_version_id = 1,
    .fields = (VMStateField []) {
        VMSTATE_USB_DEVICE(dev, MSDState),
G
Gerd Hoffmann 已提交
650 651 652 653 654 655 656 657
        VMSTATE_UINT32(mode, MSDState),
        VMSTATE_UINT32(scsi_len, MSDState),
        VMSTATE_UINT32(scsi_off, MSDState),
        VMSTATE_UINT32(data_len, MSDState),
        VMSTATE_UINT32(csw.sig, MSDState),
        VMSTATE_UINT32(csw.tag, MSDState),
        VMSTATE_UINT32(csw.residue, MSDState),
        VMSTATE_UINT8(csw.status, MSDState),
658 659 660 661
        VMSTATE_END_OF_LIST()
    }
};

662 663 664 665 666 667 668
static Property msd_properties[] = {
    DEFINE_BLOCK_PROPERTIES(MSDState, conf),
    DEFINE_PROP_STRING("serial", MSDState, serial),
    DEFINE_PROP_BIT("removable", MSDState, removable, 0, false),
    DEFINE_PROP_END_OF_LIST(),
};

669 670
static void usb_msd_class_initfn(ObjectClass *klass, void *data)
{
671
    DeviceClass *dc = DEVICE_CLASS(klass);
672 673 674 675 676 677 678 679 680 681
    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);

    uc->init           = usb_msd_initfn;
    uc->product_desc   = "QEMU USB MSD";
    uc->usb_desc       = &desc;
    uc->cancel_packet  = usb_msd_cancel_io;
    uc->handle_attach  = usb_desc_attach;
    uc->handle_reset   = usb_msd_handle_reset;
    uc->handle_control = usb_msd_handle_control;
    uc->handle_data    = usb_msd_handle_data;
682 683 684
    dc->fw_name = "storage";
    dc->vmsd = &vmstate_usb_msd;
    dc->props = msd_properties;
685 686
}

687 688 689 690 691
static TypeInfo msd_info = {
    .name          = "usb-storage",
    .parent        = TYPE_USB_DEVICE,
    .instance_size = sizeof(MSDState),
    .class_init    = usb_msd_class_initfn,
692 693
};

A
Andreas Färber 已提交
694
static void usb_msd_register_types(void)
695
{
696
    type_register_static(&msd_info);
697
    usb_legacy_register("usb-storage", "disk", usb_msd_init);
698
}
A
Andreas Färber 已提交
699 700

type_init(usb_msd_register_types)