diff options
author | Gerd Hoffmann <kraxel@redhat.com> | 2012-03-07 14:55:18 +0100 |
---|---|---|
committer | Gerd Hoffmann <kraxel@redhat.com> | 2012-03-13 10:15:32 +0100 |
commit | f1ae32a1ecda8aaff7a355c9030c0d8c363f3a70 (patch) | |
tree | 39edd226fd23a9dfee6d32ee3cf289dfff05132d /hw/usb-msd.c | |
parent | cb72b75824c0362e5cb32eb8796930f29fa36d17 (diff) |
usb: the big rename
Reorganize usb source files. Create a new hw/usb/ directory and move
all usb source code to that place. Also make filenames a bit more
descriptive. Host adapters are prefixed with "hch-" now, usb device
emulations are prefixed with "dev-". Fixup paths Makefile and include
paths to make it compile. No code changes.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Diffstat (limited to 'hw/usb-msd.c')
-rw-r--r-- | hw/usb-msd.c | 677 |
1 files changed, 0 insertions, 677 deletions
diff --git a/hw/usb-msd.c b/hw/usb-msd.c deleted file mode 100644 index c6f08a0313..0000000000 --- a/hw/usb-msd.c +++ /dev/null @@ -1,677 +0,0 @@ -/* - * USB Mass Storage Device emulation - * - * Copyright (c) 2006 CodeSourcery. - * Written by Paul Brook - * - * This code is licensed under the LGPL. - */ - -#include "qemu-common.h" -#include "qemu-option.h" -#include "qemu-config.h" -#include "usb.h" -#include "usb-desc.h" -#include "scsi.h" -#include "console.h" -#include "monitor.h" -#include "sysemu.h" -#include "blockdev.h" - -//#define DEBUG_MSD - -#ifdef DEBUG_MSD -#define DPRINTF(fmt, ...) \ -do { printf("usb-msd: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) do {} while(0) -#endif - -/* USB requests. */ -#define MassStorageReset 0xff -#define GetMaxLun 0xfe - -enum USBMSDMode { - USB_MSDM_CBW, /* Command Block. */ - USB_MSDM_DATAOUT, /* Transfer data to device. */ - USB_MSDM_DATAIN, /* Transfer data from device. */ - USB_MSDM_CSW /* Command Status. */ -}; - -struct usb_msd_csw { - uint32_t sig; - uint32_t tag; - uint32_t residue; - uint8_t status; -}; - -typedef struct { - USBDevice dev; - enum USBMSDMode mode; - uint32_t scsi_len; - uint8_t *scsi_buf; - uint32_t data_len; - uint32_t residue; - struct usb_msd_csw csw; - SCSIRequest *req; - SCSIBus bus; - BlockConf conf; - char *serial; - SCSIDevice *scsi_dev; - uint32_t removable; - /* For async completion. */ - USBPacket *packet; -} MSDState; - -struct usb_msd_cbw { - uint32_t sig; - uint32_t tag; - uint32_t data_len; - uint8_t flags; - uint8_t lun; - uint8_t cmd_len; - uint8_t cmd[16]; -}; - -enum { - STR_MANUFACTURER = 1, - STR_PRODUCT, - STR_SERIALNUMBER, - STR_CONFIG_FULL, - STR_CONFIG_HIGH, -}; - -static const USBDescStrings desc_strings = { - [STR_MANUFACTURER] = "QEMU " QEMU_VERSION, - [STR_PRODUCT] = "QEMU USB HARDDRIVE", - [STR_SERIALNUMBER] = "1", - [STR_CONFIG_FULL] = "Full speed config (usb 1.1)", - [STR_CONFIG_HIGH] = "High speed config (usb 2.0)", -}; - -static const USBDescIface desc_iface_full = { - .bInterfaceNumber = 0, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_MASS_STORAGE, - .bInterfaceSubClass = 0x06, /* SCSI */ - .bInterfaceProtocol = 0x50, /* Bulk */ - .eps = (USBDescEndpoint[]) { - { - .bEndpointAddress = USB_DIR_IN | 0x01, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = 64, - },{ - .bEndpointAddress = USB_DIR_OUT | 0x02, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = 64, - }, - } -}; - -static const USBDescDevice desc_device_full = { - .bcdUSB = 0x0200, - .bMaxPacketSize0 = 8, - .bNumConfigurations = 1, - .confs = (USBDescConfig[]) { - { - .bNumInterfaces = 1, - .bConfigurationValue = 1, - .iConfiguration = STR_CONFIG_FULL, - .bmAttributes = 0xc0, - .nif = 1, - .ifs = &desc_iface_full, - }, - }, -}; - -static const USBDescIface desc_iface_high = { - .bInterfaceNumber = 0, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_MASS_STORAGE, - .bInterfaceSubClass = 0x06, /* SCSI */ - .bInterfaceProtocol = 0x50, /* Bulk */ - .eps = (USBDescEndpoint[]) { - { - .bEndpointAddress = USB_DIR_IN | 0x01, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = 512, - },{ - .bEndpointAddress = USB_DIR_OUT | 0x02, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = 512, - }, - } -}; - -static const USBDescDevice desc_device_high = { - .bcdUSB = 0x0200, - .bMaxPacketSize0 = 64, - .bNumConfigurations = 1, - .confs = (USBDescConfig[]) { - { - .bNumInterfaces = 1, - .bConfigurationValue = 1, - .iConfiguration = STR_CONFIG_HIGH, - .bmAttributes = 0xc0, - .nif = 1, - .ifs = &desc_iface_high, - }, - }, -}; - -static const USBDesc desc = { - .id = { - .idVendor = 0x46f4, /* CRC16() of "QEMU" */ - .idProduct = 0x0001, - .bcdDevice = 0, - .iManufacturer = STR_MANUFACTURER, - .iProduct = STR_PRODUCT, - .iSerialNumber = STR_SERIALNUMBER, - }, - .full = &desc_device_full, - .high = &desc_device_high, - .str = desc_strings, -}; - -static void usb_msd_copy_data(MSDState *s, USBPacket *p) -{ - uint32_t len; - len = p->iov.size - p->result; - if (len > s->scsi_len) - len = s->scsi_len; - usb_packet_copy(p, s->scsi_buf, len); - s->scsi_len -= len; - s->scsi_buf += len; - s->data_len -= len; - if (s->scsi_len == 0 || s->data_len == 0) { - scsi_req_continue(s->req); - } -} - -static void usb_msd_send_status(MSDState *s, USBPacket *p) -{ - int len; - - DPRINTF("Command status %d tag 0x%x, len %zd\n", - s->csw.status, s->csw.tag, p->iov.size); - - assert(s->csw.sig == 0x53425355); - len = MIN(sizeof(s->csw), p->iov.size); - usb_packet_copy(p, &s->csw, len); - memset(&s->csw, 0, sizeof(s->csw)); -} - -static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len) -{ - MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent); - USBPacket *p = s->packet; - - assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV)); - s->scsi_len = len; - s->scsi_buf = scsi_req_get_buf(req); - if (p) { - usb_msd_copy_data(s, p); - p = s->packet; - if (p && p->result == p->iov.size) { - /* Set s->packet to NULL before calling usb_packet_complete - because another request may be issued before - usb_packet_complete returns. */ - DPRINTF("Packet complete %p\n", p); - s->packet = NULL; - usb_packet_complete(&s->dev, p); - } - } -} - -static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, size_t resid) -{ - MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent); - USBPacket *p = s->packet; - - DPRINTF("Command complete %d tag 0x%x\n", status, req->tag); - s->residue = s->data_len; - - s->csw.sig = cpu_to_le32(0x53425355); - s->csw.tag = cpu_to_le32(req->tag); - s->csw.residue = s->residue; - s->csw.status = status != 0; - - if (s->packet) { - if (s->data_len == 0 && s->mode == USB_MSDM_DATAOUT) { - /* A deferred packet with no write data remaining must be - the status read packet. */ - usb_msd_send_status(s, p); - s->mode = USB_MSDM_CBW; - } else { - if (s->data_len) { - int len = (p->iov.size - p->result); - usb_packet_skip(p, len); - s->data_len -= len; - } - if (s->data_len == 0) { - s->mode = USB_MSDM_CSW; - } - } - s->packet = NULL; - usb_packet_complete(&s->dev, p); - } else if (s->data_len == 0) { - s->mode = USB_MSDM_CSW; - } - scsi_req_unref(req); - s->req = NULL; -} - -static void usb_msd_request_cancelled(SCSIRequest *req) -{ - MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent); - - if (req == s->req) { - scsi_req_unref(s->req); - s->req = NULL; - s->packet = NULL; - s->scsi_len = 0; - } -} - -static void usb_msd_handle_reset(USBDevice *dev) -{ - MSDState *s = (MSDState *)dev; - - DPRINTF("Reset\n"); - if (s->req) { - scsi_req_cancel(s->req); - } - assert(s->req == NULL); - - if (s->packet) { - USBPacket *p = s->packet; - s->packet = NULL; - p->result = USB_RET_STALL; - usb_packet_complete(dev, p); - } - - s->mode = USB_MSDM_CBW; -} - -static int usb_msd_handle_control(USBDevice *dev, USBPacket *p, - int request, int value, int index, int length, uint8_t *data) -{ - MSDState *s = (MSDState *)dev; - int ret; - - ret = usb_desc_handle_control(dev, p, request, value, index, length, data); - if (ret >= 0) { - return ret; - } - - ret = 0; - switch (request) { - case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: - ret = 0; - break; - /* Class specific requests. */ - case ClassInterfaceOutRequest | MassStorageReset: - /* Reset state ready for the next CBW. */ - s->mode = USB_MSDM_CBW; - ret = 0; - break; - case ClassInterfaceRequest | GetMaxLun: - data[0] = 0; - ret = 1; - break; - default: - ret = USB_RET_STALL; - break; - } - return ret; -} - -static void usb_msd_cancel_io(USBDevice *dev, USBPacket *p) -{ - MSDState *s = DO_UPCAST(MSDState, dev, dev); - - if (s->req) { - scsi_req_cancel(s->req); - } -} - -static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) -{ - MSDState *s = (MSDState *)dev; - uint32_t tag; - int ret = 0; - struct usb_msd_cbw cbw; - uint8_t devep = p->ep->nr; - - switch (p->pid) { - case USB_TOKEN_OUT: - if (devep != 2) - goto fail; - - switch (s->mode) { - case USB_MSDM_CBW: - if (p->iov.size != 31) { - fprintf(stderr, "usb-msd: Bad CBW size"); - goto fail; - } - usb_packet_copy(p, &cbw, 31); - if (le32_to_cpu(cbw.sig) != 0x43425355) { - fprintf(stderr, "usb-msd: Bad signature %08x\n", - le32_to_cpu(cbw.sig)); - goto fail; - } - DPRINTF("Command on LUN %d\n", cbw.lun); - if (cbw.lun != 0) { - fprintf(stderr, "usb-msd: Bad LUN %d\n", cbw.lun); - goto fail; - } - tag = le32_to_cpu(cbw.tag); - s->data_len = le32_to_cpu(cbw.data_len); - if (s->data_len == 0) { - s->mode = USB_MSDM_CSW; - } else if (cbw.flags & 0x80) { - s->mode = USB_MSDM_DATAIN; - } else { - s->mode = USB_MSDM_DATAOUT; - } - DPRINTF("Command tag 0x%x flags %08x len %d data %d\n", - tag, cbw.flags, cbw.cmd_len, s->data_len); - s->residue = 0; - s->scsi_len = 0; - s->req = scsi_req_new(s->scsi_dev, tag, 0, cbw.cmd, NULL); - scsi_req_enqueue(s->req); - if (s->req && s->req->cmd.xfer != SCSI_XFER_NONE) { - scsi_req_continue(s->req); - } - ret = p->result; - break; - - case USB_MSDM_DATAOUT: - DPRINTF("Data out %zd/%d\n", p->iov.size, s->data_len); - if (p->iov.size > s->data_len) { - goto fail; - } - - if (s->scsi_len) { - usb_msd_copy_data(s, p); - } - if (s->residue) { - int len = p->iov.size - p->result; - if (len) { - usb_packet_skip(p, len); - s->data_len -= len; - if (s->data_len == 0) { - s->mode = USB_MSDM_CSW; - } - } - } - if (p->result < p->iov.size) { - DPRINTF("Deferring packet %p\n", p); - s->packet = p; - ret = USB_RET_ASYNC; - } else { - ret = p->result; - } - break; - - default: - DPRINTF("Unexpected write (len %zd)\n", p->iov.size); - goto fail; - } - break; - - case USB_TOKEN_IN: - if (devep != 1) - goto fail; - - switch (s->mode) { - case USB_MSDM_DATAOUT: - if (s->data_len != 0 || p->iov.size < 13) { - goto fail; - } - /* Waiting for SCSI write to complete. */ - s->packet = p; - ret = USB_RET_ASYNC; - break; - - case USB_MSDM_CSW: - if (p->iov.size < 13) { - goto fail; - } - - if (s->req) { - /* still in flight */ - s->packet = p; - ret = USB_RET_ASYNC; - } else { - usb_msd_send_status(s, p); - s->mode = USB_MSDM_CBW; - ret = 13; - } - break; - - case USB_MSDM_DATAIN: - DPRINTF("Data in %zd/%d, scsi_len %d\n", - p->iov.size, s->data_len, s->scsi_len); - if (s->scsi_len) { - usb_msd_copy_data(s, p); - } - if (s->residue) { - int len = p->iov.size - p->result; - if (len) { - usb_packet_skip(p, len); - s->data_len -= len; - if (s->data_len == 0) { - s->mode = USB_MSDM_CSW; - } - } - } - if (p->result < p->iov.size) { - DPRINTF("Deferring packet %p\n", p); - s->packet = p; - ret = USB_RET_ASYNC; - } else { - ret = p->result; - } - break; - - default: - DPRINTF("Unexpected read (len %zd)\n", p->iov.size); - goto fail; - } - break; - - default: - DPRINTF("Bad token\n"); - fail: - ret = USB_RET_STALL; - break; - } - - return ret; -} - -static void usb_msd_password_cb(void *opaque, int err) -{ - MSDState *s = opaque; - - if (!err) - err = usb_device_attach(&s->dev); - - if (err) - qdev_unplug(&s->dev.qdev); -} - -static const struct SCSIBusInfo usb_msd_scsi_info = { - .tcq = false, - .max_target = 0, - .max_lun = 0, - - .transfer_data = usb_msd_transfer_data, - .complete = usb_msd_command_complete, - .cancel = usb_msd_request_cancelled -}; - -static int usb_msd_initfn(USBDevice *dev) -{ - MSDState *s = DO_UPCAST(MSDState, dev, dev); - BlockDriverState *bs = s->conf.bs; - DriveInfo *dinfo; - - if (!bs) { - error_report("drive property not set"); - return -1; - } - - /* - * Hack alert: this pretends to be a block device, but it's really - * a SCSI bus that can serve only a single device, which it - * creates automatically. But first it needs to detach from its - * blockdev, or else scsi_bus_legacy_add_drive() dies when it - * attaches again. - * - * The hack is probably a bad idea. - */ - bdrv_detach_dev(bs, &s->dev.qdev); - s->conf.bs = NULL; - - if (!s->serial) { - /* try to fall back to value set with legacy -drive serial=... */ - dinfo = drive_get_by_blockdev(bs); - if (*dinfo->serial) { - s->serial = strdup(dinfo->serial); - } - } - if (s->serial) { - usb_desc_set_string(dev, STR_SERIALNUMBER, s->serial); - } - - usb_desc_init(dev); - scsi_bus_new(&s->bus, &s->dev.qdev, &usb_msd_scsi_info); - s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable, - s->conf.bootindex); - if (!s->scsi_dev) { - return -1; - } - s->bus.qbus.allow_hotplug = 0; - usb_msd_handle_reset(dev); - - if (bdrv_key_required(bs)) { - if (cur_mon) { - monitor_read_bdrv_key_start(cur_mon, bs, usb_msd_password_cb, s); - s->dev.auto_attach = 0; - } else { - autostart = 0; - } - } - - return 0; -} - -static USBDevice *usb_msd_init(USBBus *bus, const char *filename) -{ - static int nr=0; - char id[8]; - QemuOpts *opts; - DriveInfo *dinfo; - USBDevice *dev; - 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_find_opts("drive"), 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"); - - /* create host drive */ - dinfo = drive_init(opts, 0); - if (!dinfo) { - qemu_opts_del(opts); - return NULL; - } - - /* create guest device */ - dev = usb_create(bus, "usb-storage"); - if (!dev) { - return NULL; - } - if (qdev_prop_set_drive(&dev->qdev, "drive", dinfo->bdrv) < 0) { - qdev_free(&dev->qdev); - return NULL; - } - if (qdev_init(&dev->qdev) < 0) - return NULL; - - return dev; -} - -static const VMStateDescription vmstate_usb_msd = { - .name = "usb-storage", - .unmigratable = 1, /* FIXME: handle transactions which are in flight */ - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField []) { - VMSTATE_USB_DEVICE(dev, MSDState), - VMSTATE_END_OF_LIST() - } -}; - -static Property msd_properties[] = { - DEFINE_BLOCK_PROPERTIES(MSDState, conf), - DEFINE_PROP_STRING("serial", MSDState, serial), - DEFINE_PROP_BIT("removable", MSDState, removable, 0, false), - DEFINE_PROP_END_OF_LIST(), -}; - -static void usb_msd_class_initfn(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - USBDeviceClass *uc = USB_DEVICE_CLASS(klass); - - uc->init = usb_msd_initfn; - uc->product_desc = "QEMU USB MSD"; - uc->usb_desc = &desc; - uc->cancel_packet = usb_msd_cancel_io; - uc->handle_attach = usb_desc_attach; - uc->handle_reset = usb_msd_handle_reset; - uc->handle_control = usb_msd_handle_control; - uc->handle_data = usb_msd_handle_data; - dc->fw_name = "storage"; - dc->vmsd = &vmstate_usb_msd; - dc->props = msd_properties; -} - -static TypeInfo msd_info = { - .name = "usb-storage", - .parent = TYPE_USB_DEVICE, - .instance_size = sizeof(MSDState), - .class_init = usb_msd_class_initfn, -}; - -static void usb_msd_register_types(void) -{ - type_register_static(&msd_info); - usb_legacy_register("usb-storage", "disk", usb_msd_init); -} - -type_init(usb_msd_register_types) |