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