cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

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
     92struct 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"
    112OBJECT_DECLARE_SIMPLE_TYPE(USBSerialState, USB_SERIAL)
    113
    114enum {
    115    STR_MANUFACTURER = 1,
    116    STR_PRODUCT_SERIAL,
    117    STR_PRODUCT_BRAILLE,
    118    STR_SERIALNUMBER,
    119};
    120
    121static 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
    128static 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
    147static 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
    163static 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
    176static 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
    189static 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
    200static 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
    211static 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
    221static 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
    232static 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
    259static 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
    424static 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
    479static 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
    518static 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
    528static 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
    561static 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
    586static 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
    617static 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
    632static const VMStateDescription vmstate_usb_serial = {
    633    .name = "usb-serial",
    634    .unmigratable = 1,
    635};
    636
    637static 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
    643static 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
    656static 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
    664static 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
    674static const TypeInfo serial_info = {
    675    .name          = "usb-serial",
    676    .parent        = TYPE_USB_SERIAL,
    677    .class_init    = usb_serial_class_initfn,
    678};
    679
    680static Property braille_properties[] = {
    681    DEFINE_PROP_CHR("chardev", USBSerialState, cs),
    682    DEFINE_PROP_END_OF_LIST(),
    683};
    684
    685static 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
    695static const TypeInfo braille_info = {
    696    .name          = "usb-braille",
    697    .parent        = TYPE_USB_SERIAL,
    698    .class_init    = usb_braille_class_initfn,
    699};
    700
    701static 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
    709type_init(usb_serial_register_types)