iotests: Drop readlink -f
[qemu/ar7.git] / hw / usb / dev-storage.c
blob648340323f68ce1c056c3c8a765059d7449e631e
1 /*
2 * USB Mass Storage Device emulation
4 * Copyright (c) 2006 CodeSourcery.
5 * Written by Paul Brook
7 * This code is licensed under the LGPL.
8 */
10 #include "qemu/osdep.h"
11 #include "qapi/error.h"
12 #include "qemu/error-report.h"
13 #include "qemu/module.h"
14 #include "qemu/option.h"
15 #include "qemu/config-file.h"
16 #include "hw/usb.h"
17 #include "desc.h"
18 #include "hw/qdev-properties.h"
19 #include "hw/scsi/scsi.h"
20 #include "migration/vmstate.h"
21 #include "sysemu/sysemu.h"
22 #include "sysemu/block-backend.h"
23 #include "qapi/visitor.h"
24 #include "qemu/cutils.h"
25 #include "qom/object.h"
27 //#define DEBUG_MSD
29 #ifdef DEBUG_MSD
30 #define DPRINTF(fmt, ...) \
31 do { printf("usb-msd: " fmt , ## __VA_ARGS__); } while (0)
32 #else
33 #define DPRINTF(fmt, ...) do {} while(0)
34 #endif
36 /* USB requests. */
37 #define MassStorageReset 0xff
38 #define GetMaxLun 0xfe
40 enum USBMSDMode {
41 USB_MSDM_CBW, /* Command Block. */
42 USB_MSDM_DATAOUT, /* Transfer data to device. */
43 USB_MSDM_DATAIN, /* Transfer data from device. */
44 USB_MSDM_CSW /* Command Status. */
47 struct usb_msd_csw {
48 uint32_t sig;
49 uint32_t tag;
50 uint32_t residue;
51 uint8_t status;
54 struct MSDState {
55 USBDevice dev;
56 enum USBMSDMode mode;
57 uint32_t scsi_off;
58 uint32_t scsi_len;
59 uint32_t data_len;
60 struct usb_msd_csw csw;
61 SCSIRequest *req;
62 SCSIBus bus;
63 /* For async completion. */
64 USBPacket *packet;
65 /* usb-storage only */
66 BlockConf conf;
67 uint32_t removable;
68 SCSIDevice *scsi_dev;
70 typedef struct MSDState MSDState;
72 #define TYPE_USB_STORAGE "usb-storage-dev"
73 DECLARE_INSTANCE_CHECKER(MSDState, USB_STORAGE_DEV,
74 TYPE_USB_STORAGE)
76 struct usb_msd_cbw {
77 uint32_t sig;
78 uint32_t tag;
79 uint32_t data_len;
80 uint8_t flags;
81 uint8_t lun;
82 uint8_t cmd_len;
83 uint8_t cmd[16];
86 enum {
87 STR_MANUFACTURER = 1,
88 STR_PRODUCT,
89 STR_SERIALNUMBER,
90 STR_CONFIG_FULL,
91 STR_CONFIG_HIGH,
92 STR_CONFIG_SUPER,
95 static const USBDescStrings desc_strings = {
96 [STR_MANUFACTURER] = "QEMU",
97 [STR_PRODUCT] = "QEMU USB HARDDRIVE",
98 [STR_SERIALNUMBER] = "1",
99 [STR_CONFIG_FULL] = "Full speed config (usb 1.1)",
100 [STR_CONFIG_HIGH] = "High speed config (usb 2.0)",
101 [STR_CONFIG_SUPER] = "Super speed config (usb 3.0)",
104 static const USBDescIface desc_iface_full = {
105 .bInterfaceNumber = 0,
106 .bNumEndpoints = 2,
107 .bInterfaceClass = USB_CLASS_MASS_STORAGE,
108 .bInterfaceSubClass = 0x06, /* SCSI */
109 .bInterfaceProtocol = 0x50, /* Bulk */
110 .eps = (USBDescEndpoint[]) {
112 .bEndpointAddress = USB_DIR_IN | 0x01,
113 .bmAttributes = USB_ENDPOINT_XFER_BULK,
114 .wMaxPacketSize = 64,
116 .bEndpointAddress = USB_DIR_OUT | 0x02,
117 .bmAttributes = USB_ENDPOINT_XFER_BULK,
118 .wMaxPacketSize = 64,
123 static const USBDescDevice desc_device_full = {
124 .bcdUSB = 0x0200,
125 .bMaxPacketSize0 = 8,
126 .bNumConfigurations = 1,
127 .confs = (USBDescConfig[]) {
129 .bNumInterfaces = 1,
130 .bConfigurationValue = 1,
131 .iConfiguration = STR_CONFIG_FULL,
132 .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
133 .nif = 1,
134 .ifs = &desc_iface_full,
139 static const USBDescIface desc_iface_high = {
140 .bInterfaceNumber = 0,
141 .bNumEndpoints = 2,
142 .bInterfaceClass = USB_CLASS_MASS_STORAGE,
143 .bInterfaceSubClass = 0x06, /* SCSI */
144 .bInterfaceProtocol = 0x50, /* Bulk */
145 .eps = (USBDescEndpoint[]) {
147 .bEndpointAddress = USB_DIR_IN | 0x01,
148 .bmAttributes = USB_ENDPOINT_XFER_BULK,
149 .wMaxPacketSize = 512,
151 .bEndpointAddress = USB_DIR_OUT | 0x02,
152 .bmAttributes = USB_ENDPOINT_XFER_BULK,
153 .wMaxPacketSize = 512,
158 static const USBDescDevice desc_device_high = {
159 .bcdUSB = 0x0200,
160 .bMaxPacketSize0 = 64,
161 .bNumConfigurations = 1,
162 .confs = (USBDescConfig[]) {
164 .bNumInterfaces = 1,
165 .bConfigurationValue = 1,
166 .iConfiguration = STR_CONFIG_HIGH,
167 .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
168 .nif = 1,
169 .ifs = &desc_iface_high,
174 static const USBDescIface desc_iface_super = {
175 .bInterfaceNumber = 0,
176 .bNumEndpoints = 2,
177 .bInterfaceClass = USB_CLASS_MASS_STORAGE,
178 .bInterfaceSubClass = 0x06, /* SCSI */
179 .bInterfaceProtocol = 0x50, /* Bulk */
180 .eps = (USBDescEndpoint[]) {
182 .bEndpointAddress = USB_DIR_IN | 0x01,
183 .bmAttributes = USB_ENDPOINT_XFER_BULK,
184 .wMaxPacketSize = 1024,
185 .bMaxBurst = 15,
187 .bEndpointAddress = USB_DIR_OUT | 0x02,
188 .bmAttributes = USB_ENDPOINT_XFER_BULK,
189 .wMaxPacketSize = 1024,
190 .bMaxBurst = 15,
195 static const USBDescDevice desc_device_super = {
196 .bcdUSB = 0x0300,
197 .bMaxPacketSize0 = 9,
198 .bNumConfigurations = 1,
199 .confs = (USBDescConfig[]) {
201 .bNumInterfaces = 1,
202 .bConfigurationValue = 1,
203 .iConfiguration = STR_CONFIG_SUPER,
204 .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
205 .nif = 1,
206 .ifs = &desc_iface_super,
211 static const USBDesc desc = {
212 .id = {
213 .idVendor = 0x46f4, /* CRC16() of "QEMU" */
214 .idProduct = 0x0001,
215 .bcdDevice = 0,
216 .iManufacturer = STR_MANUFACTURER,
217 .iProduct = STR_PRODUCT,
218 .iSerialNumber = STR_SERIALNUMBER,
220 .full = &desc_device_full,
221 .high = &desc_device_high,
222 .super = &desc_device_super,
223 .str = desc_strings,
226 static void usb_msd_copy_data(MSDState *s, USBPacket *p)
228 uint32_t len;
229 len = p->iov.size - p->actual_length;
230 if (len > s->scsi_len)
231 len = s->scsi_len;
232 usb_packet_copy(p, scsi_req_get_buf(s->req) + s->scsi_off, len);
233 s->scsi_len -= len;
234 s->scsi_off += len;
235 if (len > s->data_len) {
236 len = s->data_len;
238 s->data_len -= len;
239 if (s->scsi_len == 0 || s->data_len == 0) {
240 scsi_req_continue(s->req);
244 static void usb_msd_send_status(MSDState *s, USBPacket *p)
246 int len;
248 DPRINTF("Command status %d tag 0x%x, len %zd\n",
249 s->csw.status, le32_to_cpu(s->csw.tag), p->iov.size);
251 assert(s->csw.sig == cpu_to_le32(0x53425355));
252 len = MIN(sizeof(s->csw), p->iov.size);
253 usb_packet_copy(p, &s->csw, len);
254 memset(&s->csw, 0, sizeof(s->csw));
257 static void usb_msd_packet_complete(MSDState *s)
259 USBPacket *p = s->packet;
261 /* Set s->packet to NULL before calling usb_packet_complete
262 because another request may be issued before
263 usb_packet_complete returns. */
264 DPRINTF("Packet complete %p\n", p);
265 s->packet = NULL;
266 usb_packet_complete(&s->dev, p);
269 static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
271 MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
272 USBPacket *p = s->packet;
274 assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV));
275 s->scsi_len = len;
276 s->scsi_off = 0;
277 if (p) {
278 usb_msd_copy_data(s, p);
279 p = s->packet;
280 if (p && p->actual_length == p->iov.size) {
281 p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
282 usb_msd_packet_complete(s);
287 static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, size_t resid)
289 MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
290 USBPacket *p = s->packet;
292 DPRINTF("Command complete %d tag 0x%x\n", status, req->tag);
294 s->csw.sig = cpu_to_le32(0x53425355);
295 s->csw.tag = cpu_to_le32(req->tag);
296 s->csw.residue = cpu_to_le32(s->data_len);
297 s->csw.status = status != 0;
299 if (s->packet) {
300 if (s->data_len == 0 && s->mode == USB_MSDM_DATAOUT) {
301 /* A deferred packet with no write data remaining must be
302 the status read packet. */
303 usb_msd_send_status(s, p);
304 s->mode = USB_MSDM_CBW;
305 } else if (s->mode == USB_MSDM_CSW) {
306 usb_msd_send_status(s, p);
307 s->mode = USB_MSDM_CBW;
308 } else {
309 if (s->data_len) {
310 int len = (p->iov.size - p->actual_length);
311 usb_packet_skip(p, len);
312 if (len > s->data_len) {
313 len = s->data_len;
315 s->data_len -= len;
317 if (s->data_len == 0) {
318 s->mode = USB_MSDM_CSW;
321 p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
322 usb_msd_packet_complete(s);
323 } else if (s->data_len == 0) {
324 s->mode = USB_MSDM_CSW;
326 scsi_req_unref(req);
327 s->req = NULL;
330 static void usb_msd_request_cancelled(SCSIRequest *req)
332 MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
334 if (req == s->req) {
335 scsi_req_unref(s->req);
336 s->req = NULL;
337 s->scsi_len = 0;
341 static void usb_msd_handle_reset(USBDevice *dev)
343 MSDState *s = (MSDState *)dev;
345 DPRINTF("Reset\n");
346 if (s->req) {
347 scsi_req_cancel(s->req);
349 assert(s->req == NULL);
351 if (s->packet) {
352 s->packet->status = USB_RET_STALL;
353 usb_msd_packet_complete(s);
356 s->mode = USB_MSDM_CBW;
359 static void usb_msd_handle_control(USBDevice *dev, USBPacket *p,
360 int request, int value, int index, int length, uint8_t *data)
362 MSDState *s = (MSDState *)dev;
363 SCSIDevice *scsi_dev;
364 int ret, maxlun;
366 ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
367 if (ret >= 0) {
368 return;
371 switch (request) {
372 case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
373 break;
374 /* Class specific requests. */
375 case ClassInterfaceOutRequest | MassStorageReset:
376 /* Reset state ready for the next CBW. */
377 s->mode = USB_MSDM_CBW;
378 break;
379 case ClassInterfaceRequest | GetMaxLun:
380 maxlun = 0;
381 for (;;) {
382 scsi_dev = scsi_device_find(&s->bus, 0, 0, maxlun+1);
383 if (scsi_dev == NULL) {
384 break;
386 if (scsi_dev->lun != maxlun+1) {
387 break;
389 maxlun++;
391 DPRINTF("MaxLun %d\n", maxlun);
392 data[0] = maxlun;
393 p->actual_length = 1;
394 break;
395 default:
396 p->status = USB_RET_STALL;
397 break;
401 static void usb_msd_cancel_io(USBDevice *dev, USBPacket *p)
403 MSDState *s = USB_STORAGE_DEV(dev);
405 assert(s->packet == p);
406 s->packet = NULL;
408 if (s->req) {
409 scsi_req_cancel(s->req);
413 static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
415 MSDState *s = (MSDState *)dev;
416 uint32_t tag;
417 struct usb_msd_cbw cbw;
418 uint8_t devep = p->ep->nr;
419 SCSIDevice *scsi_dev;
420 uint32_t len;
422 switch (p->pid) {
423 case USB_TOKEN_OUT:
424 if (devep != 2)
425 goto fail;
427 switch (s->mode) {
428 case USB_MSDM_CBW:
429 if (p->iov.size != 31) {
430 error_report("usb-msd: Bad CBW size");
431 goto fail;
433 usb_packet_copy(p, &cbw, 31);
434 if (le32_to_cpu(cbw.sig) != 0x43425355) {
435 error_report("usb-msd: Bad signature %08x",
436 le32_to_cpu(cbw.sig));
437 goto fail;
439 DPRINTF("Command on LUN %d\n", cbw.lun);
440 scsi_dev = scsi_device_find(&s->bus, 0, 0, cbw.lun);
441 if (scsi_dev == NULL) {
442 error_report("usb-msd: Bad LUN %d", cbw.lun);
443 goto fail;
445 tag = le32_to_cpu(cbw.tag);
446 s->data_len = le32_to_cpu(cbw.data_len);
447 if (s->data_len == 0) {
448 s->mode = USB_MSDM_CSW;
449 } else if (cbw.flags & 0x80) {
450 s->mode = USB_MSDM_DATAIN;
451 } else {
452 s->mode = USB_MSDM_DATAOUT;
454 DPRINTF("Command tag 0x%x flags %08x len %d data %d\n",
455 tag, cbw.flags, cbw.cmd_len, s->data_len);
456 assert(le32_to_cpu(s->csw.residue) == 0);
457 s->scsi_len = 0;
458 s->req = scsi_req_new(scsi_dev, tag, cbw.lun, cbw.cmd, NULL);
459 #ifdef DEBUG_MSD
460 scsi_req_print(s->req);
461 #endif
462 len = scsi_req_enqueue(s->req);
463 if (len) {
464 scsi_req_continue(s->req);
466 break;
468 case USB_MSDM_DATAOUT:
469 DPRINTF("Data out %zd/%d\n", p->iov.size, s->data_len);
470 if (p->iov.size > s->data_len) {
471 goto fail;
474 if (s->scsi_len) {
475 usb_msd_copy_data(s, p);
477 if (le32_to_cpu(s->csw.residue)) {
478 int len = p->iov.size - p->actual_length;
479 if (len) {
480 usb_packet_skip(p, len);
481 if (len > s->data_len) {
482 len = s->data_len;
484 s->data_len -= len;
485 if (s->data_len == 0) {
486 s->mode = USB_MSDM_CSW;
490 if (p->actual_length < p->iov.size) {
491 DPRINTF("Deferring packet %p [wait data-out]\n", p);
492 s->packet = p;
493 p->status = USB_RET_ASYNC;
495 break;
497 default:
498 DPRINTF("Unexpected write (len %zd)\n", p->iov.size);
499 goto fail;
501 break;
503 case USB_TOKEN_IN:
504 if (devep != 1)
505 goto fail;
507 switch (s->mode) {
508 case USB_MSDM_DATAOUT:
509 if (s->data_len != 0 || p->iov.size < 13) {
510 goto fail;
512 /* Waiting for SCSI write to complete. */
513 s->packet = p;
514 p->status = USB_RET_ASYNC;
515 break;
517 case USB_MSDM_CSW:
518 if (p->iov.size < 13) {
519 goto fail;
522 if (s->req) {
523 /* still in flight */
524 DPRINTF("Deferring packet %p [wait status]\n", p);
525 s->packet = p;
526 p->status = USB_RET_ASYNC;
527 } else {
528 usb_msd_send_status(s, p);
529 s->mode = USB_MSDM_CBW;
531 break;
533 case USB_MSDM_DATAIN:
534 DPRINTF("Data in %zd/%d, scsi_len %d\n",
535 p->iov.size, s->data_len, s->scsi_len);
536 if (s->scsi_len) {
537 usb_msd_copy_data(s, p);
539 if (le32_to_cpu(s->csw.residue)) {
540 int len = p->iov.size - p->actual_length;
541 if (len) {
542 usb_packet_skip(p, len);
543 if (len > s->data_len) {
544 len = s->data_len;
546 s->data_len -= len;
547 if (s->data_len == 0) {
548 s->mode = USB_MSDM_CSW;
552 if (p->actual_length < p->iov.size && s->mode == USB_MSDM_DATAIN) {
553 DPRINTF("Deferring packet %p [wait data-in]\n", p);
554 s->packet = p;
555 p->status = USB_RET_ASYNC;
557 break;
559 default:
560 DPRINTF("Unexpected read (len %zd)\n", p->iov.size);
561 goto fail;
563 break;
565 default:
566 DPRINTF("Bad token\n");
567 fail:
568 p->status = USB_RET_STALL;
569 break;
573 static void *usb_msd_load_request(QEMUFile *f, SCSIRequest *req)
575 MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
577 /* nothing to load, just store req in our state struct */
578 assert(s->req == NULL);
579 scsi_req_ref(req);
580 s->req = req;
581 return NULL;
584 static const struct SCSIBusInfo usb_msd_scsi_info_storage = {
585 .tcq = false,
586 .max_target = 0,
587 .max_lun = 0,
589 .transfer_data = usb_msd_transfer_data,
590 .complete = usb_msd_command_complete,
591 .cancel = usb_msd_request_cancelled,
592 .load_request = usb_msd_load_request,
595 static const struct SCSIBusInfo usb_msd_scsi_info_bot = {
596 .tcq = false,
597 .max_target = 0,
598 .max_lun = 15,
600 .transfer_data = usb_msd_transfer_data,
601 .complete = usb_msd_command_complete,
602 .cancel = usb_msd_request_cancelled,
603 .load_request = usb_msd_load_request,
606 static void usb_msd_storage_realize(USBDevice *dev, Error **errp)
608 MSDState *s = USB_STORAGE_DEV(dev);
609 BlockBackend *blk = s->conf.blk;
610 SCSIDevice *scsi_dev;
612 if (!blk) {
613 error_setg(errp, "drive property not set");
614 return;
617 if (!blkconf_blocksizes(&s->conf, errp)) {
618 return;
621 if (!blkconf_apply_backend_options(&s->conf, blk_is_read_only(blk), true,
622 errp)) {
623 return;
627 * Hack alert: this pretends to be a block device, but it's really
628 * a SCSI bus that can serve only a single device, which it
629 * creates automatically. But first it needs to detach from its
630 * blockdev, or else scsi_bus_legacy_add_drive() dies when it
631 * attaches again. We also need to take another reference so that
632 * blk_detach_dev() doesn't free blk while we still need it.
634 * The hack is probably a bad idea.
636 blk_ref(blk);
637 blk_detach_dev(blk, DEVICE(s));
638 s->conf.blk = NULL;
640 usb_desc_create_serial(dev);
641 usb_desc_init(dev);
642 scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
643 &usb_msd_scsi_info_storage, NULL);
644 scsi_dev = scsi_bus_legacy_add_drive(&s->bus, blk, 0, !!s->removable,
645 s->conf.bootindex, s->conf.share_rw,
646 s->conf.rerror, s->conf.werror,
647 dev->serial,
648 errp);
649 blk_unref(blk);
650 if (!scsi_dev) {
651 return;
653 usb_msd_handle_reset(dev);
654 s->scsi_dev = scsi_dev;
657 static void usb_msd_bot_realize(USBDevice *dev, Error **errp)
659 MSDState *s = USB_STORAGE_DEV(dev);
660 DeviceState *d = DEVICE(dev);
662 usb_desc_create_serial(dev);
663 usb_desc_init(dev);
664 if (d->hotplugged) {
665 s->dev.auto_attach = 0;
668 scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
669 &usb_msd_scsi_info_bot, NULL);
670 usb_msd_handle_reset(dev);
673 static const VMStateDescription vmstate_usb_msd = {
674 .name = "usb-storage",
675 .version_id = 1,
676 .minimum_version_id = 1,
677 .fields = (VMStateField[]) {
678 VMSTATE_USB_DEVICE(dev, MSDState),
679 VMSTATE_UINT32(mode, MSDState),
680 VMSTATE_UINT32(scsi_len, MSDState),
681 VMSTATE_UINT32(scsi_off, MSDState),
682 VMSTATE_UINT32(data_len, MSDState),
683 VMSTATE_UINT32(csw.sig, MSDState),
684 VMSTATE_UINT32(csw.tag, MSDState),
685 VMSTATE_UINT32(csw.residue, MSDState),
686 VMSTATE_UINT8(csw.status, MSDState),
687 VMSTATE_END_OF_LIST()
691 static Property msd_properties[] = {
692 DEFINE_BLOCK_PROPERTIES(MSDState, conf),
693 DEFINE_BLOCK_ERROR_PROPERTIES(MSDState, conf),
694 DEFINE_PROP_BIT("removable", MSDState, removable, 0, false),
695 DEFINE_PROP_END_OF_LIST(),
698 static void usb_msd_class_initfn_common(ObjectClass *klass, void *data)
700 DeviceClass *dc = DEVICE_CLASS(klass);
701 USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
703 uc->product_desc = "QEMU USB MSD";
704 uc->usb_desc = &desc;
705 uc->cancel_packet = usb_msd_cancel_io;
706 uc->handle_attach = usb_desc_attach;
707 uc->handle_reset = usb_msd_handle_reset;
708 uc->handle_control = usb_msd_handle_control;
709 uc->handle_data = usb_msd_handle_data;
710 set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
711 dc->fw_name = "storage";
712 dc->vmsd = &vmstate_usb_msd;
715 static void usb_msd_class_storage_initfn(ObjectClass *klass, void *data)
717 DeviceClass *dc = DEVICE_CLASS(klass);
718 USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
720 uc->realize = usb_msd_storage_realize;
721 device_class_set_props(dc, msd_properties);
724 static void usb_msd_get_bootindex(Object *obj, Visitor *v, const char *name,
725 void *opaque, Error **errp)
727 USBDevice *dev = USB_DEVICE(obj);
728 MSDState *s = USB_STORAGE_DEV(dev);
730 visit_type_int32(v, name, &s->conf.bootindex, errp);
733 static void usb_msd_set_bootindex(Object *obj, Visitor *v, const char *name,
734 void *opaque, Error **errp)
736 USBDevice *dev = USB_DEVICE(obj);
737 MSDState *s = USB_STORAGE_DEV(dev);
738 int32_t boot_index;
739 Error *local_err = NULL;
741 if (!visit_type_int32(v, name, &boot_index, errp)) {
742 return;
744 /* check whether bootindex is present in fw_boot_order list */
745 check_boot_index(boot_index, &local_err);
746 if (local_err) {
747 goto out;
749 /* change bootindex to a new one */
750 s->conf.bootindex = boot_index;
752 if (s->scsi_dev) {
753 object_property_set_int(OBJECT(s->scsi_dev), "bootindex", boot_index,
754 &error_abort);
757 out:
758 error_propagate(errp, local_err);
761 static const TypeInfo usb_storage_dev_type_info = {
762 .name = TYPE_USB_STORAGE,
763 .parent = TYPE_USB_DEVICE,
764 .instance_size = sizeof(MSDState),
765 .abstract = true,
766 .class_init = usb_msd_class_initfn_common,
769 static void usb_msd_instance_init(Object *obj)
771 object_property_add(obj, "bootindex", "int32",
772 usb_msd_get_bootindex,
773 usb_msd_set_bootindex, NULL, NULL);
774 object_property_set_int(obj, "bootindex", -1, NULL);
777 static void usb_msd_class_bot_initfn(ObjectClass *klass, void *data)
779 USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
781 uc->realize = usb_msd_bot_realize;
782 uc->attached_settable = true;
785 static const TypeInfo msd_info = {
786 .name = "usb-storage",
787 .parent = TYPE_USB_STORAGE,
788 .class_init = usb_msd_class_storage_initfn,
789 .instance_init = usb_msd_instance_init,
792 static const TypeInfo bot_info = {
793 .name = "usb-bot",
794 .parent = TYPE_USB_STORAGE,
795 .class_init = usb_msd_class_bot_initfn,
798 static void usb_msd_register_types(void)
800 type_register_static(&usb_storage_dev_type_info);
801 type_register_static(&msd_info);
802 type_register_static(&bot_info);
805 type_init(usb_msd_register_types)