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 */ 24*922a01a0SMarkus Armbruster 252b2f23daSMarc-André Lureau #include "qemu/osdep.h" 26*922a01a0SMarkus Armbruster #include "qemu/option.h" 272b2f23daSMarc-André Lureau #include "qemu/sockets.h" 282b2f23daSMarc-André Lureau #include "io/channel-file.h" 292b2f23daSMarc-André Lureau #include "qapi/error.h" 302b2f23daSMarc-André Lureau 312b2f23daSMarc-André Lureau #ifdef _WIN32 328228e353SMarc-André Lureau #include "chardev/char-win.h" 332b2f23daSMarc-André Lureau #else 342b2f23daSMarc-André Lureau #include <sys/ioctl.h> 352b2f23daSMarc-André Lureau #include <termios.h> 368228e353SMarc-André Lureau #include "chardev/char-fd.h" 372b2f23daSMarc-André Lureau #endif 382b2f23daSMarc-André Lureau 398228e353SMarc-André Lureau #include "chardev/char-serial.h" 402b2f23daSMarc-André Lureau 412b2f23daSMarc-André Lureau #ifdef _WIN32 422b2f23daSMarc-André Lureau 432b2f23daSMarc-André Lureau static void qmp_chardev_open_serial(Chardev *chr, 442b2f23daSMarc-André Lureau ChardevBackend *backend, 452b2f23daSMarc-André Lureau bool *be_opened, 462b2f23daSMarc-André Lureau Error **errp) 472b2f23daSMarc-André Lureau { 482b2f23daSMarc-André Lureau ChardevHostdev *serial = backend->u.serial.data; 492b2f23daSMarc-André Lureau 50221e659cSMarc-André Lureau win_chr_serial_init(chr, serial->device, errp); 512b2f23daSMarc-André Lureau } 522b2f23daSMarc-André Lureau 532b2f23daSMarc-André Lureau #elif defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \ 542b2f23daSMarc-André Lureau || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \ 552b2f23daSMarc-André Lureau || defined(__GLIBC__) 562b2f23daSMarc-André Lureau 572b2f23daSMarc-André Lureau static void tty_serial_init(int fd, int speed, 582b2f23daSMarc-André Lureau int parity, int data_bits, int stop_bits) 592b2f23daSMarc-André Lureau { 602b2f23daSMarc-André Lureau struct termios tty; 612b2f23daSMarc-André Lureau speed_t spd; 622b2f23daSMarc-André Lureau 632b2f23daSMarc-André Lureau #if 0 642b2f23daSMarc-André Lureau printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n", 652b2f23daSMarc-André Lureau speed, parity, data_bits, stop_bits); 662b2f23daSMarc-André Lureau #endif 672b2f23daSMarc-André Lureau tcgetattr(fd, &tty); 682b2f23daSMarc-André Lureau 6919a4d43eSEric Blake #define check_speed(val) \ 7019a4d43eSEric Blake if (speed <= val) { \ 7119a4d43eSEric Blake spd = B##val; \ 7219a4d43eSEric Blake goto done; \ 7319a4d43eSEric Blake } 7419a4d43eSEric Blake 752b2f23daSMarc-André Lureau speed = speed * 10 / 11; 762b2f23daSMarc-André Lureau check_speed(50); 772b2f23daSMarc-André Lureau check_speed(75); 782b2f23daSMarc-André Lureau check_speed(110); 792b2f23daSMarc-André Lureau check_speed(134); 802b2f23daSMarc-André Lureau check_speed(150); 812b2f23daSMarc-André Lureau check_speed(200); 822b2f23daSMarc-André Lureau check_speed(300); 832b2f23daSMarc-André Lureau check_speed(600); 842b2f23daSMarc-André Lureau check_speed(1200); 852b2f23daSMarc-André Lureau check_speed(1800); 862b2f23daSMarc-André Lureau check_speed(2400); 872b2f23daSMarc-André Lureau check_speed(4800); 882b2f23daSMarc-André Lureau check_speed(9600); 892b2f23daSMarc-André Lureau check_speed(19200); 902b2f23daSMarc-André Lureau check_speed(38400); 912b2f23daSMarc-André Lureau /* Non-Posix values follow. They may be unsupported on some systems. */ 922b2f23daSMarc-André Lureau check_speed(57600); 932b2f23daSMarc-André Lureau check_speed(115200); 942b2f23daSMarc-André Lureau #ifdef B230400 952b2f23daSMarc-André Lureau check_speed(230400); 962b2f23daSMarc-André Lureau #endif 972b2f23daSMarc-André Lureau #ifdef B460800 982b2f23daSMarc-André Lureau check_speed(460800); 992b2f23daSMarc-André Lureau #endif 1002b2f23daSMarc-André Lureau #ifdef B500000 1012b2f23daSMarc-André Lureau check_speed(500000); 1022b2f23daSMarc-André Lureau #endif 1032b2f23daSMarc-André Lureau #ifdef B576000 1042b2f23daSMarc-André Lureau check_speed(576000); 1052b2f23daSMarc-André Lureau #endif 1062b2f23daSMarc-André Lureau #ifdef B921600 1072b2f23daSMarc-André Lureau check_speed(921600); 1082b2f23daSMarc-André Lureau #endif 1092b2f23daSMarc-André Lureau #ifdef B1000000 1102b2f23daSMarc-André Lureau check_speed(1000000); 1112b2f23daSMarc-André Lureau #endif 1122b2f23daSMarc-André Lureau #ifdef B1152000 1132b2f23daSMarc-André Lureau check_speed(1152000); 1142b2f23daSMarc-André Lureau #endif 1152b2f23daSMarc-André Lureau #ifdef B1500000 1162b2f23daSMarc-André Lureau check_speed(1500000); 1172b2f23daSMarc-André Lureau #endif 1182b2f23daSMarc-André Lureau #ifdef B2000000 1192b2f23daSMarc-André Lureau check_speed(2000000); 1202b2f23daSMarc-André Lureau #endif 1212b2f23daSMarc-André Lureau #ifdef B2500000 1222b2f23daSMarc-André Lureau check_speed(2500000); 1232b2f23daSMarc-André Lureau #endif 1242b2f23daSMarc-André Lureau #ifdef B3000000 1252b2f23daSMarc-André Lureau check_speed(3000000); 1262b2f23daSMarc-André Lureau #endif 1272b2f23daSMarc-André Lureau #ifdef B3500000 1282b2f23daSMarc-André Lureau check_speed(3500000); 1292b2f23daSMarc-André Lureau #endif 1302b2f23daSMarc-André Lureau #ifdef B4000000 1312b2f23daSMarc-André Lureau check_speed(4000000); 1322b2f23daSMarc-André Lureau #endif 1332b2f23daSMarc-André Lureau spd = B115200; 1342b2f23daSMarc-André Lureau 13519a4d43eSEric Blake #undef check_speed 13619a4d43eSEric Blake done: 1372b2f23daSMarc-André Lureau cfsetispeed(&tty, spd); 1382b2f23daSMarc-André Lureau cfsetospeed(&tty, spd); 1392b2f23daSMarc-André Lureau 1402b2f23daSMarc-André Lureau tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP 1412b2f23daSMarc-André Lureau | INLCR | IGNCR | ICRNL | IXON); 1422b2f23daSMarc-André Lureau tty.c_oflag |= OPOST; 1432b2f23daSMarc-André Lureau tty.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG); 1442b2f23daSMarc-André Lureau tty.c_cflag &= ~(CSIZE | PARENB | PARODD | CRTSCTS | CSTOPB); 1452b2f23daSMarc-André Lureau switch (data_bits) { 1462b2f23daSMarc-André Lureau default: 1472b2f23daSMarc-André Lureau case 8: 1482b2f23daSMarc-André Lureau tty.c_cflag |= CS8; 1492b2f23daSMarc-André Lureau break; 1502b2f23daSMarc-André Lureau case 7: 1512b2f23daSMarc-André Lureau tty.c_cflag |= CS7; 1522b2f23daSMarc-André Lureau break; 1532b2f23daSMarc-André Lureau case 6: 1542b2f23daSMarc-André Lureau tty.c_cflag |= CS6; 1552b2f23daSMarc-André Lureau break; 1562b2f23daSMarc-André Lureau case 5: 1572b2f23daSMarc-André Lureau tty.c_cflag |= CS5; 1582b2f23daSMarc-André Lureau break; 1592b2f23daSMarc-André Lureau } 1602b2f23daSMarc-André Lureau switch (parity) { 1612b2f23daSMarc-André Lureau default: 1622b2f23daSMarc-André Lureau case 'N': 1632b2f23daSMarc-André Lureau break; 1642b2f23daSMarc-André Lureau case 'E': 1652b2f23daSMarc-André Lureau tty.c_cflag |= PARENB; 1662b2f23daSMarc-André Lureau break; 1672b2f23daSMarc-André Lureau case 'O': 1682b2f23daSMarc-André Lureau tty.c_cflag |= PARENB | PARODD; 1692b2f23daSMarc-André Lureau break; 1702b2f23daSMarc-André Lureau } 1712b2f23daSMarc-André Lureau if (stop_bits == 2) { 1722b2f23daSMarc-André Lureau tty.c_cflag |= CSTOPB; 1732b2f23daSMarc-André Lureau } 1742b2f23daSMarc-André Lureau 1752b2f23daSMarc-André Lureau tcsetattr(fd, TCSANOW, &tty); 1762b2f23daSMarc-André Lureau } 1772b2f23daSMarc-André Lureau 1782b2f23daSMarc-André Lureau static int tty_serial_ioctl(Chardev *chr, int cmd, void *arg) 1792b2f23daSMarc-André Lureau { 1802b2f23daSMarc-André Lureau FDChardev *s = FD_CHARDEV(chr); 1812b2f23daSMarc-André Lureau QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc_in); 1822b2f23daSMarc-André Lureau 1832b2f23daSMarc-André Lureau switch (cmd) { 1842b2f23daSMarc-André Lureau case CHR_IOCTL_SERIAL_SET_PARAMS: 1852b2f23daSMarc-André Lureau { 1862b2f23daSMarc-André Lureau QEMUSerialSetParams *ssp = arg; 1872b2f23daSMarc-André Lureau tty_serial_init(fioc->fd, 1882b2f23daSMarc-André Lureau ssp->speed, ssp->parity, 1892b2f23daSMarc-André Lureau ssp->data_bits, ssp->stop_bits); 1902b2f23daSMarc-André Lureau } 1912b2f23daSMarc-André Lureau break; 1922b2f23daSMarc-André Lureau case CHR_IOCTL_SERIAL_SET_BREAK: 1932b2f23daSMarc-André Lureau { 1942b2f23daSMarc-André Lureau int enable = *(int *)arg; 1952b2f23daSMarc-André Lureau if (enable) { 1962b2f23daSMarc-André Lureau tcsendbreak(fioc->fd, 1); 1972b2f23daSMarc-André Lureau } 1982b2f23daSMarc-André Lureau } 1992b2f23daSMarc-André Lureau break; 2002b2f23daSMarc-André Lureau case CHR_IOCTL_SERIAL_GET_TIOCM: 2012b2f23daSMarc-André Lureau { 2022b2f23daSMarc-André Lureau int sarg = 0; 2032b2f23daSMarc-André Lureau int *targ = (int *)arg; 2042b2f23daSMarc-André Lureau ioctl(fioc->fd, TIOCMGET, &sarg); 2052b2f23daSMarc-André Lureau *targ = 0; 2062b2f23daSMarc-André Lureau if (sarg & TIOCM_CTS) { 2072b2f23daSMarc-André Lureau *targ |= CHR_TIOCM_CTS; 2082b2f23daSMarc-André Lureau } 2092b2f23daSMarc-André Lureau if (sarg & TIOCM_CAR) { 2102b2f23daSMarc-André Lureau *targ |= CHR_TIOCM_CAR; 2112b2f23daSMarc-André Lureau } 2122b2f23daSMarc-André Lureau if (sarg & TIOCM_DSR) { 2132b2f23daSMarc-André Lureau *targ |= CHR_TIOCM_DSR; 2142b2f23daSMarc-André Lureau } 2152b2f23daSMarc-André Lureau if (sarg & TIOCM_RI) { 2162b2f23daSMarc-André Lureau *targ |= CHR_TIOCM_RI; 2172b2f23daSMarc-André Lureau } 2182b2f23daSMarc-André Lureau if (sarg & TIOCM_DTR) { 2192b2f23daSMarc-André Lureau *targ |= CHR_TIOCM_DTR; 2202b2f23daSMarc-André Lureau } 2212b2f23daSMarc-André Lureau if (sarg & TIOCM_RTS) { 2222b2f23daSMarc-André Lureau *targ |= CHR_TIOCM_RTS; 2232b2f23daSMarc-André Lureau } 2242b2f23daSMarc-André Lureau } 2252b2f23daSMarc-André Lureau break; 2262b2f23daSMarc-André Lureau case CHR_IOCTL_SERIAL_SET_TIOCM: 2272b2f23daSMarc-André Lureau { 2282b2f23daSMarc-André Lureau int sarg = *(int *)arg; 2292b2f23daSMarc-André Lureau int targ = 0; 2302b2f23daSMarc-André Lureau ioctl(fioc->fd, TIOCMGET, &targ); 2312b2f23daSMarc-André Lureau targ &= ~(CHR_TIOCM_CTS | CHR_TIOCM_CAR | CHR_TIOCM_DSR 2322b2f23daSMarc-André Lureau | CHR_TIOCM_RI | CHR_TIOCM_DTR | CHR_TIOCM_RTS); 2332b2f23daSMarc-André Lureau if (sarg & CHR_TIOCM_CTS) { 2342b2f23daSMarc-André Lureau targ |= TIOCM_CTS; 2352b2f23daSMarc-André Lureau } 2362b2f23daSMarc-André Lureau if (sarg & CHR_TIOCM_CAR) { 2372b2f23daSMarc-André Lureau targ |= TIOCM_CAR; 2382b2f23daSMarc-André Lureau } 2392b2f23daSMarc-André Lureau if (sarg & CHR_TIOCM_DSR) { 2402b2f23daSMarc-André Lureau targ |= TIOCM_DSR; 2412b2f23daSMarc-André Lureau } 2422b2f23daSMarc-André Lureau if (sarg & CHR_TIOCM_RI) { 2432b2f23daSMarc-André Lureau targ |= TIOCM_RI; 2442b2f23daSMarc-André Lureau } 2452b2f23daSMarc-André Lureau if (sarg & CHR_TIOCM_DTR) { 2462b2f23daSMarc-André Lureau targ |= TIOCM_DTR; 2472b2f23daSMarc-André Lureau } 2482b2f23daSMarc-André Lureau if (sarg & CHR_TIOCM_RTS) { 2492b2f23daSMarc-André Lureau targ |= TIOCM_RTS; 2502b2f23daSMarc-André Lureau } 2512b2f23daSMarc-André Lureau ioctl(fioc->fd, TIOCMSET, &targ); 2522b2f23daSMarc-André Lureau } 2532b2f23daSMarc-André Lureau break; 2542b2f23daSMarc-André Lureau default: 2552b2f23daSMarc-André Lureau return -ENOTSUP; 2562b2f23daSMarc-André Lureau } 2572b2f23daSMarc-André Lureau return 0; 2582b2f23daSMarc-André Lureau } 2592b2f23daSMarc-André Lureau 2602b2f23daSMarc-André Lureau static void qmp_chardev_open_serial(Chardev *chr, 2612b2f23daSMarc-André Lureau ChardevBackend *backend, 2622b2f23daSMarc-André Lureau bool *be_opened, 2632b2f23daSMarc-André Lureau Error **errp) 2642b2f23daSMarc-André Lureau { 2652b2f23daSMarc-André Lureau ChardevHostdev *serial = backend->u.serial.data; 2662b2f23daSMarc-André Lureau int fd; 2672b2f23daSMarc-André Lureau 2682b2f23daSMarc-André Lureau fd = qmp_chardev_open_file_source(serial->device, O_RDWR, errp); 2692b2f23daSMarc-André Lureau if (fd < 0) { 2702b2f23daSMarc-André Lureau return; 2712b2f23daSMarc-André Lureau } 2722b2f23daSMarc-André Lureau qemu_set_nonblock(fd); 2732b2f23daSMarc-André Lureau tty_serial_init(fd, 115200, 'N', 8, 1); 2742b2f23daSMarc-André Lureau 2752b2f23daSMarc-André Lureau qemu_chr_open_fd(chr, fd, fd); 2762b2f23daSMarc-André Lureau } 2772b2f23daSMarc-André Lureau #endif /* __linux__ || __sun__ */ 2782b2f23daSMarc-André Lureau 2792b2f23daSMarc-André Lureau #ifdef HAVE_CHARDEV_SERIAL 2802b2f23daSMarc-André Lureau static void qemu_chr_parse_serial(QemuOpts *opts, ChardevBackend *backend, 2812b2f23daSMarc-André Lureau Error **errp) 2822b2f23daSMarc-André Lureau { 2832b2f23daSMarc-André Lureau const char *device = qemu_opt_get(opts, "path"); 2842b2f23daSMarc-André Lureau ChardevHostdev *serial; 2852b2f23daSMarc-André Lureau 2862b2f23daSMarc-André Lureau if (device == NULL) { 2872b2f23daSMarc-André Lureau error_setg(errp, "chardev: serial/tty: no device path given"); 2882b2f23daSMarc-André Lureau return; 2892b2f23daSMarc-André Lureau } 2902b2f23daSMarc-André Lureau backend->type = CHARDEV_BACKEND_KIND_SERIAL; 2912b2f23daSMarc-André Lureau serial = backend->u.serial.data = g_new0(ChardevHostdev, 1); 2922b2f23daSMarc-André Lureau qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(serial)); 2932b2f23daSMarc-André Lureau serial->device = g_strdup(device); 2942b2f23daSMarc-André Lureau } 2952b2f23daSMarc-André Lureau 2962b2f23daSMarc-André Lureau static void char_serial_class_init(ObjectClass *oc, void *data) 2972b2f23daSMarc-André Lureau { 2982b2f23daSMarc-André Lureau ChardevClass *cc = CHARDEV_CLASS(oc); 2992b2f23daSMarc-André Lureau 3002b2f23daSMarc-André Lureau cc->parse = qemu_chr_parse_serial; 3012b2f23daSMarc-André Lureau cc->open = qmp_chardev_open_serial; 3022b2f23daSMarc-André Lureau #ifndef _WIN32 3032b2f23daSMarc-André Lureau cc->chr_ioctl = tty_serial_ioctl; 3042b2f23daSMarc-André Lureau #endif 3052b2f23daSMarc-André Lureau } 3062b2f23daSMarc-André Lureau 3072b2f23daSMarc-André Lureau 3082b2f23daSMarc-André Lureau static const TypeInfo char_serial_type_info = { 3092b2f23daSMarc-André Lureau .name = TYPE_CHARDEV_SERIAL, 3102b2f23daSMarc-André Lureau #ifdef _WIN32 3112b2f23daSMarc-André Lureau .parent = TYPE_CHARDEV_WIN, 3122b2f23daSMarc-André Lureau #else 3132b2f23daSMarc-André Lureau .parent = TYPE_CHARDEV_FD, 3142b2f23daSMarc-André Lureau #endif 3152b2f23daSMarc-André Lureau .class_init = char_serial_class_init, 3162b2f23daSMarc-André Lureau }; 3172b2f23daSMarc-André Lureau 3182b2f23daSMarc-André Lureau static void register_types(void) 3192b2f23daSMarc-André Lureau { 3202b2f23daSMarc-André Lureau type_register_static(&char_serial_type_info); 3212b2f23daSMarc-André Lureau } 3222b2f23daSMarc-André Lureau 3232b2f23daSMarc-André Lureau type_init(register_types); 3242b2f23daSMarc-André Lureau 3252b2f23daSMarc-André Lureau #endif 326