2 * USB Mass Storage Device emulation
4 * Copyright (c) 2006 CodeSourcery.
5 * Written by Paul Brook
7 * This code is licensed under the LGPL.
10 #include "qemu/osdep.h"
11 #include "qemu/typedefs.h"
12 #include "qapi/error.h"
13 #include "qapi/visitor.h"
15 #include "hw/usb/desc.h"
16 #include "hw/usb/msd.h"
17 #include "sysemu/sysemu.h"
18 #include "sysemu/block-backend.h"
20 static const struct SCSIBusInfo usb_msd_scsi_info_storage
= {
25 .transfer_data
= usb_msd_transfer_data
,
26 .complete
= usb_msd_command_complete
,
27 .cancel
= usb_msd_request_cancelled
,
28 .load_request
= usb_msd_load_request
,
31 static void usb_msd_storage_realize(USBDevice
*dev
, Error
**errp
)
33 MSDState
*s
= USB_STORAGE_DEV(dev
);
34 BlockBackend
*blk
= s
->conf
.blk
;
38 error_setg(errp
, "drive property not set");
42 if (!blkconf_blocksizes(&s
->conf
, errp
)) {
46 if (!blkconf_apply_backend_options(&s
->conf
, !blk_supports_write_perm(blk
),
52 * Hack alert: this pretends to be a block device, but it's really
53 * a SCSI bus that can serve only a single device, which it
54 * creates automatically. But first it needs to detach from its
55 * blockdev, or else scsi_bus_legacy_add_drive() dies when it
56 * attaches again. We also need to take another reference so that
57 * blk_detach_dev() doesn't free blk while we still need it.
59 * The hack is probably a bad idea.
62 blk_detach_dev(blk
, DEVICE(s
));
65 usb_desc_create_serial(dev
);
67 dev
->flags
|= (1 << USB_DEV_FLAG_IS_SCSI_STORAGE
);
68 scsi_bus_new(&s
->bus
, sizeof(s
->bus
), DEVICE(dev
),
69 &usb_msd_scsi_info_storage
, NULL
);
70 scsi_dev
= scsi_bus_legacy_add_drive(&s
->bus
, blk
, 0, !!s
->removable
,
71 s
->conf
.bootindex
, s
->conf
.share_rw
,
72 s
->conf
.rerror
, s
->conf
.werror
,
79 usb_msd_handle_reset(dev
);
80 s
->scsi_dev
= scsi_dev
;
83 static Property msd_properties
[] = {
84 DEFINE_BLOCK_PROPERTIES(MSDState
, conf
),
85 DEFINE_BLOCK_ERROR_PROPERTIES(MSDState
, conf
),
86 DEFINE_PROP_BOOL("removable", MSDState
, removable
, false),
87 DEFINE_PROP_BOOL("commandlog", MSDState
, commandlog
, false),
88 DEFINE_PROP_END_OF_LIST(),
91 static void usb_msd_class_storage_initfn(ObjectClass
*klass
, void *data
)
93 DeviceClass
*dc
= DEVICE_CLASS(klass
);
94 USBDeviceClass
*uc
= USB_DEVICE_CLASS(klass
);
96 uc
->realize
= usb_msd_storage_realize
;
97 device_class_set_props(dc
, msd_properties
);
100 static void usb_msd_get_bootindex(Object
*obj
, Visitor
*v
, const char *name
,
101 void *opaque
, Error
**errp
)
103 USBDevice
*dev
= USB_DEVICE(obj
);
104 MSDState
*s
= USB_STORAGE_DEV(dev
);
106 visit_type_int32(v
, name
, &s
->conf
.bootindex
, errp
);
109 static void usb_msd_set_bootindex(Object
*obj
, Visitor
*v
, const char *name
,
110 void *opaque
, Error
**errp
)
112 USBDevice
*dev
= USB_DEVICE(obj
);
113 MSDState
*s
= USB_STORAGE_DEV(dev
);
115 Error
*local_err
= NULL
;
117 if (!visit_type_int32(v
, name
, &boot_index
, errp
)) {
120 /* check whether bootindex is present in fw_boot_order list */
121 check_boot_index(boot_index
, &local_err
);
125 /* change bootindex to a new one */
126 s
->conf
.bootindex
= boot_index
;
129 object_property_set_int(OBJECT(s
->scsi_dev
), "bootindex", boot_index
,
134 error_propagate(errp
, local_err
);
137 static void usb_msd_instance_init(Object
*obj
)
139 object_property_add(obj
, "bootindex", "int32",
140 usb_msd_get_bootindex
,
141 usb_msd_set_bootindex
, NULL
, NULL
);
142 object_property_set_int(obj
, "bootindex", -1, NULL
);
145 static const TypeInfo msd_info
= {
146 .name
= "usb-storage",
147 .parent
= TYPE_USB_STORAGE
,
148 .class_init
= usb_msd_class_storage_initfn
,
149 .instance_init
= usb_msd_instance_init
,
152 static void register_types(void)
154 type_register_static(&msd_info
);
157 type_init(register_types
)