Merge remote-tracking branch 'kraxel/usb.77' into staging
# By Gerd Hoffmann # Via Gerd Hoffmann * kraxel/usb.77: usb: add usb-bot device (scsi bulk-only transport). ohci: add missing break Revert "usb-storage: Drop useless null test in usb_msd_handle_data()"
This commit is contained in:
commit
36ba58044e
@ -2,7 +2,7 @@
|
|||||||
qemu usb storage emulation
|
qemu usb storage emulation
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
QEMU has two emulations for usb storage devices.
|
QEMU has three devices for usb storage emulation.
|
||||||
|
|
||||||
Number one emulates the classic bulk-only transport protocol which is
|
Number one emulates the classic bulk-only transport protocol which is
|
||||||
used by 99% of the usb sticks on the marked today and is called
|
used by 99% of the usb sticks on the marked today and is called
|
||||||
@ -31,6 +31,15 @@ with tree logical units:
|
|||||||
-device scsi-cd,bus=uas.0,scsi-id=0,lun=5,drive=uas-cdrom
|
-device scsi-cd,bus=uas.0,scsi-id=0,lun=5,drive=uas-cdrom
|
||||||
|
|
||||||
|
|
||||||
|
Number three emulates the classic bulk-only transport protocol too.
|
||||||
|
It's called "usb-bot". It shares most code with "usb-storage", and
|
||||||
|
the guest will not be able to see the difference. The qemu command
|
||||||
|
line interface is simliar to usb-uas though, i.e. no automatic scsi
|
||||||
|
disk creation. It also features support for up to 16 LUNs. The LUN
|
||||||
|
numbers must be continous, i.e. for three devices you must use 0+1+2.
|
||||||
|
The 0+1+5 numbering from the "usb-uas" example isn't going to work
|
||||||
|
with "usb-bot".
|
||||||
|
|
||||||
enjoy,
|
enjoy,
|
||||||
Gerd
|
Gerd
|
||||||
|
|
||||||
|
@ -54,12 +54,12 @@ typedef struct {
|
|||||||
struct usb_msd_csw csw;
|
struct usb_msd_csw csw;
|
||||||
SCSIRequest *req;
|
SCSIRequest *req;
|
||||||
SCSIBus bus;
|
SCSIBus bus;
|
||||||
BlockConf conf;
|
|
||||||
char *serial;
|
|
||||||
SCSIDevice *scsi_dev;
|
|
||||||
uint32_t removable;
|
|
||||||
/* For async completion. */
|
/* For async completion. */
|
||||||
USBPacket *packet;
|
USBPacket *packet;
|
||||||
|
/* usb-storage only */
|
||||||
|
BlockConf conf;
|
||||||
|
char *serial;
|
||||||
|
uint32_t removable;
|
||||||
} MSDState;
|
} MSDState;
|
||||||
|
|
||||||
struct usb_msd_cbw {
|
struct usb_msd_cbw {
|
||||||
@ -343,7 +343,8 @@ static void usb_msd_handle_control(USBDevice *dev, USBPacket *p,
|
|||||||
int request, int value, int index, int length, uint8_t *data)
|
int request, int value, int index, int length, uint8_t *data)
|
||||||
{
|
{
|
||||||
MSDState *s = (MSDState *)dev;
|
MSDState *s = (MSDState *)dev;
|
||||||
int ret;
|
SCSIDevice *scsi_dev;
|
||||||
|
int ret, maxlun;
|
||||||
|
|
||||||
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
|
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
|
||||||
if (ret >= 0) {
|
if (ret >= 0) {
|
||||||
@ -359,7 +360,19 @@ static void usb_msd_handle_control(USBDevice *dev, USBPacket *p,
|
|||||||
s->mode = USB_MSDM_CBW;
|
s->mode = USB_MSDM_CBW;
|
||||||
break;
|
break;
|
||||||
case ClassInterfaceRequest | GetMaxLun:
|
case ClassInterfaceRequest | GetMaxLun:
|
||||||
data[0] = 0;
|
maxlun = 0;
|
||||||
|
for (;;) {
|
||||||
|
scsi_dev = scsi_device_find(&s->bus, 0, 0, maxlun+1);
|
||||||
|
if (scsi_dev == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (scsi_dev->lun != maxlun+1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
maxlun++;
|
||||||
|
}
|
||||||
|
DPRINTF("MaxLun %d\n", maxlun);
|
||||||
|
data[0] = maxlun;
|
||||||
p->actual_length = 1;
|
p->actual_length = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -386,6 +399,7 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
|
|||||||
uint32_t tag;
|
uint32_t tag;
|
||||||
struct usb_msd_cbw cbw;
|
struct usb_msd_cbw cbw;
|
||||||
uint8_t devep = p->ep->nr;
|
uint8_t devep = p->ep->nr;
|
||||||
|
SCSIDevice *scsi_dev;
|
||||||
|
|
||||||
switch (p->pid) {
|
switch (p->pid) {
|
||||||
case USB_TOKEN_OUT:
|
case USB_TOKEN_OUT:
|
||||||
@ -405,7 +419,8 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
DPRINTF("Command on LUN %d\n", cbw.lun);
|
DPRINTF("Command on LUN %d\n", cbw.lun);
|
||||||
if (cbw.lun != 0) {
|
scsi_dev = scsi_device_find(&s->bus, 0, 0, cbw.lun);
|
||||||
|
if (scsi_dev == NULL) {
|
||||||
fprintf(stderr, "usb-msd: Bad LUN %d\n", cbw.lun);
|
fprintf(stderr, "usb-msd: Bad LUN %d\n", cbw.lun);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@ -422,12 +437,12 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
|
|||||||
tag, cbw.flags, cbw.cmd_len, s->data_len);
|
tag, cbw.flags, cbw.cmd_len, s->data_len);
|
||||||
assert(le32_to_cpu(s->csw.residue) == 0);
|
assert(le32_to_cpu(s->csw.residue) == 0);
|
||||||
s->scsi_len = 0;
|
s->scsi_len = 0;
|
||||||
s->req = scsi_req_new(s->scsi_dev, tag, 0, cbw.cmd, NULL);
|
s->req = scsi_req_new(scsi_dev, tag, cbw.lun, cbw.cmd, NULL);
|
||||||
#ifdef DEBUG_MSD
|
#ifdef DEBUG_MSD
|
||||||
scsi_req_print(s->req);
|
scsi_req_print(s->req);
|
||||||
#endif
|
#endif
|
||||||
scsi_req_enqueue(s->req);
|
scsi_req_enqueue(s->req);
|
||||||
if (s->req->cmd.xfer != SCSI_XFER_NONE) {
|
if (s->req && s->req->cmd.xfer != SCSI_XFER_NONE) {
|
||||||
scsi_req_continue(s->req);
|
scsi_req_continue(s->req);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -553,7 +568,7 @@ static void *usb_msd_load_request(QEMUFile *f, SCSIRequest *req)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct SCSIBusInfo usb_msd_scsi_info = {
|
static const struct SCSIBusInfo usb_msd_scsi_info_storage = {
|
||||||
.tcq = false,
|
.tcq = false,
|
||||||
.max_target = 0,
|
.max_target = 0,
|
||||||
.max_lun = 0,
|
.max_lun = 0,
|
||||||
@ -564,10 +579,22 @@ static const struct SCSIBusInfo usb_msd_scsi_info = {
|
|||||||
.load_request = usb_msd_load_request,
|
.load_request = usb_msd_load_request,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int usb_msd_initfn(USBDevice *dev)
|
static const struct SCSIBusInfo usb_msd_scsi_info_bot = {
|
||||||
|
.tcq = false,
|
||||||
|
.max_target = 0,
|
||||||
|
.max_lun = 15,
|
||||||
|
|
||||||
|
.transfer_data = usb_msd_transfer_data,
|
||||||
|
.complete = usb_msd_command_complete,
|
||||||
|
.cancel = usb_msd_request_cancelled,
|
||||||
|
.load_request = usb_msd_load_request,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int usb_msd_initfn_storage(USBDevice *dev)
|
||||||
{
|
{
|
||||||
MSDState *s = DO_UPCAST(MSDState, dev, dev);
|
MSDState *s = DO_UPCAST(MSDState, dev, dev);
|
||||||
BlockDriverState *bs = s->conf.bs;
|
BlockDriverState *bs = s->conf.bs;
|
||||||
|
SCSIDevice *scsi_dev;
|
||||||
|
|
||||||
if (!bs) {
|
if (!bs) {
|
||||||
error_report("drive property not set");
|
error_report("drive property not set");
|
||||||
@ -595,10 +622,10 @@ static int usb_msd_initfn(USBDevice *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
usb_desc_init(dev);
|
usb_desc_init(dev);
|
||||||
scsi_bus_new(&s->bus, &s->dev.qdev, &usb_msd_scsi_info);
|
scsi_bus_new(&s->bus, &s->dev.qdev, &usb_msd_scsi_info_storage);
|
||||||
s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable,
|
scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable,
|
||||||
s->conf.bootindex);
|
s->conf.bootindex);
|
||||||
if (!s->scsi_dev) {
|
if (!scsi_dev) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
s->bus.qbus.allow_hotplug = 0;
|
s->bus.qbus.allow_hotplug = 0;
|
||||||
@ -616,6 +643,19 @@ static int usb_msd_initfn(USBDevice *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int usb_msd_initfn_bot(USBDevice *dev)
|
||||||
|
{
|
||||||
|
MSDState *s = DO_UPCAST(MSDState, dev, dev);
|
||||||
|
|
||||||
|
usb_desc_create_serial(dev);
|
||||||
|
usb_desc_init(dev);
|
||||||
|
scsi_bus_new(&s->bus, &s->dev.qdev, &usb_msd_scsi_info_bot);
|
||||||
|
s->bus.qbus.allow_hotplug = 0;
|
||||||
|
usb_msd_handle_reset(dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static USBDevice *usb_msd_init(USBBus *bus, const char *filename)
|
static USBDevice *usb_msd_init(USBBus *bus, const char *filename)
|
||||||
{
|
{
|
||||||
static int nr=0;
|
static int nr=0;
|
||||||
@ -698,12 +738,11 @@ static Property msd_properties[] = {
|
|||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
static void usb_msd_class_initfn(ObjectClass *klass, void *data)
|
static void usb_msd_class_initfn_common(ObjectClass *klass)
|
||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
|
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
|
||||||
|
|
||||||
uc->init = usb_msd_initfn;
|
|
||||||
uc->product_desc = "QEMU USB MSD";
|
uc->product_desc = "QEMU USB MSD";
|
||||||
uc->usb_desc = &desc;
|
uc->usb_desc = &desc;
|
||||||
uc->cancel_packet = usb_msd_cancel_io;
|
uc->cancel_packet = usb_msd_cancel_io;
|
||||||
@ -713,19 +752,44 @@ static void usb_msd_class_initfn(ObjectClass *klass, void *data)
|
|||||||
uc->handle_data = usb_msd_handle_data;
|
uc->handle_data = usb_msd_handle_data;
|
||||||
dc->fw_name = "storage";
|
dc->fw_name = "storage";
|
||||||
dc->vmsd = &vmstate_usb_msd;
|
dc->vmsd = &vmstate_usb_msd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_msd_class_initfn_storage(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
|
||||||
|
|
||||||
|
uc->init = usb_msd_initfn_storage;
|
||||||
dc->props = msd_properties;
|
dc->props = msd_properties;
|
||||||
|
usb_msd_class_initfn_common(klass);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_msd_class_initfn_bot(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
|
||||||
|
|
||||||
|
uc->init = usb_msd_initfn_bot;
|
||||||
|
usb_msd_class_initfn_common(klass);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo msd_info = {
|
static const TypeInfo msd_info = {
|
||||||
.name = "usb-storage",
|
.name = "usb-storage",
|
||||||
.parent = TYPE_USB_DEVICE,
|
.parent = TYPE_USB_DEVICE,
|
||||||
.instance_size = sizeof(MSDState),
|
.instance_size = sizeof(MSDState),
|
||||||
.class_init = usb_msd_class_initfn,
|
.class_init = usb_msd_class_initfn_storage,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const TypeInfo bot_info = {
|
||||||
|
.name = "usb-bot",
|
||||||
|
.parent = TYPE_USB_DEVICE,
|
||||||
|
.instance_size = sizeof(MSDState),
|
||||||
|
.class_init = usb_msd_class_initfn_bot,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void usb_msd_register_types(void)
|
static void usb_msd_register_types(void)
|
||||||
{
|
{
|
||||||
type_register_static(&msd_info);
|
type_register_static(&msd_info);
|
||||||
|
type_register_static(&bot_info);
|
||||||
usb_legacy_register("usb-storage", "disk", usb_msd_init);
|
usb_legacy_register("usb-storage", "disk", usb_msd_init);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1736,6 +1736,7 @@ static void ohci_mem_write(void *opaque,
|
|||||||
/* PXA27x specific registers */
|
/* PXA27x specific registers */
|
||||||
case 24: /* HcStatus */
|
case 24: /* HcStatus */
|
||||||
ohci->hstatus &= ~(val & ohci->hmask);
|
ohci->hstatus &= ~(val & ohci->hmask);
|
||||||
|
break;
|
||||||
|
|
||||||
case 25: /* HcHReset */
|
case 25: /* HcHReset */
|
||||||
ohci->hreset = val & ~OHCI_HRESET_FSBIR;
|
ohci->hreset = val & ~OHCI_HRESET_FSBIR;
|
||||||
|
Loading…
Reference in New Issue
Block a user