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 "qapi/error.h"
12 #include "qapi/visitor.h"
14 #include "hw/usb/desc.h"
15 #include "hw/usb/msd.h"
16 #include "sysemu/sysemu.h"
17 #include "sysemu/block-backend.h"
19 static const struct SCSIBusInfo usb_msd_scsi_info_storage
= {
24 .transfer_data
= usb_msd_transfer_data
,
25 .complete
= usb_msd_command_complete
,
26 .cancel
= usb_msd_request_cancelled
,
27 .load_request
= usb_msd_load_request
,
30 static void usb_msd_storage_realize(USBDevice
*dev
, Error
**errp
)
32 MSDState
*s
= USB_STORAGE_DEV(dev
);
33 BlockBackend
*blk
= s
->conf
.blk
;
37 error_setg(errp
, "drive property not set");
41 if (!blkconf_blocksizes(&s
->conf
, errp
)) {
45 if (!blkconf_apply_backend_options(&s
->conf
, !blk_supports_write_perm(blk
),
51 * Hack alert: this pretends to be a block device, but it's really
52 * a SCSI bus that can serve only a single device, which it
53 * creates automatically. But first it needs to detach from its
54 * blockdev, or else scsi_bus_legacy_add_drive() dies when it
55 * attaches again. We also need to take another reference so that
56 * blk_detach_dev() doesn't free blk while we still need it.
58 * The hack is probably a bad idea.
61 blk_detach_dev(blk
, DEVICE(s
));
64 usb_desc_create_serial(dev
);
66 dev
->flags
|= (1 << USB_DEV_FLAG_IS_SCSI_STORAGE
);
67 scsi_bus_init(&s
->bus
, sizeof(s
->bus
), DEVICE(dev
),
68 &usb_msd_scsi_info_storage
);
69 scsi_dev
= scsi_bus_legacy_add_drive(&s
->bus
, blk
, 0, !!s
->removable
,
70 &s
->conf
, dev
->serial
, errp
);
75 usb_msd_handle_reset(dev
);
76 s
->scsi_dev
= scsi_dev
;
79 static Property msd_properties
[] = {
80 DEFINE_BLOCK_PROPERTIES(MSDState
, conf
),
81 DEFINE_BLOCK_ERROR_PROPERTIES(MSDState
, conf
),
82 DEFINE_PROP_BOOL("removable", MSDState
, removable
, false),
83 DEFINE_PROP_BOOL("commandlog", MSDState
, commandlog
, false),
84 DEFINE_PROP_END_OF_LIST(),
87 static void usb_msd_class_storage_initfn(ObjectClass
*klass
, void *data
)
89 DeviceClass
*dc
= DEVICE_CLASS(klass
);
90 USBDeviceClass
*uc
= USB_DEVICE_CLASS(klass
);
92 uc
->realize
= usb_msd_storage_realize
;
93 device_class_set_props(dc
, msd_properties
);
96 static void usb_msd_get_bootindex(Object
*obj
, Visitor
*v
, const char *name
,
97 void *opaque
, Error
**errp
)
99 USBDevice
*dev
= USB_DEVICE(obj
);
100 MSDState
*s
= USB_STORAGE_DEV(dev
);
102 visit_type_int32(v
, name
, &s
->conf
.bootindex
, errp
);
105 static void usb_msd_set_bootindex(Object
*obj
, Visitor
*v
, const char *name
,
106 void *opaque
, Error
**errp
)
108 USBDevice
*dev
= USB_DEVICE(obj
);
109 MSDState
*s
= USB_STORAGE_DEV(dev
);
111 Error
*local_err
= NULL
;
113 if (!visit_type_int32(v
, name
, &boot_index
, errp
)) {
116 /* check whether bootindex is present in fw_boot_order list */
117 check_boot_index(boot_index
, &local_err
);
121 /* change bootindex to a new one */
122 s
->conf
.bootindex
= boot_index
;
125 object_property_set_int(OBJECT(s
->scsi_dev
), "bootindex", boot_index
,
130 error_propagate(errp
, local_err
);
133 static void usb_msd_instance_init(Object
*obj
)
135 object_property_add(obj
, "bootindex", "int32",
136 usb_msd_get_bootindex
,
137 usb_msd_set_bootindex
, NULL
, NULL
);
138 object_property_set_int(obj
, "bootindex", -1, NULL
);
141 static const TypeInfo msd_info
= {
142 .name
= "usb-storage",
143 .parent
= TYPE_USB_STORAGE
,
144 .class_init
= usb_msd_class_storage_initfn
,
145 .instance_init
= usb_msd_instance_init
,
148 static void register_types(void)
150 type_register_static(&msd_info
);
153 type_init(register_types
)