diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/block/virtio-blk.c | 2 | ||||
-rw-r--r-- | hw/i386/pc_piix.c | 4 | ||||
-rw-r--r-- | hw/ide/core.c | 2 | ||||
-rw-r--r-- | hw/scsi/scsi-bus.c | 2 | ||||
-rw-r--r-- | hw/scsi/scsi-disk.c | 3 | ||||
-rw-r--r-- | hw/scsi/scsi-generic.c | 2 | ||||
-rw-r--r-- | hw/scsi/virtio-scsi.c | 6 | ||||
-rw-r--r-- | hw/usb/Makefile.objs | 2 | ||||
-rw-r--r-- | hw/usb/bus.c | 2 | ||||
-rw-r--r-- | hw/usb/desc-msos.c | 234 | ||||
-rw-r--r-- | hw/usb/desc.c | 37 | ||||
-rw-r--r-- | hw/usb/desc.h | 11 | ||||
-rw-r--r-- | hw/usb/dev-hid.c | 8 | ||||
-rw-r--r-- | hw/virtio/dataplane/vring.c | 2 |
14 files changed, 305 insertions, 12 deletions
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 19d0961a47..8a568e5edb 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -731,7 +731,7 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) register_savevm(dev, "virtio-blk", virtio_blk_id++, 2, virtio_blk_save, virtio_blk_load, s); bdrv_set_dev_ops(s->bs, &virtio_block_ops, s); - bdrv_set_buffer_alignment(s->bs, s->conf->logical_block_size); + bdrv_set_guest_block_size(s->bs, s->conf->logical_block_size); bdrv_iostatus_enable(s->bs); diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 276641436e..a327d71fb1 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -393,6 +393,10 @@ static QEMUMachine pc_i440fx_machine_v1_7 = { PC_I440FX_1_7_MACHINE_OPTIONS, .name = "pc-i440fx-1.7", .init = pc_init_pci_1_7, + .compat_props = (GlobalProperty[]) { + PC_COMPAT_1_7, + { /* end of list */ } + }, }; #define PC_I440FX_1_6_MACHINE_OPTIONS PC_I440FX_MACHINE_OPTIONS diff --git a/hw/ide/core.c b/hw/ide/core.c index e1f4c33fb8..036cd4a6d1 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -2103,7 +2103,7 @@ int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind, s->smart_selftest_count = 0; if (kind == IDE_CD) { bdrv_set_dev_ops(bs, &ide_cd_block_ops, s); - bdrv_set_buffer_alignment(bs, 2048); + bdrv_set_guest_block_size(bs, 2048); } else { if (!bdrv_is_inserted(s->bs)) { error_report("Device needs media, but drive is empty"); diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 3496c0bbd8..50b89ad4aa 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -469,6 +469,8 @@ static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf) r->req.dev->sense_is_ua = false; } break; + case TEST_UNIT_READY: + break; default: scsi_req_build_sense(req, SENSE_CODE(LUN_NOT_SUPPORTED)); scsi_req_complete(req, CHECK_CONDITION); diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index bce617cb93..a8d0f15ebe 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -2254,7 +2254,7 @@ static int scsi_initfn(SCSIDevice *dev) } else { bdrv_set_dev_ops(s->qdev.conf.bs, &scsi_disk_block_ops, s); } - bdrv_set_buffer_alignment(s->qdev.conf.bs, s->qdev.blocksize); + bdrv_set_guest_block_size(s->qdev.conf.bs, s->qdev.blocksize); bdrv_iostatus_enable(s->qdev.conf.bs); add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, NULL); @@ -2306,6 +2306,7 @@ static const SCSIReqOps scsi_disk_emulate_reqops = { .send_command = scsi_disk_emulate_command, .read_data = scsi_disk_emulate_read_data, .write_data = scsi_disk_emulate_write_data, + .cancel_io = scsi_cancel_io, .get_buf = scsi_get_buf, }; diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index 8f195bec00..f08b64e177 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -210,7 +210,7 @@ static void scsi_read_complete(void * opaque, int ret) s->blocksize = ldl_be_p(&r->buf[8]); s->max_lba = ldq_be_p(&r->buf[0]); } - bdrv_set_buffer_alignment(s->conf.bs, s->blocksize); + bdrv_set_guest_block_size(s->conf.bs, s->blocksize); scsi_req_data(&r->req, len); if (!r->req.io_canceled) { diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 6dcdd1b91c..6610b3aab3 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -306,6 +306,10 @@ static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status, VirtIOSCSIReq *req = r->hba_private; uint32_t sense_len; + if (r->io_canceled) { + return; + } + req->resp.cmd->response = VIRTIO_SCSI_S_OK; req->resp.cmd->status = status; if (req->resp.cmd->status == GOOD) { @@ -516,7 +520,7 @@ static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, evt->event = event; evt->reason = reason; if (!dev) { - assert(event == VIRTIO_SCSI_T_NO_EVENT); + assert(event == VIRTIO_SCSI_T_EVENTS_MISSED); } else { evt->lun[0] = 1; evt->lun[1] = dev->id; diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs index a3eac3e5c1..97b457541f 100644 --- a/hw/usb/Makefile.objs +++ b/hw/usb/Makefile.objs @@ -1,5 +1,5 @@ # usb subsystem core -common-obj-y += core.o combined-packet.o bus.o desc.o +common-obj-y += core.o combined-packet.o bus.o desc.o desc-msos.o common-obj-y += libhw.o # usb host adapters diff --git a/hw/usb/bus.c b/hw/usb/bus.c index 09848c6320..fe70429304 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -16,6 +16,8 @@ static Property usb_props[] = { DEFINE_PROP_STRING("serial", USBDevice, serial), DEFINE_PROP_BIT("full-path", USBDevice, flags, USB_DEV_FLAG_FULL_PATH, true), + DEFINE_PROP_BIT("msos-desc", USBDevice, flags, + USB_DEV_FLAG_MSOS_DESC_ENABLE, true), DEFINE_PROP_END_OF_LIST() }; diff --git a/hw/usb/desc-msos.c b/hw/usb/desc-msos.c new file mode 100644 index 0000000000..ed8d62cab8 --- /dev/null +++ b/hw/usb/desc-msos.c @@ -0,0 +1,234 @@ +#include "hw/usb.h" +#include "hw/usb/desc.h" + +/* + * Microsoft OS Descriptors + * + * Windows tries to fetch some special descriptors with informations + * specifically for windows. Presence is indicated using a special + * string @ index 0xee. There are two kinds of descriptors: + * + * compatid descriptor + * Used to bind drivers, if usb class isn't specific enougth. + * Used for PTP/MTP for example (both share the same usb class). + * + * properties descriptor + * Does carry registry entries. They show up in + * HLM\SYSTEM\CurrentControlSet\Enum\USB\<devid>\<serial>\Device Parameters + * + * Note that Windows caches the stuff it got in the registry, so when + * playing with this you have to delete registry subtrees to make + * windows query the device again: + * HLM\SYSTEM\CurrentControlSet\Control\usbflags + * HLM\SYSTEM\CurrentControlSet\Enum\USB + * Windows will complain it can't delete entries on the second one. + * It has deleted everything it had permissions too, which is enouth + * as this includes "Device Parameters". + * + * http://msdn.microsoft.com/en-us/library/windows/hardware/ff537430.aspx + * + */ + +/* ------------------------------------------------------------------ */ + +typedef struct msos_compat_hdr { + uint32_t dwLength; + uint8_t bcdVersion_lo; + uint8_t bcdVersion_hi; + uint8_t wIndex_lo; + uint8_t wIndex_hi; + uint8_t bCount; + uint8_t reserved[7]; +} QEMU_PACKED msos_compat_hdr; + +typedef struct msos_compat_func { + uint8_t bFirstInterfaceNumber; + uint8_t reserved_1; + uint8_t compatibleId[8]; + uint8_t subCompatibleId[8]; + uint8_t reserved_2[6]; +} QEMU_PACKED msos_compat_func; + +static int usb_desc_msos_compat(const USBDesc *desc, uint8_t *dest) +{ + msos_compat_hdr *hdr = (void *)dest; + msos_compat_func *func; + int length = sizeof(*hdr); + int count = 0; + + func = (void *)(dest + length); + func->bFirstInterfaceNumber = 0; + func->reserved_1 = 0x01; + length += sizeof(*func); + count++; + + hdr->dwLength = cpu_to_le32(length); + hdr->bcdVersion_lo = 0x00; + hdr->bcdVersion_hi = 0x01; + hdr->wIndex_lo = 0x04; + hdr->wIndex_hi = 0x00; + hdr->bCount = count; + return length; +} + +/* ------------------------------------------------------------------ */ + +typedef struct msos_prop_hdr { + uint32_t dwLength; + uint8_t bcdVersion_lo; + uint8_t bcdVersion_hi; + uint8_t wIndex_lo; + uint8_t wIndex_hi; + uint8_t wCount_lo; + uint8_t wCount_hi; +} QEMU_PACKED msos_prop_hdr; + +typedef struct msos_prop { + uint32_t dwLength; + uint32_t dwPropertyDataType; + uint8_t dwPropertyNameLength_lo; + uint8_t dwPropertyNameLength_hi; + uint8_t bPropertyName[]; +} QEMU_PACKED msos_prop; + +typedef struct msos_prop_data { + uint32_t dwPropertyDataLength; + uint8_t bPropertyData[]; +} QEMU_PACKED msos_prop_data; + +typedef enum msos_prop_type { + MSOS_REG_SZ = 1, + MSOS_REG_EXPAND_SZ = 2, + MSOS_REG_BINARY = 3, + MSOS_REG_DWORD_LE = 4, + MSOS_REG_DWORD_BE = 5, + MSOS_REG_LINK = 6, + MSOS_REG_MULTI_SZ = 7, +} msos_prop_type; + +static int usb_desc_msos_prop_name(struct msos_prop *prop, + const wchar_t *name) +{ + int length = wcslen(name) + 1; + int i; + + prop->dwPropertyNameLength_lo = usb_lo(length*2); + prop->dwPropertyNameLength_hi = usb_hi(length*2); + for (i = 0; i < length; i++) { + prop->bPropertyName[i*2] = usb_lo(name[i]); + prop->bPropertyName[i*2+1] = usb_hi(name[i]); + } + return length*2; +} + +static int usb_desc_msos_prop_str(uint8_t *dest, msos_prop_type type, + const wchar_t *name, const wchar_t *value) +{ + struct msos_prop *prop = (void *)dest; + struct msos_prop_data *data; + int length = sizeof(*prop); + int i, vlen = wcslen(value) + 1; + + prop->dwPropertyDataType = cpu_to_le32(type); + length += usb_desc_msos_prop_name(prop, name); + data = (void *)(dest + length); + + data->dwPropertyDataLength = cpu_to_le32(vlen*2); + length += sizeof(*prop); + + for (i = 0; i < vlen; i++) { + data->bPropertyData[i*2] = usb_lo(value[i]); + data->bPropertyData[i*2+1] = usb_hi(value[i]); + } + length += vlen*2; + + prop->dwLength = cpu_to_le32(length); + return length; +} + +static int usb_desc_msos_prop_dword(uint8_t *dest, const wchar_t *name, + uint32_t value) +{ + struct msos_prop *prop = (void *)dest; + struct msos_prop_data *data; + int length = sizeof(*prop); + + prop->dwPropertyDataType = cpu_to_le32(MSOS_REG_DWORD_LE); + length += usb_desc_msos_prop_name(prop, name); + data = (void *)(dest + length); + + data->dwPropertyDataLength = cpu_to_le32(4); + data->bPropertyData[0] = (value) & 0xff; + data->bPropertyData[1] = (value >> 8) & 0xff; + data->bPropertyData[2] = (value >> 16) & 0xff; + data->bPropertyData[3] = (value >> 24) & 0xff; + length += sizeof(*prop) + 4; + + prop->dwLength = cpu_to_le32(length); + return length; +} + +static int usb_desc_msos_prop(const USBDesc *desc, uint8_t *dest) +{ + msos_prop_hdr *hdr = (void *)dest; + int length = sizeof(*hdr); + int count = 0; + + if (desc->msos->Label) { + /* + * Given as example in the specs. Havn't figured yet where + * this label shows up in the windows gui. + */ + length += usb_desc_msos_prop_str(dest+length, MSOS_REG_SZ, + L"Label", desc->msos->Label); + count++; + } + + if (desc->msos->SelectiveSuspendEnabled) { + /* + * Signaling remote wakeup capability in the standard usb + * descriptors isn't enouth to make windows actually use it. + * This is the "Yes, we really mean it" registy entry to flip + * the switch in the windows drivers. + */ + length += usb_desc_msos_prop_dword(dest+length, + L"SelectiveSuspendEnabled", 1); + count++; + } + + hdr->dwLength = cpu_to_le32(length); + hdr->bcdVersion_lo = 0x00; + hdr->bcdVersion_hi = 0x01; + hdr->wIndex_lo = 0x05; + hdr->wIndex_hi = 0x00; + hdr->wCount_lo = usb_lo(count); + hdr->wCount_hi = usb_hi(count); + return length; +} + +/* ------------------------------------------------------------------ */ + +int usb_desc_msos(const USBDesc *desc, USBPacket *p, + int index, uint8_t *dest, size_t len) +{ + void *buf = g_malloc0(4096); + int length = 0; + + switch (index) { + case 0x0004: + length = usb_desc_msos_compat(desc, buf); + break; + case 0x0005: + length = usb_desc_msos_prop(desc, buf); + break; + } + + if (length > len) { + length = len; + } + memcpy(dest, buf, length); + free(buf); + + p->actual_length = length; + return 0; +} diff --git a/hw/usb/desc.c b/hw/usb/desc.c index f18a043500..f133ddb9db 100644 --- a/hw/usb/desc.c +++ b/hw/usb/desc.c @@ -7,7 +7,7 @@ /* ------------------------------------------------------------------ */ int usb_desc_device(const USBDescID *id, const USBDescDevice *dev, - uint8_t *dest, size_t len) + bool msos, uint8_t *dest, size_t len) { uint8_t bLength = 0x12; USBDescriptor *d = (void *)dest; @@ -19,8 +19,18 @@ int usb_desc_device(const USBDescID *id, const USBDescDevice *dev, d->bLength = bLength; d->bDescriptorType = USB_DT_DEVICE; - d->u.device.bcdUSB_lo = usb_lo(dev->bcdUSB); - d->u.device.bcdUSB_hi = usb_hi(dev->bcdUSB); + if (msos && dev->bcdUSB < 0x0200) { + /* + * Version 2.0+ required for microsoft os descriptors to work. + * Done this way so msos-desc compat property will handle both + * the version and the new descriptors being present. + */ + d->u.device.bcdUSB_lo = usb_lo(0x0200); + d->u.device.bcdUSB_hi = usb_hi(0x0200); + } else { + d->u.device.bcdUSB_lo = usb_lo(dev->bcdUSB); + d->u.device.bcdUSB_hi = usb_hi(dev->bcdUSB); + } d->u.device.bDeviceClass = dev->bDeviceClass; d->u.device.bDeviceSubClass = dev->bDeviceSubClass; d->u.device.bDeviceProtocol = dev->bDeviceProtocol; @@ -499,6 +509,10 @@ void usb_desc_init(USBDevice *dev) if (desc->super) { dev->speedmask |= USB_SPEED_MASK_SUPER; } + if (desc->msos && (dev->flags & (1 << USB_DEV_FLAG_MSOS_DESC_ENABLE))) { + dev->flags |= (1 << USB_DEV_FLAG_MSOS_DESC_IN_USE); + usb_desc_set_string(dev, 0xee, "MSFT100Q"); + } usb_desc_setdefaults(dev); } @@ -626,6 +640,7 @@ int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len) int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p, int value, uint8_t *dest, size_t len) { + bool msos = (dev->flags & (1 << USB_DEV_FLAG_MSOS_DESC_IN_USE)); const USBDesc *desc = usb_device_get_usb_desc(dev); const USBDescDevice *other_dev; uint8_t buf[256]; @@ -646,7 +661,7 @@ int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p, switch(type) { case USB_DT_DEVICE: - ret = usb_desc_device(&desc->id, dev->device, buf, sizeof(buf)); + ret = usb_desc_device(&desc->id, dev->device, msos, buf, sizeof(buf)); trace_usb_desc_device(dev->addr, len, ret); break; case USB_DT_CONFIG: @@ -703,6 +718,7 @@ int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p, int usb_desc_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { + bool msos = (dev->flags & (1 << USB_DEV_FLAG_MSOS_DESC_IN_USE)); const USBDesc *desc = usb_device_get_usb_desc(dev); int ret = -1; @@ -782,6 +798,19 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p, trace_usb_set_interface(dev->addr, index, value, ret); break; + case VendorDeviceRequest | 'Q': + if (msos) { + ret = usb_desc_msos(desc, p, index, data, length); + trace_usb_desc_msos(dev->addr, index, length, ret); + } + break; + case VendorInterfaceRequest | 'Q': + if (msos) { + ret = usb_desc_msos(desc, p, index, data, length); + trace_usb_desc_msos(dev->addr, index, length, ret); + } + break; + } return ret; } diff --git a/hw/usb/desc.h b/hw/usb/desc.h index 81327b0e74..2b4fcdae76 100644 --- a/hw/usb/desc.h +++ b/hw/usb/desc.h @@ -2,6 +2,7 @@ #define QEMU_HW_USB_DESC_H #include <inttypes.h> +#include <wchar.h> /* binary representation */ typedef struct USBDescriptor { @@ -182,6 +183,11 @@ struct USBDescOther { const uint8_t *data; }; +struct USBDescMSOS { + const wchar_t *Label; + bool SelectiveSuspendEnabled; +}; + typedef const char *USBDescStrings[256]; struct USBDesc { @@ -190,6 +196,7 @@ struct USBDesc { const USBDescDevice *high; const USBDescDevice *super; const char* const *str; + const USBDescMSOS *msos; }; #define USB_DESC_FLAG_SUPER (1 << 1) @@ -207,7 +214,7 @@ static inline uint8_t usb_hi(uint16_t val) /* generate usb packages from structs */ int usb_desc_device(const USBDescID *id, const USBDescDevice *dev, - uint8_t *dest, size_t len); + bool msos, uint8_t *dest, size_t len); int usb_desc_device_qualifier(const USBDescDevice *dev, uint8_t *dest, size_t len); int usb_desc_config(const USBDescConfig *conf, int flags, @@ -219,6 +226,8 @@ int usb_desc_iface(const USBDescIface *iface, int flags, int usb_desc_endpoint(const USBDescEndpoint *ep, int flags, uint8_t *dest, size_t len); int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len); +int usb_desc_msos(const USBDesc *desc, USBPacket *p, + int index, uint8_t *dest, size_t len); /* control message emulation helpers */ void usb_desc_init(USBDevice *dev); diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index 5e667f0199..2966066682 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -261,6 +261,10 @@ static const USBDescDevice desc_device_keyboard = { }, }; +static const USBDescMSOS desc_msos_suspend = { + .SelectiveSuspendEnabled = true, +}; + static const USBDesc desc_mouse = { .id = { .idVendor = 0x0627, @@ -272,6 +276,7 @@ static const USBDesc desc_mouse = { }, .full = &desc_device_mouse, .str = desc_strings, + .msos = &desc_msos_suspend, }; static const USBDesc desc_tablet = { @@ -285,6 +290,7 @@ static const USBDesc desc_tablet = { }, .full = &desc_device_tablet, .str = desc_strings, + .msos = &desc_msos_suspend, }; static const USBDesc desc_tablet2 = { @@ -299,6 +305,7 @@ static const USBDesc desc_tablet2 = { .full = &desc_device_tablet, .high = &desc_device_tablet2, .str = desc_strings, + .msos = &desc_msos_suspend, }; static const USBDesc desc_keyboard = { @@ -312,6 +319,7 @@ static const USBDesc desc_keyboard = { }, .full = &desc_device_keyboard, .str = desc_strings, + .msos = &desc_msos_suspend, }; static const uint8_t qemu_mouse_hid_report_descriptor[] = { diff --git a/hw/virtio/dataplane/vring.c b/hw/virtio/dataplane/vring.c index 250d45ec3d..665a1ffcb3 100644 --- a/hw/virtio/dataplane/vring.c +++ b/hw/virtio/dataplane/vring.c @@ -376,7 +376,7 @@ int vring_pop(VirtIODevice *vdev, Vring *vring, barrier(); if (desc.flags & VRING_DESC_F_INDIRECT) { - int ret = get_indirect(vring, elem, &desc); + ret = get_indirect(vring, elem, &desc); if (ret < 0) { goto out; } |