xref: /qemu/chardev/char-serial.c (revision b84bb4df)
12b2f23daSMarc-André Lureau /*
22b2f23daSMarc-André Lureau  * QEMU System Emulator
32b2f23daSMarc-André Lureau  *
42b2f23daSMarc-André Lureau  * Copyright (c) 2003-2008 Fabrice Bellard
52b2f23daSMarc-André Lureau  *
62b2f23daSMarc-André Lureau  * Permission is hereby granted, free of charge, to any person obtaining a copy
72b2f23daSMarc-André Lureau  * of this software and associated documentation files (the "Software"), to deal
82b2f23daSMarc-André Lureau  * in the Software without restriction, including without limitation the rights
92b2f23daSMarc-André Lureau  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
102b2f23daSMarc-André Lureau  * copies of the Software, and to permit persons to whom the Software is
112b2f23daSMarc-André Lureau  * furnished to do so, subject to the following conditions:
122b2f23daSMarc-André Lureau  *
132b2f23daSMarc-André Lureau  * The above copyright notice and this permission notice shall be included in
142b2f23daSMarc-André Lureau  * all copies or substantial portions of the Software.
152b2f23daSMarc-André Lureau  *
162b2f23daSMarc-André Lureau  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
172b2f23daSMarc-André Lureau  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
182b2f23daSMarc-André Lureau  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
192b2f23daSMarc-André Lureau  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
202b2f23daSMarc-André Lureau  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
212b2f23daSMarc-André Lureau  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
222b2f23daSMarc-André Lureau  * THE SOFTWARE.
232b2f23daSMarc-André Lureau  */
24922a01a0SMarkus Armbruster 
252b2f23daSMarc-André Lureau #include "qemu/osdep.h"
260b8fa32fSMarkus Armbruster #include "qemu/module.h"
27922a01a0SMarkus Armbruster #include "qemu/option.h"
282b2f23daSMarc-André Lureau #include "qemu/sockets.h"
292b2f23daSMarc-André Lureau #include "io/channel-file.h"
302b2f23daSMarc-André Lureau #include "qapi/error.h"
312b2f23daSMarc-André Lureau 
322b2f23daSMarc-André Lureau #ifdef _WIN32
338228e353SMarc-André Lureau #include "chardev/char-win.h"
342b2f23daSMarc-André Lureau #else
352b2f23daSMarc-André Lureau #include <sys/ioctl.h>
362b2f23daSMarc-André Lureau #include <termios.h>
378228e353SMarc-André Lureau #include "chardev/char-fd.h"
382b2f23daSMarc-André Lureau #endif
392b2f23daSMarc-André Lureau 
408228e353SMarc-André Lureau #include "chardev/char-serial.h"
412b2f23daSMarc-André Lureau 
422b2f23daSMarc-André Lureau #ifdef _WIN32
432b2f23daSMarc-André Lureau 
qmp_chardev_open_serial(Chardev * chr,ChardevBackend * backend,bool * be_opened,Error ** errp)442b2f23daSMarc-André Lureau static void qmp_chardev_open_serial(Chardev *chr,
452b2f23daSMarc-André Lureau                                     ChardevBackend *backend,
462b2f23daSMarc-André Lureau                                     bool *be_opened,
472b2f23daSMarc-André Lureau                                     Error **errp)
482b2f23daSMarc-André Lureau {
492b2f23daSMarc-André Lureau     ChardevHostdev *serial = backend->u.serial.data;
502b2f23daSMarc-André Lureau 
51221e659cSMarc-André Lureau     win_chr_serial_init(chr, serial->device, errp);
522b2f23daSMarc-André Lureau }
532b2f23daSMarc-André Lureau 
542b2f23daSMarc-André Lureau #elif defined(__linux__) || defined(__sun__) || defined(__FreeBSD__)      \
552b2f23daSMarc-André Lureau     || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
56949da1ebSMikhail Gusarov     || defined(__GLIBC__) || defined(__APPLE__)
572b2f23daSMarc-André Lureau 
tty_serial_init(int fd,int speed,int parity,int data_bits,int stop_bits)582b2f23daSMarc-André Lureau static void tty_serial_init(int fd, int speed,
592b2f23daSMarc-André Lureau                             int parity, int data_bits, int stop_bits)
602b2f23daSMarc-André Lureau {
61211ef6c4SDaniel P. Berrangé     struct termios tty = {0};
622b2f23daSMarc-André Lureau     speed_t spd;
632b2f23daSMarc-André Lureau 
642b2f23daSMarc-André Lureau #if 0
652b2f23daSMarc-André Lureau     printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n",
662b2f23daSMarc-André Lureau            speed, parity, data_bits, stop_bits);
672b2f23daSMarc-André Lureau #endif
682b2f23daSMarc-André Lureau     tcgetattr(fd, &tty);
692b2f23daSMarc-André Lureau 
7019a4d43eSEric Blake #define check_speed(val) \
7119a4d43eSEric Blake     if (speed <= val) {  \
7219a4d43eSEric Blake         spd = B##val;    \
7319a4d43eSEric Blake         goto done;       \
7419a4d43eSEric Blake     }
7519a4d43eSEric Blake 
762b2f23daSMarc-André Lureau     speed = speed * 10 / 11;
772b2f23daSMarc-André Lureau     check_speed(50);
782b2f23daSMarc-André Lureau     check_speed(75);
792b2f23daSMarc-André Lureau     check_speed(110);
802b2f23daSMarc-André Lureau     check_speed(134);
812b2f23daSMarc-André Lureau     check_speed(150);
822b2f23daSMarc-André Lureau     check_speed(200);
832b2f23daSMarc-André Lureau     check_speed(300);
842b2f23daSMarc-André Lureau     check_speed(600);
852b2f23daSMarc-André Lureau     check_speed(1200);
862b2f23daSMarc-André Lureau     check_speed(1800);
872b2f23daSMarc-André Lureau     check_speed(2400);
882b2f23daSMarc-André Lureau     check_speed(4800);
892b2f23daSMarc-André Lureau     check_speed(9600);
902b2f23daSMarc-André Lureau     check_speed(19200);
912b2f23daSMarc-André Lureau     check_speed(38400);
922b2f23daSMarc-André Lureau     /* Non-Posix values follow. They may be unsupported on some systems. */
932b2f23daSMarc-André Lureau     check_speed(57600);
942b2f23daSMarc-André Lureau     check_speed(115200);
952b2f23daSMarc-André Lureau #ifdef B230400
962b2f23daSMarc-André Lureau     check_speed(230400);
972b2f23daSMarc-André Lureau #endif
982b2f23daSMarc-André Lureau #ifdef B460800
992b2f23daSMarc-André Lureau     check_speed(460800);
1002b2f23daSMarc-André Lureau #endif
1012b2f23daSMarc-André Lureau #ifdef B500000
1022b2f23daSMarc-André Lureau     check_speed(500000);
1032b2f23daSMarc-André Lureau #endif
1042b2f23daSMarc-André Lureau #ifdef B576000
1052b2f23daSMarc-André Lureau     check_speed(576000);
1062b2f23daSMarc-André Lureau #endif
1072b2f23daSMarc-André Lureau #ifdef B921600
1082b2f23daSMarc-André Lureau     check_speed(921600);
1092b2f23daSMarc-André Lureau #endif
1102b2f23daSMarc-André Lureau #ifdef B1000000
1112b2f23daSMarc-André Lureau     check_speed(1000000);
1122b2f23daSMarc-André Lureau #endif
1132b2f23daSMarc-André Lureau #ifdef B1152000
1142b2f23daSMarc-André Lureau     check_speed(1152000);
1152b2f23daSMarc-André Lureau #endif
1162b2f23daSMarc-André Lureau #ifdef B1500000
1172b2f23daSMarc-André Lureau     check_speed(1500000);
1182b2f23daSMarc-André Lureau #endif
1192b2f23daSMarc-André Lureau #ifdef B2000000
1202b2f23daSMarc-André Lureau     check_speed(2000000);
1212b2f23daSMarc-André Lureau #endif
1222b2f23daSMarc-André Lureau #ifdef B2500000
1232b2f23daSMarc-André Lureau     check_speed(2500000);
1242b2f23daSMarc-André Lureau #endif
1252b2f23daSMarc-André Lureau #ifdef B3000000
1262b2f23daSMarc-André Lureau     check_speed(3000000);
1272b2f23daSMarc-André Lureau #endif
1282b2f23daSMarc-André Lureau #ifdef B3500000
1292b2f23daSMarc-André Lureau     check_speed(3500000);
1302b2f23daSMarc-André Lureau #endif
1312b2f23daSMarc-André Lureau #ifdef B4000000
1322b2f23daSMarc-André Lureau     check_speed(4000000);
1332b2f23daSMarc-André Lureau #endif
1342b2f23daSMarc-André Lureau     spd = B115200;
1352b2f23daSMarc-André Lureau 
13619a4d43eSEric Blake #undef check_speed
13719a4d43eSEric Blake  done:
1382b2f23daSMarc-André Lureau     cfsetispeed(&tty, spd);
1392b2f23daSMarc-André Lureau     cfsetospeed(&tty, spd);
1402b2f23daSMarc-André Lureau 
1412b2f23daSMarc-André Lureau     tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
1422b2f23daSMarc-André Lureau                      | INLCR | IGNCR | ICRNL | IXON);
14312fb0ac0SPatryk Olszewski     tty.c_oflag &= ~OPOST;
1442b2f23daSMarc-André Lureau     tty.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);
1452b2f23daSMarc-André Lureau     tty.c_cflag &= ~(CSIZE | PARENB | PARODD | CRTSCTS | CSTOPB);
1462b2f23daSMarc-André Lureau     switch (data_bits) {
1472b2f23daSMarc-André Lureau     default:
1482b2f23daSMarc-André Lureau     case 8:
1492b2f23daSMarc-André Lureau         tty.c_cflag |= CS8;
1502b2f23daSMarc-André Lureau         break;
1512b2f23daSMarc-André Lureau     case 7:
1522b2f23daSMarc-André Lureau         tty.c_cflag |= CS7;
1532b2f23daSMarc-André Lureau         break;
1542b2f23daSMarc-André Lureau     case 6:
1552b2f23daSMarc-André Lureau         tty.c_cflag |= CS6;
1562b2f23daSMarc-André Lureau         break;
1572b2f23daSMarc-André Lureau     case 5:
1582b2f23daSMarc-André Lureau         tty.c_cflag |= CS5;
1592b2f23daSMarc-André Lureau         break;
1602b2f23daSMarc-André Lureau     }
1612b2f23daSMarc-André Lureau     switch (parity) {
1622b2f23daSMarc-André Lureau     default:
1632b2f23daSMarc-André Lureau     case 'N':
1642b2f23daSMarc-André Lureau         break;
1652b2f23daSMarc-André Lureau     case 'E':
1662b2f23daSMarc-André Lureau         tty.c_cflag |= PARENB;
1672b2f23daSMarc-André Lureau         break;
1682b2f23daSMarc-André Lureau     case 'O':
1692b2f23daSMarc-André Lureau         tty.c_cflag |= PARENB | PARODD;
1702b2f23daSMarc-André Lureau         break;
1712b2f23daSMarc-André Lureau     }
1722b2f23daSMarc-André Lureau     if (stop_bits == 2) {
1732b2f23daSMarc-André Lureau         tty.c_cflag |= CSTOPB;
1742b2f23daSMarc-André Lureau     }
1752b2f23daSMarc-André Lureau 
1762b2f23daSMarc-André Lureau     tcsetattr(fd, TCSANOW, &tty);
1772b2f23daSMarc-André Lureau }
1782b2f23daSMarc-André Lureau 
tty_serial_ioctl(Chardev * chr,int cmd,void * arg)1792b2f23daSMarc-André Lureau static int tty_serial_ioctl(Chardev *chr, int cmd, void *arg)
1802b2f23daSMarc-André Lureau {
1812b2f23daSMarc-André Lureau     FDChardev *s = FD_CHARDEV(chr);
1822b2f23daSMarc-André Lureau     QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc_in);
1832b2f23daSMarc-André Lureau 
1842b2f23daSMarc-André Lureau     switch (cmd) {
1852b2f23daSMarc-André Lureau     case CHR_IOCTL_SERIAL_SET_PARAMS:
1862b2f23daSMarc-André Lureau         {
1872b2f23daSMarc-André Lureau             QEMUSerialSetParams *ssp = arg;
1882b2f23daSMarc-André Lureau             tty_serial_init(fioc->fd,
1892b2f23daSMarc-André Lureau                             ssp->speed, ssp->parity,
1902b2f23daSMarc-André Lureau                             ssp->data_bits, ssp->stop_bits);
1912b2f23daSMarc-André Lureau         }
1922b2f23daSMarc-André Lureau         break;
1932b2f23daSMarc-André Lureau     case CHR_IOCTL_SERIAL_SET_BREAK:
1942b2f23daSMarc-André Lureau         {
1952b2f23daSMarc-André Lureau             int enable = *(int *)arg;
1962b2f23daSMarc-André Lureau             if (enable) {
1972b2f23daSMarc-André Lureau                 tcsendbreak(fioc->fd, 1);
1982b2f23daSMarc-André Lureau             }
1992b2f23daSMarc-André Lureau         }
2002b2f23daSMarc-André Lureau         break;
2012b2f23daSMarc-André Lureau     case CHR_IOCTL_SERIAL_GET_TIOCM:
2022b2f23daSMarc-André Lureau         {
2032b2f23daSMarc-André Lureau             int sarg = 0;
2042b2f23daSMarc-André Lureau             int *targ = (int *)arg;
2052b2f23daSMarc-André Lureau             ioctl(fioc->fd, TIOCMGET, &sarg);
2062b2f23daSMarc-André Lureau             *targ = 0;
2072b2f23daSMarc-André Lureau             if (sarg & TIOCM_CTS) {
2082b2f23daSMarc-André Lureau                 *targ |= CHR_TIOCM_CTS;
2092b2f23daSMarc-André Lureau             }
2102b2f23daSMarc-André Lureau             if (sarg & TIOCM_CAR) {
2112b2f23daSMarc-André Lureau                 *targ |= CHR_TIOCM_CAR;
2122b2f23daSMarc-André Lureau             }
2132b2f23daSMarc-André Lureau             if (sarg & TIOCM_DSR) {
2142b2f23daSMarc-André Lureau                 *targ |= CHR_TIOCM_DSR;
2152b2f23daSMarc-André Lureau             }
2162b2f23daSMarc-André Lureau             if (sarg & TIOCM_RI) {
2172b2f23daSMarc-André Lureau                 *targ |= CHR_TIOCM_RI;
2182b2f23daSMarc-André Lureau             }
2192b2f23daSMarc-André Lureau             if (sarg & TIOCM_DTR) {
2202b2f23daSMarc-André Lureau                 *targ |= CHR_TIOCM_DTR;
2212b2f23daSMarc-André Lureau             }
2222b2f23daSMarc-André Lureau             if (sarg & TIOCM_RTS) {
2232b2f23daSMarc-André Lureau                 *targ |= CHR_TIOCM_RTS;
2242b2f23daSMarc-André Lureau             }
2252b2f23daSMarc-André Lureau         }
2262b2f23daSMarc-André Lureau         break;
2272b2f23daSMarc-André Lureau     case CHR_IOCTL_SERIAL_SET_TIOCM:
2282b2f23daSMarc-André Lureau         {
2292b2f23daSMarc-André Lureau             int sarg = *(int *)arg;
2302b2f23daSMarc-André Lureau             int targ = 0;
2312b2f23daSMarc-André Lureau             ioctl(fioc->fd, TIOCMGET, &targ);
2322b2f23daSMarc-André Lureau             targ &= ~(CHR_TIOCM_CTS | CHR_TIOCM_CAR | CHR_TIOCM_DSR
2332b2f23daSMarc-André Lureau                      | CHR_TIOCM_RI | CHR_TIOCM_DTR | CHR_TIOCM_RTS);
2342b2f23daSMarc-André Lureau             if (sarg & CHR_TIOCM_CTS) {
2352b2f23daSMarc-André Lureau                 targ |= TIOCM_CTS;
2362b2f23daSMarc-André Lureau             }
2372b2f23daSMarc-André Lureau             if (sarg & CHR_TIOCM_CAR) {
2382b2f23daSMarc-André Lureau                 targ |= TIOCM_CAR;
2392b2f23daSMarc-André Lureau             }
2402b2f23daSMarc-André Lureau             if (sarg & CHR_TIOCM_DSR) {
2412b2f23daSMarc-André Lureau                 targ |= TIOCM_DSR;
2422b2f23daSMarc-André Lureau             }
2432b2f23daSMarc-André Lureau             if (sarg & CHR_TIOCM_RI) {
2442b2f23daSMarc-André Lureau                 targ |= TIOCM_RI;
2452b2f23daSMarc-André Lureau             }
2462b2f23daSMarc-André Lureau             if (sarg & CHR_TIOCM_DTR) {
2472b2f23daSMarc-André Lureau                 targ |= TIOCM_DTR;
2482b2f23daSMarc-André Lureau             }
2492b2f23daSMarc-André Lureau             if (sarg & CHR_TIOCM_RTS) {
2502b2f23daSMarc-André Lureau                 targ |= TIOCM_RTS;
2512b2f23daSMarc-André Lureau             }
2522b2f23daSMarc-André Lureau             ioctl(fioc->fd, TIOCMSET, &targ);
2532b2f23daSMarc-André Lureau         }
2542b2f23daSMarc-André Lureau         break;
2552b2f23daSMarc-André Lureau     default:
2562b2f23daSMarc-André Lureau         return -ENOTSUP;
2572b2f23daSMarc-André Lureau     }
2582b2f23daSMarc-André Lureau     return 0;
2592b2f23daSMarc-André Lureau }
2602b2f23daSMarc-André Lureau 
qmp_chardev_open_serial(Chardev * chr,ChardevBackend * backend,bool * be_opened,Error ** errp)2612b2f23daSMarc-André Lureau static void qmp_chardev_open_serial(Chardev *chr,
2622b2f23daSMarc-André Lureau                                     ChardevBackend *backend,
2632b2f23daSMarc-André Lureau                                     bool *be_opened,
2642b2f23daSMarc-André Lureau                                     Error **errp)
2652b2f23daSMarc-André Lureau {
2662b2f23daSMarc-André Lureau     ChardevHostdev *serial = backend->u.serial.data;
2672b2f23daSMarc-André Lureau     int fd;
2682b2f23daSMarc-André Lureau 
26976b004d1SDr. David Alan Gilbert     fd = qmp_chardev_open_file_source(serial->device, O_RDWR | O_NONBLOCK,
27076b004d1SDr. David Alan Gilbert                                       errp);
2712b2f23daSMarc-André Lureau     if (fd < 0) {
2722b2f23daSMarc-André Lureau         return;
2732b2f23daSMarc-André Lureau     }
274*b84bb4dfSMarc-André Lureau     if (!g_unix_set_fd_nonblocking(fd, true, NULL)) {
275*b84bb4dfSMarc-André Lureau         error_setg_errno(errp, errno, "Failed to set FD nonblocking");
276*b84bb4dfSMarc-André Lureau         return;
277*b84bb4dfSMarc-André Lureau     }
2782b2f23daSMarc-André Lureau     tty_serial_init(fd, 115200, 'N', 8, 1);
2792b2f23daSMarc-André Lureau 
2802b2f23daSMarc-André Lureau     qemu_chr_open_fd(chr, fd, fd);
2812b2f23daSMarc-André Lureau }
2822b2f23daSMarc-André Lureau #endif /* __linux__ || __sun__ */
2832b2f23daSMarc-André Lureau 
2842b2f23daSMarc-André Lureau #ifdef HAVE_CHARDEV_SERIAL
qemu_chr_parse_serial(QemuOpts * opts,ChardevBackend * backend,Error ** errp)2852b2f23daSMarc-André Lureau static void qemu_chr_parse_serial(QemuOpts *opts, ChardevBackend *backend,
2862b2f23daSMarc-André Lureau                                   Error **errp)
2872b2f23daSMarc-André Lureau {
2882b2f23daSMarc-André Lureau     const char *device = qemu_opt_get(opts, "path");
2892b2f23daSMarc-André Lureau     ChardevHostdev *serial;
2902b2f23daSMarc-André Lureau 
2912b2f23daSMarc-André Lureau     if (device == NULL) {
2922b2f23daSMarc-André Lureau         error_setg(errp, "chardev: serial/tty: no device path given");
2932b2f23daSMarc-André Lureau         return;
2942b2f23daSMarc-André Lureau     }
2952b2f23daSMarc-André Lureau     backend->type = CHARDEV_BACKEND_KIND_SERIAL;
2962b2f23daSMarc-André Lureau     serial = backend->u.serial.data = g_new0(ChardevHostdev, 1);
2972b2f23daSMarc-André Lureau     qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(serial));
2982b2f23daSMarc-André Lureau     serial->device = g_strdup(device);
2992b2f23daSMarc-André Lureau }
3002b2f23daSMarc-André Lureau 
char_serial_class_init(ObjectClass * oc,void * data)3012b2f23daSMarc-André Lureau static void char_serial_class_init(ObjectClass *oc, void *data)
3022b2f23daSMarc-André Lureau {
3032b2f23daSMarc-André Lureau     ChardevClass *cc = CHARDEV_CLASS(oc);
3042b2f23daSMarc-André Lureau 
3052b2f23daSMarc-André Lureau     cc->parse = qemu_chr_parse_serial;
3062b2f23daSMarc-André Lureau     cc->open = qmp_chardev_open_serial;
3072b2f23daSMarc-André Lureau #ifndef _WIN32
3082b2f23daSMarc-André Lureau     cc->chr_ioctl = tty_serial_ioctl;
3092b2f23daSMarc-André Lureau #endif
3102b2f23daSMarc-André Lureau }
3112b2f23daSMarc-André Lureau 
3122b2f23daSMarc-André Lureau 
3132b2f23daSMarc-André Lureau static const TypeInfo char_serial_type_info = {
3142b2f23daSMarc-André Lureau     .name = TYPE_CHARDEV_SERIAL,
3152b2f23daSMarc-André Lureau #ifdef _WIN32
3162b2f23daSMarc-André Lureau     .parent = TYPE_CHARDEV_WIN,
3172b2f23daSMarc-André Lureau #else
3182b2f23daSMarc-André Lureau     .parent = TYPE_CHARDEV_FD,
3192b2f23daSMarc-André Lureau #endif
3202b2f23daSMarc-André Lureau     .class_init = char_serial_class_init,
3212b2f23daSMarc-André Lureau };
3222b2f23daSMarc-André Lureau 
register_types(void)3232b2f23daSMarc-André Lureau static void register_types(void)
3242b2f23daSMarc-André Lureau {
3252b2f23daSMarc-André Lureau     type_register_static(&char_serial_type_info);
3262b2f23daSMarc-André Lureau }
3272b2f23daSMarc-André Lureau 
3282b2f23daSMarc-André Lureau type_init(register_types);
3292b2f23daSMarc-André Lureau 
3302b2f23daSMarc-André Lureau #endif
331