qemu/chardev/char-serial.c
<<
>>
Prefs
   1/*
   2 * QEMU System Emulator
   3 *
   4 * Copyright (c) 2003-2008 Fabrice Bellard
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24
  25#include "qemu/osdep.h"
  26#include "qemu/module.h"
  27#include "qemu/option.h"
  28#include "qemu/sockets.h"
  29#include "io/channel-file.h"
  30#include "qapi/error.h"
  31
  32#ifdef _WIN32
  33#include "chardev/char-win.h"
  34#else
  35#include <sys/ioctl.h>
  36#include <termios.h>
  37#include "chardev/char-fd.h"
  38#endif
  39
  40#include "chardev/char-serial.h"
  41
  42#ifdef _WIN32
  43
  44static void qmp_chardev_open_serial(Chardev *chr,
  45                                    ChardevBackend *backend,
  46                                    bool *be_opened,
  47                                    Error **errp)
  48{
  49    ChardevHostdev *serial = backend->u.serial.data;
  50
  51    win_chr_serial_init(chr, serial->device, errp);
  52}
  53
  54#elif defined(__linux__) || defined(__sun__) || defined(__FreeBSD__)      \
  55    || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
  56    || defined(__GLIBC__)
  57
  58static void tty_serial_init(int fd, int speed,
  59                            int parity, int data_bits, int stop_bits)
  60{
  61    struct termios tty = {0};
  62    speed_t spd;
  63
  64#if 0
  65    printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n",
  66           speed, parity, data_bits, stop_bits);
  67#endif
  68    tcgetattr(fd, &tty);
  69
  70#define check_speed(val) \
  71    if (speed <= val) {  \
  72        spd = B##val;    \
  73        goto done;       \
  74    }
  75
  76    speed = speed * 10 / 11;
  77    check_speed(50);
  78    check_speed(75);
  79    check_speed(110);
  80    check_speed(134);
  81    check_speed(150);
  82    check_speed(200);
  83    check_speed(300);
  84    check_speed(600);
  85    check_speed(1200);
  86    check_speed(1800);
  87    check_speed(2400);
  88    check_speed(4800);
  89    check_speed(9600);
  90    check_speed(19200);
  91    check_speed(38400);
  92    /* Non-Posix values follow. They may be unsupported on some systems. */
  93    check_speed(57600);
  94    check_speed(115200);
  95#ifdef B230400
  96    check_speed(230400);
  97#endif
  98#ifdef B460800
  99    check_speed(460800);
 100#endif
 101#ifdef B500000
 102    check_speed(500000);
 103#endif
 104#ifdef B576000
 105    check_speed(576000);
 106#endif
 107#ifdef B921600
 108    check_speed(921600);
 109#endif
 110#ifdef B1000000
 111    check_speed(1000000);
 112#endif
 113#ifdef B1152000
 114    check_speed(1152000);
 115#endif
 116#ifdef B1500000
 117    check_speed(1500000);
 118#endif
 119#ifdef B2000000
 120    check_speed(2000000);
 121#endif
 122#ifdef B2500000
 123    check_speed(2500000);
 124#endif
 125#ifdef B3000000
 126    check_speed(3000000);
 127#endif
 128#ifdef B3500000
 129    check_speed(3500000);
 130#endif
 131#ifdef B4000000
 132    check_speed(4000000);
 133#endif
 134    spd = B115200;
 135
 136#undef check_speed
 137 done:
 138    cfsetispeed(&tty, spd);
 139    cfsetospeed(&tty, spd);
 140
 141    tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
 142                     | INLCR | IGNCR | ICRNL | IXON);
 143    tty.c_oflag &= ~OPOST;
 144    tty.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);
 145    tty.c_cflag &= ~(CSIZE | PARENB | PARODD | CRTSCTS | CSTOPB);
 146    switch (data_bits) {
 147    default:
 148    case 8:
 149        tty.c_cflag |= CS8;
 150        break;
 151    case 7:
 152        tty.c_cflag |= CS7;
 153        break;
 154    case 6:
 155        tty.c_cflag |= CS6;
 156        break;
 157    case 5:
 158        tty.c_cflag |= CS5;
 159        break;
 160    }
 161    switch (parity) {
 162    default:
 163    case 'N':
 164        break;
 165    case 'E':
 166        tty.c_cflag |= PARENB;
 167        break;
 168    case 'O':
 169        tty.c_cflag |= PARENB | PARODD;
 170        break;
 171    }
 172    if (stop_bits == 2) {
 173        tty.c_cflag |= CSTOPB;
 174    }
 175
 176    tcsetattr(fd, TCSANOW, &tty);
 177}
 178
 179static int tty_serial_ioctl(Chardev *chr, int cmd, void *arg)
 180{
 181    FDChardev *s = FD_CHARDEV(chr);
 182    QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc_in);
 183
 184    switch (cmd) {
 185    case CHR_IOCTL_SERIAL_SET_PARAMS:
 186        {
 187            QEMUSerialSetParams *ssp = arg;
 188            tty_serial_init(fioc->fd,
 189                            ssp->speed, ssp->parity,
 190                            ssp->data_bits, ssp->stop_bits);
 191        }
 192        break;
 193    case CHR_IOCTL_SERIAL_SET_BREAK:
 194        {
 195            int enable = *(int *)arg;
 196            if (enable) {
 197                tcsendbreak(fioc->fd, 1);
 198            }
 199        }
 200        break;
 201    case CHR_IOCTL_SERIAL_GET_TIOCM:
 202        {
 203            int sarg = 0;
 204            int *targ = (int *)arg;
 205            ioctl(fioc->fd, TIOCMGET, &sarg);
 206            *targ = 0;
 207            if (sarg & TIOCM_CTS) {
 208                *targ |= CHR_TIOCM_CTS;
 209            }
 210            if (sarg & TIOCM_CAR) {
 211                *targ |= CHR_TIOCM_CAR;
 212            }
 213            if (sarg & TIOCM_DSR) {
 214                *targ |= CHR_TIOCM_DSR;
 215            }
 216            if (sarg & TIOCM_RI) {
 217                *targ |= CHR_TIOCM_RI;
 218            }
 219            if (sarg & TIOCM_DTR) {
 220                *targ |= CHR_TIOCM_DTR;
 221            }
 222            if (sarg & TIOCM_RTS) {
 223                *targ |= CHR_TIOCM_RTS;
 224            }
 225        }
 226        break;
 227    case CHR_IOCTL_SERIAL_SET_TIOCM:
 228        {
 229            int sarg = *(int *)arg;
 230            int targ = 0;
 231            ioctl(fioc->fd, TIOCMGET, &targ);
 232            targ &= ~(CHR_TIOCM_CTS | CHR_TIOCM_CAR | CHR_TIOCM_DSR
 233                     | CHR_TIOCM_RI | CHR_TIOCM_DTR | CHR_TIOCM_RTS);
 234            if (sarg & CHR_TIOCM_CTS) {
 235                targ |= TIOCM_CTS;
 236            }
 237            if (sarg & CHR_TIOCM_CAR) {
 238                targ |= TIOCM_CAR;
 239            }
 240            if (sarg & CHR_TIOCM_DSR) {
 241                targ |= TIOCM_DSR;
 242            }
 243            if (sarg & CHR_TIOCM_RI) {
 244                targ |= TIOCM_RI;
 245            }
 246            if (sarg & CHR_TIOCM_DTR) {
 247                targ |= TIOCM_DTR;
 248            }
 249            if (sarg & CHR_TIOCM_RTS) {
 250                targ |= TIOCM_RTS;
 251            }
 252            ioctl(fioc->fd, TIOCMSET, &targ);
 253        }
 254        break;
 255    default:
 256        return -ENOTSUP;
 257    }
 258    return 0;
 259}
 260
 261static void qmp_chardev_open_serial(Chardev *chr,
 262                                    ChardevBackend *backend,
 263                                    bool *be_opened,
 264                                    Error **errp)
 265{
 266    ChardevHostdev *serial = backend->u.serial.data;
 267    int fd;
 268
 269    fd = qmp_chardev_open_file_source(serial->device, O_RDWR | O_NONBLOCK,
 270                                      errp);
 271    if (fd < 0) {
 272        return;
 273    }
 274    qemu_set_nonblock(fd);
 275    tty_serial_init(fd, 115200, 'N', 8, 1);
 276
 277    qemu_chr_open_fd(chr, fd, fd);
 278}
 279#endif /* __linux__ || __sun__ */
 280
 281#ifdef HAVE_CHARDEV_SERIAL
 282static void qemu_chr_parse_serial(QemuOpts *opts, ChardevBackend *backend,
 283                                  Error **errp)
 284{
 285    const char *device = qemu_opt_get(opts, "path");
 286    ChardevHostdev *serial;
 287
 288    if (device == NULL) {
 289        error_setg(errp, "chardev: serial/tty: no device path given");
 290        return;
 291    }
 292    backend->type = CHARDEV_BACKEND_KIND_SERIAL;
 293    serial = backend->u.serial.data = g_new0(ChardevHostdev, 1);
 294    qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(serial));
 295    serial->device = g_strdup(device);
 296}
 297
 298static void char_serial_class_init(ObjectClass *oc, void *data)
 299{
 300    ChardevClass *cc = CHARDEV_CLASS(oc);
 301
 302    cc->parse = qemu_chr_parse_serial;
 303    cc->open = qmp_chardev_open_serial;
 304#ifndef _WIN32
 305    cc->chr_ioctl = tty_serial_ioctl;
 306#endif
 307}
 308
 309
 310static const TypeInfo char_serial_type_info = {
 311    .name = TYPE_CHARDEV_SERIAL,
 312#ifdef _WIN32
 313    .parent = TYPE_CHARDEV_WIN,
 314#else
 315    .parent = TYPE_CHARDEV_FD,
 316#endif
 317    .class_init = char_serial_class_init,
 318};
 319
 320static void register_types(void)
 321{
 322    type_register_static(&char_serial_type_info);
 323}
 324
 325type_init(register_types);
 326
 327#endif
 328