All of lore.kernel.org
 help / color / mirror / Atom feed
From: Samuel Thibault <samuel.thibault@eu.citrix.com>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] Re: [PATCH] USB serial device
Date: Sun, 13 Jan 2008 18:59:30 +0000	[thread overview]
Message-ID: <20080113185930.GE4309@implementation> (raw)
In-Reply-To: <20080113015556.GO4299@implementation>

[-- Attachment #1: Type: text/plain, Size: 1481 bytes --]

Hello,

Samuel Thibault, le Sun 13 Jan 2008 01:55:56 +0000, a écrit :
> Samuel Thibault, le Fri 11 Jan 2008 11:09:23 +0000, a écrit :
> > Samuel Thibault, le Fri 11 Jan 2008 00:23:12 +0000, a écrit :
> > > I would like to implement support for braille devices, and for this I'd
> > > need to first implement a USB serial device (FTDI chip).  Has anybody
> > > worked on that already?
> > 
> > Ok, was easier than expected, Here is a patch. The serial support is
> > incomplete however because qemu still lacks support for flow control and
> > modem lines.
> > 
> > You will notice in tty_serial_init that I made the baud values more
> > relaxed. This is because with divisor/baud conversions, things never get
> > exact, so we need to be laxist with the value. For instance here with
> > FTDI, the base divisor is 48000000/2, so for 57600 bps the guest needs
> > to choose between divisors 416 and 417, which bring to either 57692bps
> > or 57553bps but not exactly 57600bps. It happens that Linux chooses
> > divisor 416, hence 57692bps. Of course, the higher the speed, the worse
> > things get. The 1.1 factor is the smallest factor I could find between
> > usual bps values, notably B110, B134 and B150.
> 
> Here is an updated version, that takes parameters, so as to be able to
> notably provide the product ID.

There was a small bug, here is a fixed version.
I also have a braille device emulation patch which now works, but it
probably needs a bit more polishing.

Samuel

[-- Attachment #2: patch-qemu-usb-serial --]
[-- Type: text/plain, Size: 19999 bytes --]

Index: Makefile
===================================================================
RCS file: /sources/qemu/qemu/Makefile,v
retrieving revision 1.140
diff -u -p -r1.140 Makefile
--- Makefile	6 Jan 2008 18:27:12 -0000	1.140
+++ Makefile	13 Jan 2008 01:54:17 -0000
@@ -57,7 +57,7 @@ OBJS+=i2c.o smbus.o smbus_eeprom.o max73
 OBJS+=ssd0303.o ssd0323.o ads7846.o stellaris_input.o
 OBJS+=scsi-disk.o cdrom.o
 OBJS+=scsi-generic.o
-OBJS+=usb.o usb-hub.o usb-linux.o usb-hid.o usb-msd.o usb-wacom.o
+OBJS+=usb.o usb-hub.o usb-linux.o usb-hid.o usb-msd.o usb-wacom.o usb-serial.o
 OBJS+=sd.o ssi-sd.o
 
 ifdef CONFIG_WIN32
Index: vl.c
===================================================================
RCS file: /sources/qemu/qemu/vl.c,v
retrieving revision 1.395
diff -u -p -r1.395 vl.c
--- vl.c	8 Jan 2008 19:32:16 -0000	1.395
+++ vl.c	13 Jan 2008 01:54:21 -0000
@@ -2237,45 +2237,33 @@ static void tty_serial_init(int fd, int 
 #endif
     tcgetattr (fd, &tty);
 
-    switch(speed) {
-    case 50:
+#define MARGIN 1.1
+    if (speed <= 50 * MARGIN)
         spd = B50;
-        break;
-    case 75:
+    else if (speed <= 75 * MARGIN)
         spd = B75;
-        break;
-    case 300:
+    else if (speed <= 300 * MARGIN)
         spd = B300;
-        break;
-    case 600:
+    else if (speed <= 600 * MARGIN)
         spd = B600;
-        break;
-    case 1200:
+    else if (speed <= 1200 * MARGIN)
         spd = B1200;
-        break;
-    case 2400:
+    else if (speed <= 2400 * MARGIN)
         spd = B2400;
-        break;
-    case 4800:
+    else if (speed <= 4800 * MARGIN)
         spd = B4800;
-        break;
-    case 9600:
+    else if (speed <= 9600 * MARGIN)
         spd = B9600;
-        break;
-    case 19200:
+    else if (speed <= 19200 * MARGIN)
         spd = B19200;
-        break;
-    case 38400:
+    else if (speed <= 38400 * MARGIN)
         spd = B38400;
-        break;
-    case 57600:
+    else if (speed <= 57600 * MARGIN)
         spd = B57600;
-        break;
-    default:
-    case 115200:
+    else if (speed <= 115200 * MARGIN)
+        spd = B115200;
+    else
         spd = B115200;
-        break;
-    }
 
     cfsetispeed(&tty, spd);
     cfsetospeed(&tty, spd);
@@ -5196,6 +5184,8 @@ static int usb_device_add(const char *de
         dev = usb_msd_init(p);
     } else if (!strcmp(devname, "wacom-tablet")) {
         dev = usb_wacom_init();
+    } else if (strstart(devname, "serial:", &p)) {
+	dev = usb_serial_init(p);
     } else {
         return -1;
     }
Index: hw/usb-serial.c
===================================================================
RCS file: hw/usb-serial.c
diff -N hw/usb-serial.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ hw/usb-serial.c	13 Jan 2008 01:54:21 -0000
@@ -0,0 +1,549 @@
+/*
+ * FTDI FT232BM Device emulation
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * 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.
+ */
+
+#include "qemu-common.h"
+#include "usb.h"
+#include "qemu-char.h"
+
+//#define DEBUG_Serial
+
+#ifdef DEBUG_Serial
+#define DPRINTF(fmt, args...) \
+do { printf("usb-serial: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while(0)
+#endif
+
+#define RECV_BUF 384
+#define SEND_BUF 128        // Not used for now
+
+/* Commands */
+#define FTDI_RESET		0
+#define FTDI_SET_MDM_CTRL	1
+#define FTDI_SET_FLOW_CTRL	2
+#define FTDI_SET_BAUD		3
+#define FTDI_SET_DATA		4
+#define FTDI_GET_MDM_ST		5
+#define FTDI_SET_EVENT_CHR	6
+#define FTDI_SET_ERROR_CHR	7
+#define FTDI_SET_LATENCY	9
+#define FTDI_GET_LATENCY	10
+
+#define DeviceOutVendor	((USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<	8)
+#define DeviceInVendor	((USB_DIR_IN |USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<	8)
+
+/* RESET */
+
+#define FTDI_RESET_SIO	0
+#define FTDI_RESET_RX	1
+#define FTDI_RESET_TX	2
+
+/* SET_MDM_CTRL */
+
+#define FTDI_MDM_CTRL	3
+#define FTDI_DTR	1
+#define FTDI_RTS	2
+
+/* SET_FLOW_CTRL */
+
+#define FTDI_RTS_CTS_HS		1
+#define FTDI_DTR_DSR_HS		2
+#define FTDI_XON_XOFF_HS	4
+
+/* SET_DATA */
+
+#define FTDI_PARITY	(0x7 << 8)
+#define FTDI_ODD	(0x1 << 8)
+#define FTDI_EVEN	(0x2 << 8)
+#define FTDI_MARK	(0x3 << 8)
+#define FTDI_SPACE	(0x4 << 8)
+
+#define FTDI_STOP	(0x3 << 11)
+#define FTDI_STOP1	(0x0 << 11)
+#define FTDI_STOP15	(0x1 << 11)
+#define FTDI_STOP2	(0x2 << 11)
+
+/* GET_MDM_ST */
+/* TODO: should be sent every 40ms */
+#define FTDI_CTS  (1<<4)        // CTS line status
+#define FTDI_DSR  (1<<5)        // DSR line status
+#define FTDI_RI   (1<<6)        // RI line status
+#define FTDI_RLSD (1<<7)        // Receive Line Signal Detect
+
+/* Status */
+
+#define FTDI_DR   (1<<0)        // Data Ready
+#define FTDI_OE   (1<<1)        // Overrun Err
+#define FTDI_PE   (1<<2)        // Parity Err
+#define FTDI_FE   (1<<3)        // Framing Err
+#define FTDI_BI   (1<<4)        // Break Interrupt
+#define FTDI_THRE (1<<5)        // Transmitter Holding Register
+#define FTDI_TEMT (1<<6)        // Transmitter Empty
+#define FTDI_FIFO (1<<7)        // Error in FIFO
+
+typedef struct {
+    USBDevice dev;
+    uint16_t vendorid;
+    uint16_t productid;
+    uint8_t recv_buf[RECV_BUF];
+    uint8_t recv_ptr;
+    uint8_t recv_used;
+    uint8_t send_buf[SEND_BUF];
+    uint8_t event_chr;
+    uint8_t error_chr;
+    uint8_t event_trigger;
+    uint8_t lines;
+    QEMUSerialSetParams params;
+    int latency;        /* ms */
+    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; */
+};
+
+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 void usb_serial_reset(USBSerialState *s)
+{
+    /* TODO: Set flow control to none */
+    s->event_chr = 0x0d;
+    s->event_trigger = 0;
+    s->recv_ptr = 0;
+    s->recv_used = 0;
+    /* TODO: purge in char driver */
+    s->lines &= ~(FTDI_DTR|FTDI_RTS);
+}
+
+static void usb_serial_handle_reset(USBDevice *dev)
+{
+    USBSerialState *s = (USBSerialState *)dev;
+
+    DPRINTF("Reset\n");
+
+    usb_serial_reset(s);
+    /* TODO: Reset char device, send BREAK? */
+}
+
+static int usb_serial_handle_control(USBDevice *dev, int request, int value,
+                                  int index, int length, uint8_t *data)
+{
+    USBSerialState *s = (USBSerialState *)dev;
+    int ret = 0;
+
+    //DPRINTF("got control %x, value %x\n",request, value);
+    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;
+        break;
+    case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
+        ret = 0;
+        break;
+    case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
+        ret = 0;
+        break;
+
+        /* Class specific requests.  */
+    case DeviceOutVendor | FTDI_RESET:
+        switch (value) {
+        case FTDI_RESET_SIO:
+            usb_serial_reset(s);
+            break;
+        case FTDI_RESET_RX:
+            s->recv_ptr = 0;
+            s->recv_used = 0;
+            /* TODO: purge from char device */
+            break;
+        case FTDI_RESET_TX:
+            /* TODO: purge from char device */
+            break;
+        }
+        break;
+    case DeviceOutVendor | FTDI_SET_MDM_CTRL:
+        s->lines = value & FTDI_MDM_CTRL;
+        break;
+    case DeviceOutVendor | FTDI_SET_FLOW_CTRL:
+        /* TODO: ioctl */
+        break;
+    case DeviceOutVendor | FTDI_SET_BAUD: {
+        static const int subdivisors8[8] = { 0, 4, 2, 1, 3, 5, 6, 7 };
+        int subdivisor8 = subdivisors8[((value & 0xc000) >> 14)
+                                     | ((index & 1) << 2)];
+        int divisor = value & 0x3fff;
+
+        /* chip special cases */
+        if (divisor == 1 && subdivisor8 == 0)
+            subdivisor8 = 4;
+        if (divisor == 0 && subdivisor8 == 0)
+            divisor = 1;
+
+        s->params.speed = (48000000 / 2) / (8 * divisor + subdivisor8);
+        qemu_chr_ioctl(s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
+        break;
+    }
+    case DeviceOutVendor | FTDI_SET_DATA:
+        switch (value & FTDI_PARITY) {
+            case 0:
+                s->params.parity = 'N';
+                break;
+            case FTDI_ODD:
+                s->params.parity = 'O';
+                break;
+            case FTDI_EVEN:
+                s->params.parity = 'E';
+                break;
+            default:
+                DPRINTF("unsupported parity %d\n", value & FTDI_PARITY);
+                goto fail;
+        }
+        switch (value & FTDI_STOP) {
+            case FTDI_STOP1:
+                s->params.stop_bits = 1;
+                break;
+            case FTDI_STOP2:
+                s->params.stop_bits = 2;
+                break;
+            default:
+                DPRINTF("unsupported stop bits %d\n", value & FTDI_STOP);
+                goto fail;
+        }
+        qemu_chr_ioctl(s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
+        /* TODO: TX ON/OFF */
+        break;
+    case DeviceInVendor | FTDI_GET_MDM_ST:
+        /* TODO: return modem status */
+        data[0] = 0;
+        ret = 1;
+        break;
+    case DeviceOutVendor | FTDI_SET_EVENT_CHR:
+        /* TODO: handle it */
+        s->event_chr = value;
+        break;
+    case DeviceOutVendor | FTDI_SET_ERROR_CHR:
+        /* TODO: handle it */
+        s->error_chr = value;
+        break;
+    case DeviceOutVendor | FTDI_SET_LATENCY:
+        s->latency = value;
+        break;
+    case DeviceInVendor | FTDI_GET_LATENCY:
+        data[0] = s->latency;
+        ret = 1;
+        break;
+    default:
+    fail:
+        DPRINTF("got unsupported/bogus control %x, value %x\n", request, value);
+        ret = USB_RET_STALL;
+        break;
+    }
+    return ret;
+}
+
+static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
+{
+    USBSerialState *s = (USBSerialState *)dev;
+    int ret = 0;
+    uint8_t devep = p->devep;
+    uint8_t *data = p->data;
+    int len = p->len;
+    int first_len;
+
+    switch (p->pid) {
+    case USB_TOKEN_OUT:
+        if (devep != 2)
+            goto fail;
+        qemu_chr_write(s->cs, data, len);
+        break;
+
+    case USB_TOKEN_IN:
+        if (devep != 1)
+            goto fail;
+        first_len = RECV_BUF - s->recv_ptr;
+        if (len <= 2) {
+            ret = USB_RET_NAK;
+            break;
+        }
+        /* TODO: Report serial line status */
+        *data++ = 0;
+        *data++ = 0;
+        len -= 2;
+        if (len > s->recv_used)
+            len = s->recv_used;
+        if (!len) {
+            ret = USB_RET_NAK;
+            break;
+        }
+        if (first_len > len)
+            first_len = len;
+        memcpy(data, s->recv_buf + s->recv_ptr, first_len);
+        if (len > first_len)
+            memcpy(data + first_len, s->recv_buf, len - first_len);
+        s->recv_used -= len;
+        s->recv_ptr = (s->recv_ptr + len) % RECV_BUF;
+        ret = len + 2;
+        break;
+
+    default:
+        DPRINTF("Bad token\n");
+    fail:
+        ret = USB_RET_STALL;
+        break;
+    }
+
+    return ret;
+}
+
+static void usb_serial_handle_destroy(USBDevice *dev)
+{
+    USBSerialState *s = (USBSerialState *)dev;
+
+    qemu_chr_close(s->cs);
+    qemu_free(s);
+}
+
+int usb_serial_can_read(void *opaque)
+{
+    USBSerialState *s = opaque;
+    return RECV_BUF - s->recv_used;
+}
+
+void usb_serial_read(void *opaque, const uint8_t *buf, int size)
+{
+    USBSerialState *s = opaque;
+    int first_size = RECV_BUF - s->recv_ptr;
+    if (first_size > size)
+        first_size = size;
+    memcpy(s->recv_buf + s->recv_ptr + s->recv_used, buf, first_size);
+    if (size > first_size)
+        memcpy(s->recv_buf, buf + first_size, size - first_size);
+    s->recv_used += size;
+}
+
+void usb_serial_event(void *opaque, int event)
+{
+    USBSerialState *s = opaque;
+
+    switch (event) {
+        case CHR_EVENT_BREAK:
+            /* TODO: Send Break to USB */
+            break;
+        case CHR_EVENT_FOCUS:
+            break;
+        case CHR_EVENT_RESET:
+            usb_serial_reset(s);
+            /* TODO: Reset USB port */
+            break;
+    }
+}
+
+USBDevice *usb_serial_init(const char *filename)
+{
+    USBSerialState *s;
+    CharDriverState *cdrv;
+    unsigned short vendorid = 0x0403, productid = 0xFF00;
+
+    while (*filename && *filename != ':') {
+        const char *p;
+        char *e;
+        if (strstart(filename, "vendorid=", &p)) {
+            vendorid = strtol(p, &e, 16);
+            if (e == p || (*e && *e != ',' && *e != ':')) {
+                printf("bogus vendor ID %s\n", p);
+                return NULL;
+            }
+            filename = e;
+        } else if (strstart(filename, "productid=", &p)) {
+            productid = strtol(p, &e, 16);
+            if (e == p || (*e && *e != ',' && *e != ':')) {
+                printf("bogus product ID %s\n", p);
+                return NULL;
+            }
+            filename = e;
+        } else {
+            printf("unrecognized serial USB option %s\n", filename);
+            return NULL;
+        }
+        while(*filename == ',')
+            filename++;
+    }
+    if (!*filename) {
+        printf("character device specification needed\n");
+        return NULL;
+    }
+    filename++;
+    s = qemu_mallocz(sizeof(USBSerialState));
+    if (!s)
+        return NULL;
+
+    cdrv = qemu_chr_open(filename);
+    if (!cdrv)
+        goto fail;
+    s->cs = cdrv;
+    qemu_chr_add_handlers(cdrv, usb_serial_can_read, usb_serial_read, usb_serial_event, s);
+
+    s->dev.speed = USB_SPEED_FULL;
+    s->dev.handle_packet = usb_generic_handle_packet;
+
+    s->dev.handle_reset = usb_serial_handle_reset;
+    s->dev.handle_control = usb_serial_handle_control;
+    s->dev.handle_data = usb_serial_handle_data;
+    s->dev.handle_destroy = usb_serial_handle_destroy;
+
+    s->vendorid = vendorid;
+    s->productid = productid;
+
+    snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Serial(%.16s)",
+             filename);
+
+    usb_serial_handle_reset((USBDevice *)s);
+    return (USBDevice *)s;
+ fail:
+    qemu_free(s);
+    return NULL;
+}
Index: hw/usb.h
===================================================================
RCS file: /sources/qemu/qemu/hw/usb.h,v
retrieving revision 1.19
diff -u -p -r1.19 usb.h
--- hw/usb.h	17 Nov 2007 17:14:50 -0000	1.19
+++ hw/usb.h	13 Jan 2008 01:54:21 -0000
@@ -217,6 +217,9 @@ USBDevice *usb_msd_init(const char *file
 /* usb-wacom.c */
 USBDevice *usb_wacom_init(void);
 
+/* usb-serial.c */
+USBDevice *usb_serial_init(const char *filename);
+
 /* usb ports of the VM */
 
 void qemu_register_usb_port(USBPort *port, void *opaque, int index,

  reply	other threads:[~2008-01-13 18:59 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-01-11  0:23 [Qemu-devel] USB serial device Samuel Thibault
2008-01-11 11:09 ` [Qemu-devel] [PATCH] " Samuel Thibault
2008-01-13  1:55   ` [Qemu-devel] " Samuel Thibault
2008-01-13 18:59     ` Samuel Thibault [this message]
2008-01-17 14:09       ` andrzej zaborowski
2008-01-17 14:47         ` Samuel Thibault
2008-01-17 22:25           ` andrzej zaborowski
2008-01-17 22:44             ` Samuel Thibault
2008-01-19 13:05               ` andrzej zaborowski
2008-01-19 21:26                 ` Samuel Thibault

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080113185930.GE4309@implementation \
    --to=samuel.thibault@eu.citrix.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.