X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=hw%2Fusb-msd.c;h=1fb62ad13c46f7d9cc4c704529df3ee6b13f2ec3;hb=556cd09885bec3f69ba78228fe4e46dc1dad145b;hp=4530a1ceaaf8e236ac03d44a9bc350a6fa57309a;hpb=a917d384ac0d09cd68266a6f2ca5c94212c8f81e;p=qemu.git diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 4530a1cea..1fb62ad13 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -1,4 +1,4 @@ -/* +/* * USB Mass Storage Device emulation * * Copyright (c) 2006 CodeSourcery. @@ -7,15 +7,22 @@ * This code is licenced under the LGPL. */ -#include "vl.h" +#include "qemu-common.h" +#include "qemu-option.h" +#include "qemu-config.h" +#include "usb.h" +#include "block.h" +#include "scsi.h" +#include "console.h" +#include "monitor.h" //#define DEBUG_MSD #ifdef DEBUG_MSD -#define DPRINTF(fmt, args...) \ -do { printf("usb-msd: " fmt , ##args); } while (0) +#define DPRINTF(fmt, ...) \ +do { printf("usb-msd: " fmt , ## __VA_ARGS__); } while (0) #else -#define DPRINTF(fmt, args...) do {} while(0) +#define DPRINTF(fmt, ...) do {} while(0) #endif /* USB requests. */ @@ -39,7 +46,8 @@ typedef struct { uint32_t data_len; uint32_t residue; uint32_t tag; - BlockDriverState *bs; + SCSIBus bus; + DriveInfo *dinfo; SCSIDevice *scsi_dev; int result; /* For async completion. */ @@ -66,7 +74,7 @@ struct usb_msd_csw { static const uint8_t qemu_msd_dev_descriptor[] = { 0x12, /* u8 bLength; */ 0x01, /* u8 bDescriptorType; Device */ - 0x10, 0x00, /* u16 bcdUSB; v1.0 */ + 0x00, 0x01, /* u16 bcdUSB; v1.0 */ 0x00, /* u8 bDeviceClass; */ 0x00, /* u8 bDeviceSubClass; */ @@ -93,13 +101,13 @@ static const uint8_t qemu_msd_config_descriptor[] = { 0x01, /* u8 bNumInterfaces; (1) */ 0x01, /* u8 bConfigurationValue; */ 0x00, /* u8 iConfiguration; */ - 0xc0, /* u8 bmAttributes; + 0xc0, /* u8 bmAttributes; Bit 7: must be set, 6: Self-powered, 5: Remote wakeup, 4..0: resvd */ 0x00, /* u8 MaxPower; */ - + /* one interface */ 0x09, /* u8 if_bLength; */ 0x04, /* u8 if_bDescriptorType; Interface */ @@ -110,7 +118,7 @@ static const uint8_t qemu_msd_config_descriptor[] = { 0x06, /* u8 if_bInterfaceSubClass; SCSI */ 0x50, /* u8 if_bInterfaceProtocol; Bulk Only */ 0x00, /* u8 if_iInterface; */ - + /* Bulk-In endpoint */ 0x07, /* u8 ep_bLength; */ 0x05, /* u8 ep_bDescriptorType; Endpoint */ @@ -146,9 +154,9 @@ static void usb_msd_copy_data(MSDState *s) s->data_len -= len; if (s->scsi_len == 0) { if (s->mode == USB_MSDM_DATAIN) { - scsi_read_data(s->scsi_dev, s->tag); + s->scsi_dev->info->read_data(s->scsi_dev, s->tag); } else if (s->mode == USB_MSDM_DATAOUT) { - scsi_write_data(s->scsi_dev, s->tag); + s->scsi_dev->info->write_data(s->scsi_dev, s->tag); } } } @@ -164,10 +172,10 @@ static void usb_msd_send_status(MSDState *s) memcpy(s->usb_buf, &csw, 13); } -static void usb_msd_command_complete(void *opaque, int reason, uint32_t tag, +static void usb_msd_command_complete(SCSIBus *bus, int reason, uint32_t tag, uint32_t arg) { - MSDState *s = (MSDState *)opaque; + MSDState *s = DO_UPCAST(MSDState, dev.qdev, bus->qbus.parent); USBPacket *p = s->packet; if (tag != s->tag) { @@ -201,7 +209,7 @@ static void usb_msd_command_complete(void *opaque, int reason, uint32_t tag, return; } s->scsi_len = arg; - s->scsi_buf = scsi_get_buf(s->scsi_dev, tag); + s->scsi_buf = s->scsi_dev->info->get_buf(s->scsi_dev, tag); if (p) { usb_msd_copy_data(s); if (s->usb_len == 0) { @@ -259,12 +267,12 @@ static int usb_msd_handle_control(USBDevice *dev, int request, int value, case DeviceRequest | USB_REQ_GET_DESCRIPTOR: switch(value >> 8) { case USB_DT_DEVICE: - memcpy(data, qemu_msd_dev_descriptor, + memcpy(data, qemu_msd_dev_descriptor, sizeof(qemu_msd_dev_descriptor)); ret = sizeof(qemu_msd_dev_descriptor); break; case USB_DT_CONFIG: - memcpy(data, qemu_msd_config_descriptor, + memcpy(data, qemu_msd_config_descriptor, sizeof(qemu_msd_config_descriptor)); ret = sizeof(qemu_msd_config_descriptor); break; @@ -339,7 +347,7 @@ static int usb_msd_handle_control(USBDevice *dev, int request, int value, static void usb_msd_cancel_io(USBPacket *p, void *opaque) { MSDState *s = opaque; - scsi_cancel_io(s->scsi_dev, s->tag); + s->scsi_dev->info->cancel_io(s->scsi_dev, s->tag); s->packet = NULL; s->scsi_len = 0; } @@ -387,14 +395,14 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) DPRINTF("Command tag 0x%x flags %08x len %d data %d\n", s->tag, cbw.flags, cbw.cmd_len, s->data_len); s->residue = 0; - scsi_send_command(s->scsi_dev, s->tag, cbw.cmd, 0); + s->scsi_dev->info->send_command(s->scsi_dev, s->tag, cbw.cmd, 0); /* ??? Should check that USB and SCSI data transfer directions match. */ if (s->residue == 0) { if (s->mode == USB_MSDM_DATAIN) { - scsi_read_data(s->scsi_dev, s->tag); + s->scsi_dev->info->read_data(s->scsi_dev, s->tag); } else if (s->mode == USB_MSDM_DATAOUT) { - scsi_write_data(s->scsi_dev, s->tag); + s->scsi_dev->info->write_data(s->scsi_dev, s->tag); } } ret = len; @@ -501,44 +509,115 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) return ret; } -static void usb_msd_handle_destroy(USBDevice *dev) +static void usb_msd_password_cb(void *opaque, int err) { - MSDState *s = (MSDState *)dev; + MSDState *s = opaque; - scsi_disk_destroy(s->scsi_dev); - bdrv_delete(s->bs); - qemu_free(s); + if (!err) + usb_device_attach(&s->dev); + else + qdev_unplug(&s->dev.qdev); } -USBDevice *usb_msd_init(const char *filename) +static int usb_msd_initfn(USBDevice *dev) { - MSDState *s; - BlockDriverState *bdrv; + MSDState *s = DO_UPCAST(MSDState, dev, dev); + + if (!s->dinfo || !s->dinfo->bdrv) { + qemu_error("usb-msd: drive property not set\n"); + return -1; + } + + s->dev.speed = USB_SPEED_FULL; + scsi_bus_new(&s->bus, &s->dev.qdev, 0, 1, usb_msd_command_complete); + s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, s->dinfo, 0); + s->bus.qbus.allow_hotplug = 0; + usb_msd_handle_reset(dev); + + if (bdrv_key_required(s->dinfo->bdrv)) { + if (s->dev.qdev.hotplugged) { + monitor_read_bdrv_key_start(cur_mon, s->dinfo->bdrv, + usb_msd_password_cb, s); + s->dev.auto_attach = 0; + } else { + autostart = 0; + } + } - s = qemu_mallocz(sizeof(MSDState)); - if (!s) + return 0; +} + +static USBDevice *usb_msd_init(const char *filename) +{ + static int nr=0; + char id[8]; + QemuOpts *opts; + DriveInfo *dinfo; + USBDevice *dev; + int fatal_error; + const char *p1; + char fmt[32]; + + /* parse -usbdevice disk: syntax into drive opts */ + snprintf(id, sizeof(id), "usb%d", nr++); + opts = qemu_opts_create(&qemu_drive_opts, id, 0); + + p1 = strchr(filename, ':'); + if (p1++) { + const char *p2; + + if (strstart(filename, "format=", &p2)) { + int len = MIN(p1 - p2, sizeof(fmt)); + pstrcpy(fmt, len, p2); + qemu_opt_set(opts, "format", fmt); + } else if (*filename != ':') { + printf("unrecognized USB mass-storage option %s\n", filename); + return NULL; + } + filename = p1; + } + if (!*filename) { + printf("block device specification needed\n"); return NULL; + } + qemu_opt_set(opts, "file", filename); + qemu_opt_set(opts, "if", "none"); - bdrv = bdrv_new("usb"); - if (bdrv_open(bdrv, filename, 0) < 0) - goto fail; - s->bs = bdrv; + /* create host drive */ + dinfo = drive_init(opts, NULL, &fatal_error); + if (!dinfo) { + qemu_opts_del(opts); + return NULL; + } - s->dev.speed = USB_SPEED_FULL; - s->dev.handle_packet = usb_generic_handle_packet; - - s->dev.handle_reset = usb_msd_handle_reset; - s->dev.handle_control = usb_msd_handle_control; - s->dev.handle_data = usb_msd_handle_data; - s->dev.handle_destroy = usb_msd_handle_destroy; - - snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB MSD(%.16s)", - filename); - - s->scsi_dev = scsi_disk_init(bdrv, 0, usb_msd_command_complete, s); - usb_msd_handle_reset((USBDevice *)s); - return (USBDevice *)s; - fail: - qemu_free(s); - return NULL; + /* create guest device */ + dev = usb_create(NULL /* FIXME */, "usb-storage"); + qdev_prop_set_drive(&dev->qdev, "drive", dinfo); + if (qdev_init(&dev->qdev) < 0) + return NULL; + + return dev; +} + +static struct USBDeviceInfo msd_info = { + .product_desc = "QEMU USB MSD", + .qdev.name = "usb-storage", + .qdev.size = sizeof(MSDState), + .init = usb_msd_initfn, + .handle_packet = usb_generic_handle_packet, + .handle_reset = usb_msd_handle_reset, + .handle_control = usb_msd_handle_control, + .handle_data = usb_msd_handle_data, + .usbdevice_name = "disk", + .usbdevice_init = usb_msd_init, + .qdev.props = (Property[]) { + DEFINE_PROP_DRIVE("drive", MSDState, dinfo), + DEFINE_PROP_END_OF_LIST(), + }, +}; + +static void usb_msd_register_devices(void) +{ + usb_qdev_register(&msd_info); } +device_init(usb_msd_register_devices)