]> git.proxmox.com Git - qemu.git/blobdiff - hw/usb-serial.c
char: rename qemu_chr_write() -> qemu_chr_fe_write()
[qemu.git] / hw / usb-serial.c
index 5b2483ab441c79c185e1fb0d5cbdbe307781ff67..8ed0fa6a3b40f3fe11b9c0fc914107e302be8156 100644 (file)
@@ -5,12 +5,13 @@
  * Copyright (c) 2008 Samuel Thibault <samuel.thibault@ens-lyon.org>
  * Written by Paul Brook, reused for FTDI by Samuel Thibault
  *
- * This code is licenced under the LGPL.
+ * This code is licensed under the LGPL.
  */
 
 #include "qemu-common.h"
 #include "qemu-error.h"
 #include "usb.h"
+#include "usb-desc.h"
 #include "qemu-char.h"
 
 //#define DEBUG_Serial
@@ -91,8 +92,6 @@ do { printf("usb-serial: " fmt , ## __VA_ARGS__); } while (0)
 
 typedef struct {
     USBDevice dev;
-    uint32_t vendorid;
-    uint32_t productid;
     uint8_t recv_buf[RECV_BUF];
     uint16_t recv_ptr;
     uint16_t recv_used;
@@ -104,69 +103,79 @@ typedef struct {
     CharDriverState *cs;
 } USBSerialState;
 
-static const uint8_t qemu_serial_dev_descriptor[] = {
-        0x12,       /*  u8 bLength; */
-        0x01,       /*  u8 bDescriptorType; Device */
-        0x00, 0x02, /*  u16 bcdUSB; v2.0 */
-
-        0x00,       /*  u8  bDeviceClass; */
-        0x00,       /*  u8  bDeviceSubClass; */
-        0x00,       /*  u8  bDeviceProtocol; [ low/full speeds only ] */
-        0x08,       /*  u8  bMaxPacketSize0; 8 Bytes */
-
-        /* Vendor and product id are arbitrary.  */
-        0x03, 0x04, /*  u16 idVendor; */
-        0x00, 0xFF, /*  u16 idProduct; */
-        0x00, 0x04, /*  u16 bcdDevice */
-
-        0x01,       /*  u8  iManufacturer; */
-        0x02,       /*  u8  iProduct; */
-        0x03,       /*  u8  iSerialNumber; */
-        0x01        /*  u8  bNumConfigurations; */
+enum {
+    STR_MANUFACTURER = 1,
+    STR_PRODUCT_SERIAL,
+    STR_PRODUCT_BRAILLE,
+    STR_SERIALNUMBER,
 };
 
-static const uint8_t qemu_serial_config_descriptor[] = {
-
-        /* one configuration */
-        0x09,       /*  u8  bLength; */
-        0x02,       /*  u8  bDescriptorType; Configuration */
-        0x20, 0x00, /*  u16 wTotalLength; */
-        0x01,       /*  u8  bNumInterfaces; (1) */
-        0x01,       /*  u8  bConfigurationValue; */
-        0x00,       /*  u8  iConfiguration; */
-        0x80,       /*  u8  bmAttributes;
-                                 Bit 7: must be set,
-                                     6: Self-powered,
-                                     5: Remote wakeup,
-                                     4..0: resvd */
-        100/2,       /*  u8  MaxPower; */
-
-        /* one interface */
-        0x09,       /*  u8  if_bLength; */
-        0x04,       /*  u8  if_bDescriptorType; Interface */
-        0x00,       /*  u8  if_bInterfaceNumber; */
-        0x00,       /*  u8  if_bAlternateSetting; */
-        0x02,       /*  u8  if_bNumEndpoints; */
-        0xff,       /*  u8  if_bInterfaceClass; Vendor Specific */
-        0xff,       /*  u8  if_bInterfaceSubClass; Vendor Specific */
-        0xff,       /*  u8  if_bInterfaceProtocol; Vendor Specific */
-        0x02,       /*  u8  if_iInterface; */
-
-        /* Bulk-In endpoint */
-        0x07,       /*  u8  ep_bLength; */
-        0x05,       /*  u8  ep_bDescriptorType; Endpoint */
-        0x81,       /*  u8  ep_bEndpointAddress; IN Endpoint 1 */
-        0x02,       /*  u8  ep_bmAttributes; Bulk */
-        0x40, 0x00, /*  u16 ep_wMaxPacketSize; */
-        0x00,       /*  u8  ep_bInterval; */
-
-        /* Bulk-Out endpoint */
-        0x07,       /*  u8  ep_bLength; */
-        0x05,       /*  u8  ep_bDescriptorType; Endpoint */
-        0x02,       /*  u8  ep_bEndpointAddress; OUT Endpoint 2 */
-        0x02,       /*  u8  ep_bmAttributes; Bulk */
-        0x40, 0x00, /*  u16 ep_wMaxPacketSize; */
-        0x00        /*  u8  ep_bInterval; */
+static const USBDescStrings desc_strings = {
+    [STR_MANUFACTURER]    = "QEMU " QEMU_VERSION,
+    [STR_PRODUCT_SERIAL]  = "QEMU USB SERIAL",
+    [STR_PRODUCT_BRAILLE] = "QEMU USB BRAILLE",
+    [STR_SERIALNUMBER]    = "1",
+};
+
+static const USBDescIface desc_iface0 = {
+    .bInterfaceNumber              = 0,
+    .bNumEndpoints                 = 2,
+    .bInterfaceClass               = 0xff,
+    .bInterfaceSubClass            = 0xff,
+    .bInterfaceProtocol            = 0xff,
+    .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 = {
+    .bcdUSB                        = 0x0200,
+    .bMaxPacketSize0               = 8,
+    .bNumConfigurations            = 1,
+    .confs = (USBDescConfig[]) {
+        {
+            .bNumInterfaces        = 1,
+            .bConfigurationValue   = 1,
+            .bmAttributes          = 0x80,
+            .bMaxPower             = 50,
+            .nif = 1,
+            .ifs = &desc_iface0,
+        },
+    },
+};
+
+static const USBDesc desc_serial = {
+    .id = {
+        .idVendor          = 0x0403,
+        .idProduct         = 0x6001,
+        .bcdDevice         = 0x0400,
+        .iManufacturer     = STR_MANUFACTURER,
+        .iProduct          = STR_PRODUCT_SERIAL,
+        .iSerialNumber     = STR_SERIALNUMBER,
+    },
+    .full = &desc_device,
+    .str  = desc_strings,
+};
+
+static const USBDesc desc_braille = {
+    .id = {
+        .idVendor          = 0x0403,
+        .idProduct         = 0xfe72,
+        .bcdDevice         = 0x0400,
+        .iManufacturer     = STR_MANUFACTURER,
+        .iProduct          = STR_PRODUCT_BRAILLE,
+        .iSerialNumber     = STR_SERIALNUMBER,
+    },
+    .full = &desc_device,
+    .str  = desc_strings,
 };
 
 static void usb_serial_reset(USBSerialState *s)
@@ -210,93 +219,20 @@ static uint8_t usb_get_modem_lines(USBSerialState *s)
     return ret;
 }
 
-static int usb_serial_handle_control(USBDevice *dev, int request, int value,
-                                  int index, int length, uint8_t *data)
+static int usb_serial_handle_control(USBDevice *dev, USBPacket *p,
+               int request, int value, int index, int length, uint8_t *data)
 {
     USBSerialState *s = (USBSerialState *)dev;
-    int ret = 0;
+    int ret;
+
+    DPRINTF("got control %x, value %x\n",request, value);
+    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
+    if (ret >= 0) {
+        return ret;
+    }
 
-    //DPRINTF("got control %x, value %x\n",request, value);
+    ret = 0;
     switch (request) {
-    case DeviceRequest | USB_REQ_GET_STATUS:
-        data[0] = (0 << USB_DEVICE_SELF_POWERED) |
-            (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
-        data[1] = 0x00;
-        ret = 2;
-        break;
-    case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
-        if (value == USB_DEVICE_REMOTE_WAKEUP) {
-            dev->remote_wakeup = 0;
-        } else {
-            goto fail;
-        }
-        ret = 0;
-        break;
-    case DeviceOutRequest | USB_REQ_SET_FEATURE:
-        if (value == USB_DEVICE_REMOTE_WAKEUP) {
-            dev->remote_wakeup = 1;
-        } else {
-            goto fail;
-        }
-        ret = 0;
-        break;
-    case DeviceOutRequest | USB_REQ_SET_ADDRESS:
-        dev->addr = value;
-        ret = 0;
-        break;
-    case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
-        switch(value >> 8) {
-        case USB_DT_DEVICE:
-            memcpy(data, qemu_serial_dev_descriptor,
-                   sizeof(qemu_serial_dev_descriptor));
-            data[8] = s->vendorid & 0xff;
-            data[9] = ((s->vendorid) >> 8) & 0xff;
-            data[10] = s->productid & 0xff;
-            data[11] = ((s->productid) >> 8) & 0xff;
-            ret = sizeof(qemu_serial_dev_descriptor);
-            break;
-        case USB_DT_CONFIG:
-            memcpy(data, qemu_serial_config_descriptor,
-                   sizeof(qemu_serial_config_descriptor));
-            ret = sizeof(qemu_serial_config_descriptor);
-            break;
-        case USB_DT_STRING:
-            switch(value & 0xff) {
-            case 0:
-                /* language ids */
-                data[0] = 4;
-                data[1] = 3;
-                data[2] = 0x09;
-                data[3] = 0x04;
-                ret = 4;
-                break;
-            case 1:
-                /* vendor description */
-                ret = set_usb_string(data, "QEMU " QEMU_VERSION);
-                break;
-            case 2:
-                /* product description */
-                ret = set_usb_string(data, "QEMU USB SERIAL");
-                break;
-            case 3:
-                /* serial number */
-                ret = set_usb_string(data, "1");
-                break;
-            default:
-                goto fail;
-            }
-            break;
-        default:
-            goto fail;
-        }
-        break;
-    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
-        data[0] = 1;
-        ret = 1;
-        break;
-    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
-        ret = 0;
-        break;
     case DeviceRequest | USB_REQ_GET_INTERFACE:
         data[0] = 0;
         ret = 1;
@@ -423,37 +359,42 @@ static int usb_serial_handle_control(USBDevice *dev, int request, int value,
 static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
 {
     USBSerialState *s = (USBSerialState *)dev;
-    int ret = 0;
+    int i, ret = 0;
     uint8_t devep = p->devep;
-    uint8_t *data = p->data;
-    int len = p->len;
-    int first_len;
+    struct iovec *iov;
+    uint8_t header[2];
+    int first_len, len;
 
     switch (p->pid) {
     case USB_TOKEN_OUT:
         if (devep != 2)
             goto fail;
-        qemu_chr_write(s->cs, data, len);
+        for (i = 0; i < p->iov.niov; i++) {
+            iov = p->iov.iov + i;
+            qemu_chr_fe_write(s->cs, iov->iov_base, iov->iov_len);
+        }
         break;
 
     case USB_TOKEN_IN:
         if (devep != 1)
             goto fail;
         first_len = RECV_BUF - s->recv_ptr;
+        len = p->iov.size;
         if (len <= 2) {
             ret = USB_RET_NAK;
             break;
         }
-        *data++ = usb_get_modem_lines(s) | 1;
+        header[0] = usb_get_modem_lines(s) | 1;
         /* We do not have the uart details */
         /* handle serial break */
         if (s->event_trigger && s->event_trigger & FTDI_BI) {
             s->event_trigger &= ~FTDI_BI;
-            *data = FTDI_BI;
+            header[1] = FTDI_BI;
+            usb_packet_copy(p, header, 2);
             ret = 2;
             break;
         } else {
-            *data++ = 0;
+            header[1] = 0;
         }
         len -= 2;
         if (len > s->recv_used)
@@ -464,9 +405,10 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
         }
         if (first_len > len)
             first_len = len;
-        memcpy(data, s->recv_buf + s->recv_ptr, first_len);
+        usb_packet_copy(p, header, 2);
+        usb_packet_copy(p, s->recv_buf + s->recv_ptr, first_len);
         if (len > first_len)
-            memcpy(data + first_len, s->recv_buf, len - first_len);
+            usb_packet_copy(p, s->recv_buf, len - first_len);
         s->recv_used -= len;
         s->recv_ptr = (s->recv_ptr + len) % RECV_BUF;
         ret = len + 2;
@@ -543,7 +485,13 @@ static void usb_serial_event(void *opaque, int event)
 static int usb_serial_initfn(USBDevice *dev)
 {
     USBSerialState *s = DO_UPCAST(USBSerialState, dev, dev);
-    s->dev.speed = USB_SPEED_FULL;
+
+    usb_desc_init(dev);
+
+    if (!s->cs) {
+        error_report("Property chardev is required");
+        return -1;
+    }
 
     qemu_chr_add_handlers(s->cs, usb_serial_can_read, usb_serial_read,
                           usb_serial_event, s);
@@ -624,10 +572,17 @@ static USBDevice *usb_braille_init(const char *unused)
     return dev;
 }
 
+static const VMStateDescription vmstate_usb_serial = {
+    .name = "usb-serial",
+    .unmigratable = 1,
+};
+
 static struct USBDeviceInfo serial_info = {
     .product_desc   = "QEMU USB Serial",
     .qdev.name      = "usb-serial",
     .qdev.size      = sizeof(USBSerialState),
+    .qdev.vmsd      = &vmstate_usb_serial,
+    .usb_desc       = &desc_serial,
     .init           = usb_serial_initfn,
     .handle_packet  = usb_generic_handle_packet,
     .handle_reset   = usb_serial_handle_reset,
@@ -637,9 +592,7 @@ static struct USBDeviceInfo serial_info = {
     .usbdevice_name = "serial",
     .usbdevice_init = usb_serial_init,
     .qdev.props     = (Property[]) {
-        DEFINE_PROP_CHR("chardev",     USBSerialState, cs),
-        DEFINE_PROP_HEX32("vendorid",  USBSerialState, vendorid,  0x0403),
-        DEFINE_PROP_HEX32("productid", USBSerialState, productid, 0x6001),
+        DEFINE_PROP_CHR("chardev", USBSerialState, cs),
         DEFINE_PROP_END_OF_LIST(),
     },
 };
@@ -648,6 +601,8 @@ static struct USBDeviceInfo braille_info = {
     .product_desc   = "QEMU USB Braille",
     .qdev.name      = "usb-braille",
     .qdev.size      = sizeof(USBSerialState),
+    .qdev.vmsd      = &vmstate_usb_serial,
+    .usb_desc       = &desc_braille,
     .init           = usb_serial_initfn,
     .handle_packet  = usb_generic_handle_packet,
     .handle_reset   = usb_serial_handle_reset,
@@ -657,9 +612,7 @@ static struct USBDeviceInfo braille_info = {
     .usbdevice_name = "braille",
     .usbdevice_init = usb_braille_init,
     .qdev.props     = (Property[]) {
-        DEFINE_PROP_CHR("chardev",     USBSerialState, cs),
-        DEFINE_PROP_HEX32("vendorid",  USBSerialState, vendorid,  0x0403),
-        DEFINE_PROP_HEX32("productid", USBSerialState, productid, 0xfe72),
+        DEFINE_PROP_CHR("chardev", USBSerialState, cs),
         DEFINE_PROP_END_OF_LIST(),
     },
 };