dev-storage.c 18.1 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;
P
pbrook 已提交
51 52
    uint32_t scsi_len;
    uint8_t *scsi_buf;
P
pbrook 已提交
53
    uint32_t data_len;
P
pbrook 已提交
54
    uint32_t residue;
55
    struct usb_msd_csw csw;
56
    SCSIRequest *req;
57
    SCSIBus bus;
58
    BlockConf conf;
59
    char *serial;
P
pbrook 已提交
60
    SCSIDevice *scsi_dev;
61
    uint32_t removable;
P
pbrook 已提交
62 63
    /* For async completion.  */
    USBPacket *packet;
P
pbrook 已提交
64 65
} MSDState;

P
pbrook 已提交
66 67 68 69 70 71 72 73 74 75
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];
};

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

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

G
Gerd Hoffmann 已提交
92
static const USBDescIface desc_iface_full = {
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
    .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 已提交
111 112
static const USBDescDevice desc_device_full = {
    .bcdUSB                        = 0x0200,
113 114 115 116 117 118
    .bMaxPacketSize0               = 8,
    .bNumConfigurations            = 1,
    .confs = (USBDescConfig[]) {
        {
            .bNumInterfaces        = 1,
            .bConfigurationValue   = 1,
G
Gerd Hoffmann 已提交
119
            .iConfiguration        = STR_CONFIG_FULL,
120
            .bmAttributes          = 0xc0,
121
            .nif = 1,
G
Gerd Hoffmann 已提交
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 155
            .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,
156
            .nif = 1,
G
Gerd Hoffmann 已提交
157
            .ifs = &desc_iface_high,
158 159 160 161 162 163
        },
    },
};

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

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

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

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

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

204
static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
P
pbrook 已提交
205
{
206
    MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
P
pbrook 已提交
207
    USBPacket *p = s->packet;
P
pbrook 已提交
208

209
    assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV));
210
    s->scsi_len = len;
P
Paolo Bonzini 已提交
211
    s->scsi_buf = scsi_req_get_buf(req);
P
pbrook 已提交
212
    if (p) {
G
Gerd Hoffmann 已提交
213 214 215
        usb_msd_copy_data(s, p);
        p = s->packet;
        if (p && p->result == p->iov.size) {
P
pbrook 已提交
216
            /* Set s->packet to NULL before calling usb_packet_complete
B
Brad Hards 已提交
217
               because another request may be issued before
P
pbrook 已提交
218 219 220
               usb_packet_complete returns.  */
            DPRINTF("Packet complete %p\n", p);
            s->packet = NULL;
221
            usb_packet_complete(&s->dev, p);
P
pbrook 已提交
222
        }
P
pbrook 已提交
223
    }
P
pbrook 已提交
224 225
}

226
static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, size_t resid)
227 228 229 230
{
    MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
    USBPacket *p = s->packet;

231
    DPRINTF("Command complete %d tag 0x%x\n", status, req->tag);
232
    s->residue = s->data_len;
233 234

    s->csw.sig = cpu_to_le32(0x53425355);
235
    s->csw.tag = cpu_to_le32(req->tag);
236
    s->csw.residue = cpu_to_le32(s->residue);
237
    s->csw.status = status != 0;
238

239 240 241 242 243 244 245 246
    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 已提交
247 248 249
                int len = (p->iov.size - p->result);
                usb_packet_skip(p, len);
                s->data_len -= len;
250 251 252 253 254 255 256 257 258 259 260 261 262 263
            }
            if (s->data_len == 0) {
                s->mode = USB_MSDM_CSW;
            }
        }
        s->packet = NULL;
        usb_packet_complete(&s->dev, p);
    } else if (s->data_len == 0) {
        s->mode = USB_MSDM_CSW;
    }
    scsi_req_unref(req);
    s->req = NULL;
}

P
Paolo Bonzini 已提交
264 265 266 267 268 269 270 271 272 273 274 275
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->packet = NULL;
        s->scsi_len = 0;
    }
}

B
bellard 已提交
276
static void usb_msd_handle_reset(USBDevice *dev)
P
pbrook 已提交
277 278 279 280
{
    MSDState *s = (MSDState *)dev;

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

    if (s->packet) {
        USBPacket *p = s->packet;
        s->packet = NULL;
        p->result = USB_RET_STALL;
        usb_packet_complete(dev, p);
    }

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

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

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

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

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

    if (s->req) {
        scsi_req_cancel(s->req);
    }
P
pbrook 已提交
336 337 338
}

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

P
pbrook 已提交
346
    switch (p->pid) {
P
pbrook 已提交
347 348 349 350 351 352
    case USB_TOKEN_OUT:
        if (devep != 2)
            goto fail;

        switch (s->mode) {
        case USB_MSDM_CBW:
G
Gerd Hoffmann 已提交
353
            if (p->iov.size != 31) {
P
pbrook 已提交
354 355 356
                fprintf(stderr, "usb-msd: Bad CBW size");
                goto fail;
            }
G
Gerd Hoffmann 已提交
357
            usb_packet_copy(p, &cbw, 31);
P
pbrook 已提交
358 359 360 361 362 363 364 365 366 367
            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;
            }
368
            tag = le32_to_cpu(cbw.tag);
P
pbrook 已提交
369 370 371 372 373 374 375 376 377
            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",
378
                    tag, cbw.flags, cbw.cmd_len, s->data_len);
P
pbrook 已提交
379
            s->residue = 0;
G
Gerd Hoffmann 已提交
380
            s->scsi_len = 0;
381
            s->req = scsi_req_new(s->scsi_dev, tag, 0, cbw.cmd, NULL);
382
            scsi_req_enqueue(s->req);
383
            if (s->req && s->req->cmd.xfer != SCSI_XFER_NONE) {
384
                scsi_req_continue(s->req);
P
pbrook 已提交
385
            }
G
Gerd Hoffmann 已提交
386
            ret = p->result;
P
pbrook 已提交
387 388 389
            break;

        case USB_MSDM_DATAOUT:
G
Gerd Hoffmann 已提交
390 391
            DPRINTF("Data out %zd/%d\n", p->iov.size, s->data_len);
            if (p->iov.size > s->data_len) {
P
pbrook 已提交
392
                goto fail;
G
Gerd Hoffmann 已提交
393
            }
P
pbrook 已提交
394

P
pbrook 已提交
395
            if (s->scsi_len) {
G
Gerd Hoffmann 已提交
396
                usb_msd_copy_data(s, p);
P
pbrook 已提交
397
            }
G
Gerd Hoffmann 已提交
398 399 400 401 402 403 404 405 406
            if (s->residue) {
                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 已提交
407
            }
G
Gerd Hoffmann 已提交
408
            if (p->result < p->iov.size) {
P
pbrook 已提交
409 410 411
                DPRINTF("Deferring packet %p\n", p);
                s->packet = p;
                ret = USB_RET_ASYNC;
P
pbrook 已提交
412
            } else {
G
Gerd Hoffmann 已提交
413
                ret = p->result;
P
pbrook 已提交
414
            }
P
pbrook 已提交
415 416 417
            break;

        default:
G
Gerd Hoffmann 已提交
418
            DPRINTF("Unexpected write (len %zd)\n", p->iov.size);
P
pbrook 已提交
419 420 421 422 423 424 425 426 427
            goto fail;
        }
        break;

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

        switch (s->mode) {
P
pbrook 已提交
428
        case USB_MSDM_DATAOUT:
G
Gerd Hoffmann 已提交
429
            if (s->data_len != 0 || p->iov.size < 13) {
P
pbrook 已提交
430
                goto fail;
G
Gerd Hoffmann 已提交
431
            }
P
pbrook 已提交
432 433 434 435 436
            /* Waiting for SCSI write to complete.  */
            s->packet = p;
            ret = USB_RET_ASYNC;
            break;

P
pbrook 已提交
437
        case USB_MSDM_CSW:
G
Gerd Hoffmann 已提交
438
            if (p->iov.size < 13) {
P
pbrook 已提交
439
                goto fail;
G
Gerd Hoffmann 已提交
440
            }
P
pbrook 已提交
441

442 443 444 445 446 447 448 449 450
            if (s->req) {
                /* still in flight */
                s->packet = p;
                ret = USB_RET_ASYNC;
            } else {
                usb_msd_send_status(s, p);
                s->mode = USB_MSDM_CBW;
                ret = 13;
            }
P
pbrook 已提交
451 452 453
            break;

        case USB_MSDM_DATAIN:
G
Gerd Hoffmann 已提交
454 455
            DPRINTF("Data in %zd/%d, scsi_len %d\n",
                    p->iov.size, s->data_len, s->scsi_len);
P
pbrook 已提交
456
            if (s->scsi_len) {
G
Gerd Hoffmann 已提交
457
                usb_msd_copy_data(s, p);
P
pbrook 已提交
458
            }
G
Gerd Hoffmann 已提交
459 460 461 462 463 464 465 466 467
            if (s->residue) {
                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 已提交
468
            }
G
Gerd Hoffmann 已提交
469
            if (p->result < p->iov.size) {
P
pbrook 已提交
470 471 472
                DPRINTF("Deferring packet %p\n", p);
                s->packet = p;
                ret = USB_RET_ASYNC;
P
pbrook 已提交
473
            } else {
G
Gerd Hoffmann 已提交
474
                ret = p->result;
P
pbrook 已提交
475
            }
P
pbrook 已提交
476 477 478
            break;

        default:
G
Gerd Hoffmann 已提交
479
            DPRINTF("Unexpected read (len %zd)\n", p->iov.size);
P
pbrook 已提交
480 481 482 483 484 485 486 487 488 489 490 491 492 493
            goto fail;
        }
        break;

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

    return ret;
}

494 495 496 497 498
static void usb_msd_password_cb(void *opaque, int err)
{
    MSDState *s = opaque;

    if (!err)
499 500 501
        err = usb_device_attach(&s->dev);

    if (err)
502
        qdev_unplug(&s->dev.qdev, NULL);
503 504
}

505 506
static const struct SCSIBusInfo usb_msd_scsi_info = {
    .tcq = false,
P
Paolo Bonzini 已提交
507 508
    .max_target = 0,
    .max_lun = 0,
509

510
    .transfer_data = usb_msd_transfer_data,
P
Paolo Bonzini 已提交
511 512
    .complete = usb_msd_command_complete,
    .cancel = usb_msd_request_cancelled
P
Paolo Bonzini 已提交
513 514
};

515 516 517
static int usb_msd_initfn(USBDevice *dev)
{
    MSDState *s = DO_UPCAST(MSDState, dev, dev);
518
    BlockDriverState *bs = s->conf.bs;
519
    DriveInfo *dinfo;
520

521
    if (!bs) {
522
        error_report("drive property not set");
523 524 525
        return -1;
    }

526 527 528
    /*
     * 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
529 530 531
     * creates automatically.  But first it needs to detach from its
     * blockdev, or else scsi_bus_legacy_add_drive() dies when it
     * attaches again.
532 533 534
     *
     * The hack is probably a bad idea.
     */
535
    bdrv_detach_dev(bs, &s->dev.qdev);
536
    s->conf.bs = NULL;
537

538 539 540 541 542 543 544 545 546
    if (!s->serial) {
        /* try to fall back to value set with legacy -drive serial=... */
        dinfo = drive_get_by_blockdev(bs);
        if (*dinfo->serial) {
            s->serial = strdup(dinfo->serial);
        }
    }
    if (s->serial) {
        usb_desc_set_string(dev, STR_SERIALNUMBER, s->serial);
547 548
    }

549
    usb_desc_init(dev);
550
    scsi_bus_new(&s->bus, &s->dev.qdev, &usb_msd_scsi_info);
551 552
    s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable,
                                            s->conf.bootindex);
553 554 555
    if (!s->scsi_dev) {
        return -1;
    }
G
Gerd Hoffmann 已提交
556
    s->bus.qbus.allow_hotplug = 0;
557
    usb_msd_handle_reset(dev);
558

559
    if (bdrv_key_required(bs)) {
560
        if (cur_mon) {
561
            monitor_read_bdrv_key_start(cur_mon, bs, usb_msd_password_cb, s);
562 563 564 565 566 567
            s->dev.auto_attach = 0;
        } else {
            autostart = 0;
        }
    }

568 569 570
    return 0;
}

571
static USBDevice *usb_msd_init(USBBus *bus, const char *filename)
P
pbrook 已提交
572
{
573 574 575 576
    static int nr=0;
    char id[8];
    QemuOpts *opts;
    DriveInfo *dinfo;
577
    USBDevice *dev;
578 579 580
    const char *p1;
    char fmt[32];

581 582
    /* parse -usbdevice disk: syntax into drive opts */
    snprintf(id, sizeof(id), "usb%d", nr++);
583
    opts = qemu_opts_create(qemu_find_opts("drive"), id, 0);
584

585 586 587 588 589 590 591
    p1 = strchr(filename, ':');
    if (p1++) {
        const char *p2;

        if (strstart(filename, "format=", &p2)) {
            int len = MIN(p1 - p2, sizeof(fmt));
            pstrcpy(fmt, len, p2);
592
            qemu_opt_set(opts, "format", fmt);
593 594 595 596 597 598 599 600 601 602
        } 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;
    }
603 604
    qemu_opt_set(opts, "file", filename);
    qemu_opt_set(opts, "if", "none");
P
pbrook 已提交
605

606
    /* create host drive */
607
    dinfo = drive_init(opts, 0);
608 609
    if (!dinfo) {
        qemu_opts_del(opts);
610
        return NULL;
611
    }
P
pbrook 已提交
612

613
    /* create guest device */
614
    dev = usb_create(bus, "usb-storage");
P
Paul Brook 已提交
615 616 617
    if (!dev) {
        return NULL;
    }
618 619 620 621
    if (qdev_prop_set_drive(&dev->qdev, "drive", dinfo->bdrv) < 0) {
        qdev_free(&dev->qdev);
        return NULL;
    }
622 623
    if (qdev_init(&dev->qdev) < 0)
        return NULL;
624

625
    return dev;
P
pbrook 已提交
626
}
627

628 629 630 631 632 633 634 635 636 637 638
static const VMStateDescription vmstate_usb_msd = {
    .name = "usb-storage",
    .unmigratable = 1, /* FIXME: handle transactions which are in flight */
    .version_id = 1,
    .minimum_version_id = 1,
    .fields = (VMStateField []) {
        VMSTATE_USB_DEVICE(dev, MSDState),
        VMSTATE_END_OF_LIST()
    }
};

639 640 641 642 643 644 645
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(),
};

646 647
static void usb_msd_class_initfn(ObjectClass *klass, void *data)
{
648
    DeviceClass *dc = DEVICE_CLASS(klass);
649 650 651 652 653 654 655 656 657 658
    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;
659 660 661
    dc->fw_name = "storage";
    dc->vmsd = &vmstate_usb_msd;
    dc->props = msd_properties;
662 663
}

664 665 666 667 668
static TypeInfo msd_info = {
    .name          = "usb-storage",
    .parent        = TYPE_USB_DEVICE,
    .instance_size = sizeof(MSDState),
    .class_init    = usb_msd_class_initfn,
669 670
};

A
Andreas Färber 已提交
671
static void usb_msd_register_types(void)
672
{
673
    type_register_static(&msd_info);
674
    usb_legacy_register("usb-storage", "disk", usb_msd_init);
675
}
A
Andreas Färber 已提交
676 677

type_init(usb_msd_register_types)