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" 26*0b8fa32fSMarkus 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 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__) \ 562b2f23daSMarc-André Lureau || defined(__GLIBC__) 572b2f23daSMarc-André Lureau 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 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 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 } 2742b2f23daSMarc-André Lureau qemu_set_nonblock(fd); 2752b2f23daSMarc-André Lureau tty_serial_init(fd, 115200, 'N', 8, 1); 2762b2f23daSMarc-André Lureau 2772b2f23daSMarc-André Lureau qemu_chr_open_fd(chr, fd, fd); 2782b2f23daSMarc-André Lureau } 2792b2f23daSMarc-André Lureau #endif /* __linux__ || __sun__ */ 2802b2f23daSMarc-André Lureau 2812b2f23daSMarc-André Lureau #ifdef HAVE_CHARDEV_SERIAL 2822b2f23daSMarc-André Lureau static void qemu_chr_parse_serial(QemuOpts *opts, ChardevBackend *backend, 2832b2f23daSMarc-André Lureau Error **errp) 2842b2f23daSMarc-André Lureau { 2852b2f23daSMarc-André Lureau const char *device = qemu_opt_get(opts, "path"); 2862b2f23daSMarc-André Lureau ChardevHostdev *serial; 2872b2f23daSMarc-André Lureau 2882b2f23daSMarc-André Lureau if (device == NULL) { 2892b2f23daSMarc-André Lureau error_setg(errp, "chardev: serial/tty: no device path given"); 2902b2f23daSMarc-André Lureau return; 2912b2f23daSMarc-André Lureau } 2922b2f23daSMarc-André Lureau backend->type = CHARDEV_BACKEND_KIND_SERIAL; 2932b2f23daSMarc-André Lureau serial = backend->u.serial.data = g_new0(ChardevHostdev, 1); 2942b2f23daSMarc-André Lureau qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(serial)); 2952b2f23daSMarc-André Lureau serial->device = g_strdup(device); 2962b2f23daSMarc-André Lureau } 2972b2f23daSMarc-André Lureau 2982b2f23daSMarc-André Lureau static void char_serial_class_init(ObjectClass *oc, void *data) 2992b2f23daSMarc-André Lureau { 3002b2f23daSMarc-André Lureau ChardevClass *cc = CHARDEV_CLASS(oc); 3012b2f23daSMarc-André Lureau 3022b2f23daSMarc-André Lureau cc->parse = qemu_chr_parse_serial; 3032b2f23daSMarc-André Lureau cc->open = qmp_chardev_open_serial; 3042b2f23daSMarc-André Lureau #ifndef _WIN32 3052b2f23daSMarc-André Lureau cc->chr_ioctl = tty_serial_ioctl; 3062b2f23daSMarc-André Lureau #endif 3072b2f23daSMarc-André Lureau } 3082b2f23daSMarc-André Lureau 3092b2f23daSMarc-André Lureau 3102b2f23daSMarc-André Lureau static const TypeInfo char_serial_type_info = { 3112b2f23daSMarc-André Lureau .name = TYPE_CHARDEV_SERIAL, 3122b2f23daSMarc-André Lureau #ifdef _WIN32 3132b2f23daSMarc-André Lureau .parent = TYPE_CHARDEV_WIN, 3142b2f23daSMarc-André Lureau #else 3152b2f23daSMarc-André Lureau .parent = TYPE_CHARDEV_FD, 3162b2f23daSMarc-André Lureau #endif 3172b2f23daSMarc-André Lureau .class_init = char_serial_class_init, 3182b2f23daSMarc-André Lureau }; 3192b2f23daSMarc-André Lureau 3202b2f23daSMarc-André Lureau static void register_types(void) 3212b2f23daSMarc-André Lureau { 3222b2f23daSMarc-André Lureau type_register_static(&char_serial_type_info); 3232b2f23daSMarc-André Lureau } 3242b2f23daSMarc-André Lureau 3252b2f23daSMarc-André Lureau type_init(register_types); 3262b2f23daSMarc-André Lureau 3272b2f23daSMarc-André Lureau #endif 328