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#include "qemu/osdep.h"
  25#include "qemu/sockets.h"
  26#include "io/channel-file.h"
  27#include "qapi/error.h"
  28
  29#ifdef _WIN32
  30#include "chardev/char-win.h"
  31#else
  32#include <sys/ioctl.h>
  33#include <termios.h>
  34#include "chardev/char-fd.h"
  35#endif
  36
  37#include "chardev/char-serial.h"
  38
  39#ifdef _WIN32
  40
  41static void qmp_chardev_open_serial(Chardev *chr,
  42                                    ChardevBackend *backend,
  43                                    bool *be_opened,
  44                                    Error **errp)
  45{
  46    ChardevHostdev *serial = backend->u.serial.data;
  47
  48    win_chr_serial_init(chr, serial->device, errp);
  49}
  50
  51#elif defined(__linux__) || defined(__sun__) || defined(__FreeBSD__)      \
  52    || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
  53    || defined(__GLIBC__)
  54
  55static void tty_serial_init(int fd, int speed,
  56                            int parity, int data_bits, int stop_bits)
  57{
  58    struct termios tty;
  59    speed_t spd;
  60
  61#if 0
  62    printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n",
  63           speed, parity, data_bits, stop_bits);
  64#endif
  65    tcgetattr(fd, &tty);
  66
  67#define check_speed(val) if (speed <= val) { spd = B##val; break; }
  68    speed = speed * 10 / 11;
  69    do {
  70        check_speed(50);
  71        check_speed(75);
  72        check_speed(110);
  73        check_speed(134);
  74        check_speed(150);
  75        check_speed(200);
  76        check_speed(300);
  77        check_speed(600);
  78        check_speed(1200);
  79        check_speed(1800);
  80        check_speed(2400);
  81        check_speed(4800);
  82        check_speed(9600);
  83        check_speed(19200);
  84        check_speed(38400);
  85        /* Non-Posix values follow. They may be unsupported on some systems. */
  86        check_speed(57600);
  87        check_speed(115200);
  88#ifdef B230400
  89        check_speed(230400);
  90#endif
  91#ifdef B460800
  92        check_speed(460800);
  93#endif
  94#ifdef B500000
  95        check_speed(500000);
  96#endif
  97#ifdef B576000
  98        check_speed(576000);
  99#endif
 100#ifdef B921600
 101        check_speed(921600);
 102#endif
 103#ifdef B1000000
 104        check_speed(1000000);
 105#endif
 106#ifdef B1152000
 107        check_speed(1152000);
 108#endif
 109#ifdef B1500000
 110        check_speed(1500000);
 111#endif
 112#ifdef B2000000
 113        check_speed(2000000);
 114#endif
 115#ifdef B2500000
 116        check_speed(2500000);
 117#endif
 118#ifdef B3000000
 119        check_speed(3000000);
 120#endif
 121#ifdef B3500000
 122        check_speed(3500000);
 123#endif
 124#ifdef B4000000
 125        check_speed(4000000);
 126#endif
 127        spd = B115200;
 128    } while (0);
 129
 130    cfsetispeed(&tty, spd);
 131    cfsetospeed(&tty, spd);
 132
 133    tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
 134                     | INLCR | IGNCR | ICRNL | IXON);
 135    tty.c_oflag |= OPOST;
 136    tty.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);
 137    tty.c_cflag &= ~(CSIZE | PARENB | PARODD | CRTSCTS | CSTOPB);
 138    switch (data_bits) {
 139    default:
 140    case 8:
 141        tty.c_cflag |= CS8;
 142        break;
 143    case 7:
 144        tty.c_cflag |= CS7;
 145        break;
 146    case 6:
 147        tty.c_cflag |= CS6;
 148        break;
 149    case 5:
 150        tty.c_cflag |= CS5;
 151        break;
 152    }
 153    switch (parity) {
 154    default:
 155    case 'N':
 156        break;
 157    case 'E':
 158        tty.c_cflag |= PARENB;
 159        break;
 160    case 'O':
 161        tty.c_cflag |= PARENB | PARODD;
 162        break;
 163    }
 164    if (stop_bits == 2) {
 165        tty.c_cflag |= CSTOPB;
 166    }
 167
 168    tcsetattr(fd, TCSANOW, &tty);
 169}
 170
 171static int tty_serial_ioctl(Chardev *chr, int cmd, void *arg)
 172{
 173    FDChardev *s = FD_CHARDEV(chr);
 174    QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc_in);
 175
 176    switch (cmd) {
 177    case CHR_IOCTL_SERIAL_SET_PARAMS:
 178        {
 179            QEMUSerialSetParams *ssp = arg;
 180            tty_serial_init(fioc->fd,
 181                            ssp->speed, ssp->parity,
 182                            ssp->data_bits, ssp->stop_bits);
 183        }
 184        break;
 185    case CHR_IOCTL_SERIAL_SET_BREAK:
 186        {
 187            int enable = *(int *)arg;
 188            if (enable) {
 189                tcsendbreak(fioc->fd, 1);
 190            }
 191        }
 192        break;
 193    case CHR_IOCTL_SERIAL_GET_TIOCM:
 194        {
 195            int sarg = 0;
 196            int *targ = (int *)arg;
 197            ioctl(fioc->fd, TIOCMGET, &sarg);
 198            *targ = 0;
 199            if (sarg & TIOCM_CTS) {
 200                *targ |= CHR_TIOCM_CTS;
 201            }
 202            if (sarg & TIOCM_CAR) {
 203                *targ |= CHR_TIOCM_CAR;
 204            }
 205            if (sarg & TIOCM_DSR) {
 206                *targ |= CHR_TIOCM_DSR;
 207            }
 208            if (sarg & TIOCM_RI) {
 209                *targ |= CHR_TIOCM_RI;
 210            }
 211            if (sarg & TIOCM_DTR) {
 212                *targ |= CHR_TIOCM_DTR;
 213            }
 214            if (sarg & TIOCM_RTS) {
 215                *targ |= CHR_TIOCM_RTS;
 216            }
 217        }
 218        break;
 219    case CHR_IOCTL_SERIAL_SET_TIOCM:
 220        {
 221            int sarg = *(int *)arg;
 222            int targ = 0;
 223            ioctl(fioc->fd, TIOCMGET, &targ);
 224            targ &= ~(CHR_TIOCM_CTS | CHR_TIOCM_CAR | CHR_TIOCM_DSR
 225                     | CHR_TIOCM_RI | CHR_TIOCM_DTR | CHR_TIOCM_RTS);
 226            if (sarg & CHR_TIOCM_CTS) {
 227                targ |= TIOCM_CTS;
 228            }
 229            if (sarg & CHR_TIOCM_CAR) {
 230                targ |= TIOCM_CAR;
 231            }
 232            if (sarg & CHR_TIOCM_DSR) {
 233                targ |= TIOCM_DSR;
 234            }
 235            if (sarg & CHR_TIOCM_RI) {
 236                targ |= TIOCM_RI;
 237            }
 238            if (sarg & CHR_TIOCM_DTR) {
 239                targ |= TIOCM_DTR;
 240            }
 241            if (sarg & CHR_TIOCM_RTS) {
 242                targ |= TIOCM_RTS;
 243            }
 244            ioctl(fioc->fd, TIOCMSET, &targ);
 245        }
 246        break;
 247    default:
 248        return -ENOTSUP;
 249    }
 250    return 0;
 251}
 252
 253static void qmp_chardev_open_serial(Chardev *chr,
 254                                    ChardevBackend *backend,
 255                                    bool *be_opened,
 256                                    Error **errp)
 257{
 258    ChardevHostdev *serial = backend->u.serial.data;
 259    int fd;
 260
 261    fd = qmp_chardev_open_file_source(serial->device, O_RDWR, errp);
 262    if (fd < 0) {
 263        return;
 264    }
 265    qemu_set_nonblock(fd);
 266    tty_serial_init(fd, 115200, 'N', 8, 1);
 267
 268    qemu_chr_open_fd(chr, fd, fd);
 269}
 270#endif /* __linux__ || __sun__ */
 271
 272#ifdef HAVE_CHARDEV_SERIAL
 273static void qemu_chr_parse_serial(QemuOpts *opts, ChardevBackend *backend,
 274                                  Error **errp)
 275{
 276    const char *device = qemu_opt_get(opts, "path");
 277    ChardevHostdev *serial;
 278
 279    if (device == NULL) {
 280        error_setg(errp, "chardev: serial/tty: no device path given");
 281        return;
 282    }
 283    backend->type = CHARDEV_BACKEND_KIND_SERIAL;
 284    serial = backend->u.serial.data = g_new0(ChardevHostdev, 1);
 285    qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(serial));
 286    serial->device = g_strdup(device);
 287}
 288
 289static void char_serial_class_init(ObjectClass *oc, void *data)
 290{
 291    ChardevClass *cc = CHARDEV_CLASS(oc);
 292
 293    cc->parse = qemu_chr_parse_serial;
 294    cc->open = qmp_chardev_open_serial;
 295#ifndef _WIN32
 296    cc->chr_ioctl = tty_serial_ioctl;
 297#endif
 298}
 299
 300
 301static const TypeInfo char_serial_type_info = {
 302    .name = TYPE_CHARDEV_SERIAL,
 303#ifdef _WIN32
 304    .parent = TYPE_CHARDEV_WIN,
 305#else
 306    .parent = TYPE_CHARDEV_FD,
 307#endif
 308    .class_init = char_serial_class_init,
 309};
 310
 311static void register_types(void)
 312{
 313    type_register_static(&char_serial_type_info);
 314}
 315
 316type_init(register_types);
 317
 318#endif
 319