qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

dev-serial.c (19544B)


      1 /*
      2  * FTDI FT232BM Device emulation
      3  *
      4  * Copyright (c) 2006 CodeSourcery.
      5  * Copyright (c) 2008 Samuel Thibault <samuel.thibault@ens-lyon.org>
      6  * Written by Paul Brook, reused for FTDI by Samuel Thibault
      7  *
      8  * This code is licensed under the LGPL.
      9  */
     10 
     11 #include "qemu/osdep.h"
     12 #include "qapi/error.h"
     13 #include "qemu/cutils.h"
     14 #include "qemu/error-report.h"
     15 #include "qemu/module.h"
     16 #include "hw/qdev-properties.h"
     17 #include "hw/qdev-properties-system.h"
     18 #include "hw/usb.h"
     19 #include "migration/vmstate.h"
     20 #include "desc.h"
     21 #include "chardev/char-serial.h"
     22 #include "chardev/char-fe.h"
     23 #include "qom/object.h"
     24 #include "trace.h"
     25 
     26 
     27 #define RECV_BUF (512 - (2 * 8))
     28 
     29 /* Commands */
     30 #define FTDI_RESET             0
     31 #define FTDI_SET_MDM_CTRL      1
     32 #define FTDI_SET_FLOW_CTRL     2
     33 #define FTDI_SET_BAUD          3
     34 #define FTDI_SET_DATA          4
     35 #define FTDI_GET_MDM_ST        5
     36 #define FTDI_SET_EVENT_CHR     6
     37 #define FTDI_SET_ERROR_CHR     7
     38 #define FTDI_SET_LATENCY       9
     39 #define FTDI_GET_LATENCY       10
     40 
     41 /* RESET */
     42 
     43 #define FTDI_RESET_SIO 0
     44 #define FTDI_RESET_RX  1
     45 #define FTDI_RESET_TX  2
     46 
     47 /* SET_MDM_CTRL */
     48 
     49 #define FTDI_DTR       1
     50 #define FTDI_SET_DTR   (FTDI_DTR << 8)
     51 #define FTDI_RTS       2
     52 #define FTDI_SET_RTS   (FTDI_RTS << 8)
     53 
     54 /* SET_FLOW_CTRL */
     55 
     56 #define FTDI_NO_HS         0
     57 #define FTDI_RTS_CTS_HS    1
     58 #define FTDI_DTR_DSR_HS    2
     59 #define FTDI_XON_XOFF_HS   4
     60 
     61 /* SET_DATA */
     62 
     63 #define FTDI_PARITY    (0x7 << 8)
     64 #define FTDI_ODD       (0x1 << 8)
     65 #define FTDI_EVEN      (0x2 << 8)
     66 #define FTDI_MARK      (0x3 << 8)
     67 #define FTDI_SPACE     (0x4 << 8)
     68 
     69 #define FTDI_STOP      (0x3 << 11)
     70 #define FTDI_STOP1     (0x0 << 11)
     71 #define FTDI_STOP15    (0x1 << 11)
     72 #define FTDI_STOP2     (0x2 << 11)
     73 
     74 /* GET_MDM_ST */
     75 /* TODO: should be sent every 40ms */
     76 #define FTDI_CTS   (1 << 4)    /* CTS line status */
     77 #define FTDI_DSR   (1 << 5)    /* DSR line status */
     78 #define FTDI_RI    (1 << 6)    /* RI line status */
     79 #define FTDI_RLSD  (1 << 7)    /* Receive Line Signal Detect */
     80 
     81 /* Status */
     82 
     83 #define FTDI_DR    (1 << 0)    /* Data Ready */
     84 #define FTDI_OE    (1 << 1)    /* Overrun Err */
     85 #define FTDI_PE    (1 << 2)    /* Parity Err */
     86 #define FTDI_FE    (1 << 3)    /* Framing Err */
     87 #define FTDI_BI    (1 << 4)    /* Break Interrupt */
     88 #define FTDI_THRE  (1 << 5)    /* Transmitter Holding Register */
     89 #define FTDI_TEMT  (1 << 6)    /* Transmitter Empty */
     90 #define FTDI_FIFO  (1 << 7)    /* Error in FIFO */
     91 
     92 struct USBSerialState {
     93     USBDevice dev;
     94 
     95     USBEndpoint *intr;
     96     uint8_t recv_buf[RECV_BUF];
     97     uint16_t recv_ptr;
     98     uint16_t recv_used;
     99     uint8_t event_chr;
    100     uint8_t error_chr;
    101     uint8_t event_trigger;
    102     bool always_plugged;
    103     uint8_t flow_control;
    104     uint8_t xon;
    105     uint8_t xoff;
    106     QEMUSerialSetParams params;
    107     int latency;        /* ms */
    108     CharBackend cs;
    109 };
    110 
    111 #define TYPE_USB_SERIAL "usb-serial-dev"
    112 OBJECT_DECLARE_SIMPLE_TYPE(USBSerialState, USB_SERIAL)
    113 
    114 enum {
    115     STR_MANUFACTURER = 1,
    116     STR_PRODUCT_SERIAL,
    117     STR_PRODUCT_BRAILLE,
    118     STR_SERIALNUMBER,
    119 };
    120 
    121 static const USBDescStrings desc_strings = {
    122     [STR_MANUFACTURER]    = "QEMU",
    123     [STR_PRODUCT_SERIAL]  = "QEMU USB SERIAL",
    124     [STR_PRODUCT_BRAILLE] = "QEMU USB BAUM BRAILLE",
    125     [STR_SERIALNUMBER]    = "1",
    126 };
    127 
    128 static const USBDescIface desc_iface0 = {
    129     .bInterfaceNumber              = 0,
    130     .bNumEndpoints                 = 2,
    131     .bInterfaceClass               = 0xff,
    132     .bInterfaceSubClass            = 0xff,
    133     .bInterfaceProtocol            = 0xff,
    134     .eps = (USBDescEndpoint[]) {
    135         {
    136             .bEndpointAddress      = USB_DIR_IN | 0x01,
    137             .bmAttributes          = USB_ENDPOINT_XFER_BULK,
    138             .wMaxPacketSize        = 64,
    139         },{
    140             .bEndpointAddress      = USB_DIR_OUT | 0x02,
    141             .bmAttributes          = USB_ENDPOINT_XFER_BULK,
    142             .wMaxPacketSize        = 64,
    143         },
    144     }
    145 };
    146 
    147 static const USBDescDevice desc_device = {
    148     .bcdUSB                        = 0x0200,
    149     .bMaxPacketSize0               = 8,
    150     .bNumConfigurations            = 1,
    151     .confs = (USBDescConfig[]) {
    152         {
    153             .bNumInterfaces        = 1,
    154             .bConfigurationValue   = 1,
    155             .bmAttributes          = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
    156             .bMaxPower             = 50,
    157             .nif = 1,
    158             .ifs = &desc_iface0,
    159         },
    160     },
    161 };
    162 
    163 static const USBDesc desc_serial = {
    164     .id = {
    165         .idVendor          = 0x0403,
    166         .idProduct         = 0x6001,
    167         .bcdDevice         = 0x0400,
    168         .iManufacturer     = STR_MANUFACTURER,
    169         .iProduct          = STR_PRODUCT_SERIAL,
    170         .iSerialNumber     = STR_SERIALNUMBER,
    171     },
    172     .full = &desc_device,
    173     .str  = desc_strings,
    174 };
    175 
    176 static const USBDesc desc_braille = {
    177     .id = {
    178         .idVendor          = 0x0403,
    179         .idProduct         = 0xfe72,
    180         .bcdDevice         = 0x0400,
    181         .iManufacturer     = STR_MANUFACTURER,
    182         .iProduct          = STR_PRODUCT_BRAILLE,
    183         .iSerialNumber     = STR_SERIALNUMBER,
    184     },
    185     .full = &desc_device,
    186     .str  = desc_strings,
    187 };
    188 
    189 static void usb_serial_set_flow_control(USBSerialState *s,
    190                                         uint8_t flow_control)
    191 {
    192     USBDevice *dev = USB_DEVICE(s);
    193     USBBus *bus = usb_bus_from_device(dev);
    194 
    195     /* TODO: ioctl */
    196     s->flow_control = flow_control;
    197     trace_usb_serial_set_flow_control(bus->busnr, dev->addr, flow_control);
    198 }
    199 
    200 static void usb_serial_set_xonxoff(USBSerialState *s, int xonxoff)
    201 {
    202     USBDevice *dev = USB_DEVICE(s);
    203     USBBus *bus = usb_bus_from_device(dev);
    204 
    205     s->xon = xonxoff & 0xff;
    206     s->xoff = (xonxoff >> 8) & 0xff;
    207 
    208     trace_usb_serial_set_xonxoff(bus->busnr, dev->addr, s->xon, s->xoff);
    209 }
    210 
    211 static void usb_serial_reset(USBSerialState *s)
    212 {
    213     s->event_chr = 0x0d;
    214     s->event_trigger = 0;
    215     s->recv_ptr = 0;
    216     s->recv_used = 0;
    217     /* TODO: purge in char driver */
    218     usb_serial_set_flow_control(s, FTDI_NO_HS);
    219 }
    220 
    221 static void usb_serial_handle_reset(USBDevice *dev)
    222 {
    223     USBSerialState *s = USB_SERIAL(dev);
    224     USBBus *bus = usb_bus_from_device(dev);
    225 
    226     trace_usb_serial_reset(bus->busnr, dev->addr);
    227 
    228     usb_serial_reset(s);
    229     /* TODO: Reset char device, send BREAK? */
    230 }
    231 
    232 static uint8_t usb_get_modem_lines(USBSerialState *s)
    233 {
    234     int flags;
    235     uint8_t ret;
    236 
    237     if (qemu_chr_fe_ioctl(&s->cs,
    238                           CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP) {
    239         return FTDI_CTS | FTDI_DSR | FTDI_RLSD;
    240     }
    241 
    242     ret = 0;
    243     if (flags & CHR_TIOCM_CTS) {
    244         ret |= FTDI_CTS;
    245     }
    246     if (flags & CHR_TIOCM_DSR) {
    247         ret |= FTDI_DSR;
    248     }
    249     if (flags & CHR_TIOCM_RI) {
    250         ret |= FTDI_RI;
    251     }
    252     if (flags & CHR_TIOCM_CAR) {
    253         ret |= FTDI_RLSD;
    254     }
    255 
    256     return ret;
    257 }
    258 
    259 static void usb_serial_handle_control(USBDevice *dev, USBPacket *p,
    260                                       int request, int value, int index,
    261                                       int length, uint8_t *data)
    262 {
    263     USBSerialState *s = USB_SERIAL(dev);
    264     USBBus *bus = usb_bus_from_device(dev);
    265     int ret;
    266 
    267     trace_usb_serial_handle_control(bus->busnr, dev->addr, request, value);
    268 
    269     ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
    270     if (ret >= 0) {
    271         return;
    272     }
    273 
    274     switch (request) {
    275     case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
    276         break;
    277 
    278     /* Class specific requests.  */
    279     case VendorDeviceOutRequest | FTDI_RESET:
    280         switch (value) {
    281         case FTDI_RESET_SIO:
    282             usb_serial_reset(s);
    283             break;
    284         case FTDI_RESET_RX:
    285             s->recv_ptr = 0;
    286             s->recv_used = 0;
    287             /* TODO: purge from char device */
    288             break;
    289         case FTDI_RESET_TX:
    290             /* TODO: purge from char device */
    291             break;
    292         }
    293         break;
    294     case VendorDeviceOutRequest | FTDI_SET_MDM_CTRL:
    295     {
    296         static int flags;
    297         qemu_chr_fe_ioctl(&s->cs, CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
    298         if (value & FTDI_SET_RTS) {
    299             if (value & FTDI_RTS) {
    300                 flags |= CHR_TIOCM_RTS;
    301             } else {
    302                 flags &= ~CHR_TIOCM_RTS;
    303             }
    304         }
    305         if (value & FTDI_SET_DTR) {
    306             if (value & FTDI_DTR) {
    307                 flags |= CHR_TIOCM_DTR;
    308             } else {
    309                 flags &= ~CHR_TIOCM_DTR;
    310             }
    311         }
    312         qemu_chr_fe_ioctl(&s->cs, CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
    313         break;
    314     }
    315     case VendorDeviceOutRequest | FTDI_SET_FLOW_CTRL: {
    316         uint8_t flow_control = index >> 8;
    317 
    318         usb_serial_set_flow_control(s, flow_control);
    319         if (flow_control & FTDI_XON_XOFF_HS) {
    320             usb_serial_set_xonxoff(s, value);
    321         }
    322         break;
    323     }
    324     case VendorDeviceOutRequest | FTDI_SET_BAUD: {
    325         static const int subdivisors8[8] = { 0, 4, 2, 1, 3, 5, 6, 7 };
    326         int subdivisor8 = subdivisors8[((value & 0xc000) >> 14)
    327                                      | ((index & 1) << 2)];
    328         int divisor = value & 0x3fff;
    329 
    330         /* chip special cases */
    331         if (divisor == 1 && subdivisor8 == 0) {
    332             subdivisor8 = 4;
    333         }
    334         if (divisor == 0 && subdivisor8 == 0) {
    335             divisor = 1;
    336         }
    337 
    338         s->params.speed = (48000000 / 2) / (8 * divisor + subdivisor8);
    339         trace_usb_serial_set_baud(bus->busnr, dev->addr, s->params.speed);
    340         qemu_chr_fe_ioctl(&s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
    341         break;
    342     }
    343     case VendorDeviceOutRequest | FTDI_SET_DATA:
    344         switch (value & 0xff) {
    345         case 7:
    346             s->params.data_bits = 7;
    347             break;
    348         case 8:
    349             s->params.data_bits = 8;
    350             break;
    351         default:
    352             /*
    353              * According to a comment in Linux's ftdi_sio.c original FTDI
    354              * chips fall back to 8 data bits for unsupported data_bits
    355              */
    356             trace_usb_serial_unsupported_data_bits(bus->busnr, dev->addr,
    357                                                    value & 0xff);
    358             s->params.data_bits = 8;
    359         }
    360 
    361         switch (value & FTDI_PARITY) {
    362         case 0:
    363             s->params.parity = 'N';
    364             break;
    365         case FTDI_ODD:
    366             s->params.parity = 'O';
    367             break;
    368         case FTDI_EVEN:
    369             s->params.parity = 'E';
    370             break;
    371         default:
    372             trace_usb_serial_unsupported_parity(bus->busnr, dev->addr,
    373                                                 value & FTDI_PARITY);
    374             goto fail;
    375         }
    376 
    377         switch (value & FTDI_STOP) {
    378         case FTDI_STOP1:
    379             s->params.stop_bits = 1;
    380             break;
    381         case FTDI_STOP2:
    382             s->params.stop_bits = 2;
    383             break;
    384         default:
    385             trace_usb_serial_unsupported_stopbits(bus->busnr, dev->addr,
    386                                                   value & FTDI_STOP);
    387             goto fail;
    388         }
    389 
    390         trace_usb_serial_set_data(bus->busnr, dev->addr, s->params.parity,
    391                                   s->params.data_bits, s->params.stop_bits);
    392         qemu_chr_fe_ioctl(&s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
    393         /* TODO: TX ON/OFF */
    394         break;
    395     case VendorDeviceRequest | FTDI_GET_MDM_ST:
    396         data[0] = usb_get_modem_lines(s) | 1;
    397         data[1] = FTDI_THRE | FTDI_TEMT;
    398         p->actual_length = 2;
    399         break;
    400     case VendorDeviceOutRequest | FTDI_SET_EVENT_CHR:
    401         /* TODO: handle it */
    402         s->event_chr = value;
    403         break;
    404     case VendorDeviceOutRequest | FTDI_SET_ERROR_CHR:
    405         /* TODO: handle it */
    406         s->error_chr = value;
    407         break;
    408     case VendorDeviceOutRequest | FTDI_SET_LATENCY:
    409         s->latency = value;
    410         break;
    411     case VendorDeviceRequest | FTDI_GET_LATENCY:
    412         data[0] = s->latency;
    413         p->actual_length = 1;
    414         break;
    415     default:
    416     fail:
    417         trace_usb_serial_unsupported_control(bus->busnr, dev->addr, request,
    418                                              value);
    419         p->status = USB_RET_STALL;
    420         break;
    421     }
    422 }
    423 
    424 static void usb_serial_token_in(USBSerialState *s, USBPacket *p)
    425 {
    426     const int max_packet_size = desc_iface0.eps[0].wMaxPacketSize;
    427     int packet_len;
    428     uint8_t header[2];
    429 
    430     packet_len = p->iov.size;
    431     if (packet_len <= 2) {
    432         p->status = USB_RET_NAK;
    433         return;
    434     }
    435 
    436     header[0] = usb_get_modem_lines(s) | 1;
    437     /* We do not have the uart details */
    438     /* handle serial break */
    439     if (s->event_trigger && s->event_trigger & FTDI_BI) {
    440         s->event_trigger &= ~FTDI_BI;
    441         header[1] = FTDI_BI;
    442         usb_packet_copy(p, header, 2);
    443         return;
    444     } else {
    445         header[1] = 0;
    446     }
    447 
    448     if (!s->recv_used) {
    449         p->status = USB_RET_NAK;
    450         return;
    451     }
    452 
    453     while (s->recv_used && packet_len > 2) {
    454         int first_len, len;
    455 
    456         len = MIN(packet_len, max_packet_size);
    457         len -= 2;
    458         if (len > s->recv_used) {
    459             len = s->recv_used;
    460         }
    461 
    462         first_len = RECV_BUF - s->recv_ptr;
    463         if (first_len > len) {
    464             first_len = len;
    465         }
    466         usb_packet_copy(p, header, 2);
    467         usb_packet_copy(p, s->recv_buf + s->recv_ptr, first_len);
    468         if (len > first_len) {
    469             usb_packet_copy(p, s->recv_buf, len - first_len);
    470         }
    471         s->recv_used -= len;
    472         s->recv_ptr = (s->recv_ptr + len) % RECV_BUF;
    473         packet_len -= len + 2;
    474     }
    475 
    476     return;
    477 }
    478 
    479 static void usb_serial_handle_data(USBDevice *dev, USBPacket *p)
    480 {
    481     USBSerialState *s = USB_SERIAL(dev);
    482     USBBus *bus = usb_bus_from_device(dev);
    483     uint8_t devep = p->ep->nr;
    484     struct iovec *iov;
    485     int i;
    486 
    487     switch (p->pid) {
    488     case USB_TOKEN_OUT:
    489         if (devep != 2) {
    490             goto fail;
    491         }
    492         for (i = 0; i < p->iov.niov; i++) {
    493             iov = p->iov.iov + i;
    494             /*
    495              * XXX this blocks entire thread. Rewrite to use
    496              * qemu_chr_fe_write and background I/O callbacks
    497              */
    498             qemu_chr_fe_write_all(&s->cs, iov->iov_base, iov->iov_len);
    499         }
    500         p->actual_length = p->iov.size;
    501         break;
    502 
    503     case USB_TOKEN_IN:
    504         if (devep != 1) {
    505             goto fail;
    506         }
    507         usb_serial_token_in(s, p);
    508         break;
    509 
    510     default:
    511         trace_usb_serial_bad_token(bus->busnr, dev->addr);
    512     fail:
    513         p->status = USB_RET_STALL;
    514         break;
    515     }
    516 }
    517 
    518 static int usb_serial_can_read(void *opaque)
    519 {
    520     USBSerialState *s = opaque;
    521 
    522     if (!s->dev.attached) {
    523         return 0;
    524     }
    525     return RECV_BUF - s->recv_used;
    526 }
    527 
    528 static void usb_serial_read(void *opaque, const uint8_t *buf, int size)
    529 {
    530     USBSerialState *s = opaque;
    531     int first_size, start;
    532 
    533     /* room in the buffer? */
    534     if (size > (RECV_BUF - s->recv_used)) {
    535         size = RECV_BUF - s->recv_used;
    536     }
    537 
    538     start = s->recv_ptr + s->recv_used;
    539     if (start < RECV_BUF) {
    540         /* copy data to end of buffer */
    541         first_size = RECV_BUF - start;
    542         if (first_size > size) {
    543             first_size = size;
    544         }
    545 
    546         memcpy(s->recv_buf + start, buf, first_size);
    547 
    548         /* wrap around to front if needed */
    549         if (size > first_size) {
    550             memcpy(s->recv_buf, buf + first_size, size - first_size);
    551         }
    552     } else {
    553         start -= RECV_BUF;
    554         memcpy(s->recv_buf + start, buf, size);
    555     }
    556     s->recv_used += size;
    557 
    558     usb_wakeup(s->intr, 0);
    559 }
    560 
    561 static void usb_serial_event(void *opaque, QEMUChrEvent event)
    562 {
    563     USBSerialState *s = opaque;
    564 
    565     switch (event) {
    566     case CHR_EVENT_BREAK:
    567         s->event_trigger |= FTDI_BI;
    568         break;
    569     case CHR_EVENT_OPENED:
    570         if (!s->always_plugged && !s->dev.attached) {
    571             usb_device_attach(&s->dev, &error_abort);
    572         }
    573         break;
    574     case CHR_EVENT_CLOSED:
    575         if (!s->always_plugged && s->dev.attached) {
    576             usb_device_detach(&s->dev);
    577         }
    578         break;
    579     case CHR_EVENT_MUX_IN:
    580     case CHR_EVENT_MUX_OUT:
    581         /* Ignore */
    582         break;
    583     }
    584 }
    585 
    586 static void usb_serial_realize(USBDevice *dev, Error **errp)
    587 {
    588     USBSerialState *s = USB_SERIAL(dev);
    589     Error *local_err = NULL;
    590 
    591     usb_desc_create_serial(dev);
    592     usb_desc_init(dev);
    593     dev->auto_attach = 0;
    594 
    595     if (!qemu_chr_fe_backend_connected(&s->cs)) {
    596         error_setg(errp, "Property chardev is required");
    597         return;
    598     }
    599 
    600     usb_check_attach(dev, &local_err);
    601     if (local_err) {
    602         error_propagate(errp, local_err);
    603         return;
    604     }
    605 
    606     qemu_chr_fe_set_handlers(&s->cs, usb_serial_can_read, usb_serial_read,
    607                              usb_serial_event, NULL, s, NULL, true);
    608     usb_serial_handle_reset(dev);
    609 
    610     if ((s->always_plugged || qemu_chr_fe_backend_open(&s->cs)) &&
    611         !dev->attached) {
    612         usb_device_attach(dev, &error_abort);
    613     }
    614     s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
    615 }
    616 
    617 static USBDevice *usb_braille_init(void)
    618 {
    619     USBDevice *dev;
    620     Chardev *cdrv;
    621 
    622     cdrv = qemu_chr_new("braille", "braille", NULL);
    623     if (!cdrv) {
    624         return NULL;
    625     }
    626 
    627     dev = usb_new("usb-braille");
    628     qdev_prop_set_chr(&dev->qdev, "chardev", cdrv);
    629     return dev;
    630 }
    631 
    632 static const VMStateDescription vmstate_usb_serial = {
    633     .name = "usb-serial",
    634     .unmigratable = 1,
    635 };
    636 
    637 static Property serial_properties[] = {
    638     DEFINE_PROP_CHR("chardev", USBSerialState, cs),
    639     DEFINE_PROP_BOOL("always-plugged", USBSerialState, always_plugged, false),
    640     DEFINE_PROP_END_OF_LIST(),
    641 };
    642 
    643 static void usb_serial_dev_class_init(ObjectClass *klass, void *data)
    644 {
    645     DeviceClass *dc = DEVICE_CLASS(klass);
    646     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
    647 
    648     uc->realize        = usb_serial_realize;
    649     uc->handle_reset   = usb_serial_handle_reset;
    650     uc->handle_control = usb_serial_handle_control;
    651     uc->handle_data    = usb_serial_handle_data;
    652     dc->vmsd = &vmstate_usb_serial;
    653     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
    654 }
    655 
    656 static const TypeInfo usb_serial_dev_type_info = {
    657     .name = TYPE_USB_SERIAL,
    658     .parent = TYPE_USB_DEVICE,
    659     .instance_size = sizeof(USBSerialState),
    660     .abstract = true,
    661     .class_init = usb_serial_dev_class_init,
    662 };
    663 
    664 static void usb_serial_class_initfn(ObjectClass *klass, void *data)
    665 {
    666     DeviceClass *dc = DEVICE_CLASS(klass);
    667     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
    668 
    669     uc->product_desc   = "QEMU USB Serial";
    670     uc->usb_desc       = &desc_serial;
    671     device_class_set_props(dc, serial_properties);
    672 }
    673 
    674 static const TypeInfo serial_info = {
    675     .name          = "usb-serial",
    676     .parent        = TYPE_USB_SERIAL,
    677     .class_init    = usb_serial_class_initfn,
    678 };
    679 
    680 static Property braille_properties[] = {
    681     DEFINE_PROP_CHR("chardev", USBSerialState, cs),
    682     DEFINE_PROP_END_OF_LIST(),
    683 };
    684 
    685 static void usb_braille_class_initfn(ObjectClass *klass, void *data)
    686 {
    687     DeviceClass *dc = DEVICE_CLASS(klass);
    688     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
    689 
    690     uc->product_desc   = "QEMU USB Braille";
    691     uc->usb_desc       = &desc_braille;
    692     device_class_set_props(dc, braille_properties);
    693 }
    694 
    695 static const TypeInfo braille_info = {
    696     .name          = "usb-braille",
    697     .parent        = TYPE_USB_SERIAL,
    698     .class_init    = usb_braille_class_initfn,
    699 };
    700 
    701 static void usb_serial_register_types(void)
    702 {
    703     type_register_static(&usb_serial_dev_type_info);
    704     type_register_static(&serial_info);
    705     type_register_static(&braille_info);
    706     usb_legacy_register("usb-braille", "braille", usb_braille_init);
    707 }
    708 
    709 type_init(usb_serial_register_types)