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