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