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