qemu/hw/usb/dev-serial.c
<<
>>
Prefs
   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)
 710