1*2b2f23daSMarc-André Lureau /* 2*2b2f23daSMarc-André Lureau * QEMU System Emulator 3*2b2f23daSMarc-André Lureau * 4*2b2f23daSMarc-André Lureau * Copyright (c) 2003-2008 Fabrice Bellard 5*2b2f23daSMarc-André Lureau * 6*2b2f23daSMarc-André Lureau * Permission is hereby granted, free of charge, to any person obtaining a copy 7*2b2f23daSMarc-André Lureau * of this software and associated documentation files (the "Software"), to deal 8*2b2f23daSMarc-André Lureau * in the Software without restriction, including without limitation the rights 9*2b2f23daSMarc-André Lureau * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10*2b2f23daSMarc-André Lureau * copies of the Software, and to permit persons to whom the Software is 11*2b2f23daSMarc-André Lureau * furnished to do so, subject to the following conditions: 12*2b2f23daSMarc-André Lureau * 13*2b2f23daSMarc-André Lureau * The above copyright notice and this permission notice shall be included in 14*2b2f23daSMarc-André Lureau * all copies or substantial portions of the Software. 15*2b2f23daSMarc-André Lureau * 16*2b2f23daSMarc-André Lureau * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17*2b2f23daSMarc-André Lureau * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18*2b2f23daSMarc-André Lureau * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19*2b2f23daSMarc-André Lureau * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20*2b2f23daSMarc-André Lureau * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21*2b2f23daSMarc-André Lureau * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22*2b2f23daSMarc-André Lureau * THE SOFTWARE. 23*2b2f23daSMarc-André Lureau */ 24*2b2f23daSMarc-André Lureau #include "qemu/osdep.h" 25*2b2f23daSMarc-André Lureau #include "qemu/sockets.h" 26*2b2f23daSMarc-André Lureau #include "io/channel-file.h" 27*2b2f23daSMarc-André Lureau #include "qapi/error.h" 28*2b2f23daSMarc-André Lureau 29*2b2f23daSMarc-André Lureau #ifdef _WIN32 30*2b2f23daSMarc-André Lureau #include "char-win.h" 31*2b2f23daSMarc-André Lureau #else 32*2b2f23daSMarc-André Lureau #include <sys/ioctl.h> 33*2b2f23daSMarc-André Lureau #include <termios.h> 34*2b2f23daSMarc-André Lureau #include "char-fd.h" 35*2b2f23daSMarc-André Lureau #endif 36*2b2f23daSMarc-André Lureau 37*2b2f23daSMarc-André Lureau #include "char-serial.h" 38*2b2f23daSMarc-André Lureau 39*2b2f23daSMarc-André Lureau #ifdef _WIN32 40*2b2f23daSMarc-André Lureau 41*2b2f23daSMarc-André Lureau static void qmp_chardev_open_serial(Chardev *chr, 42*2b2f23daSMarc-André Lureau ChardevBackend *backend, 43*2b2f23daSMarc-André Lureau bool *be_opened, 44*2b2f23daSMarc-André Lureau Error **errp) 45*2b2f23daSMarc-André Lureau { 46*2b2f23daSMarc-André Lureau ChardevHostdev *serial = backend->u.serial.data; 47*2b2f23daSMarc-André Lureau 48*2b2f23daSMarc-André Lureau win_chr_init(chr, serial->device, errp); 49*2b2f23daSMarc-André Lureau } 50*2b2f23daSMarc-André Lureau 51*2b2f23daSMarc-André Lureau #elif defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \ 52*2b2f23daSMarc-André Lureau || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \ 53*2b2f23daSMarc-André Lureau || defined(__GLIBC__) 54*2b2f23daSMarc-André Lureau 55*2b2f23daSMarc-André Lureau static void tty_serial_init(int fd, int speed, 56*2b2f23daSMarc-André Lureau int parity, int data_bits, int stop_bits) 57*2b2f23daSMarc-André Lureau { 58*2b2f23daSMarc-André Lureau struct termios tty; 59*2b2f23daSMarc-André Lureau speed_t spd; 60*2b2f23daSMarc-André Lureau 61*2b2f23daSMarc-André Lureau #if 0 62*2b2f23daSMarc-André Lureau printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n", 63*2b2f23daSMarc-André Lureau speed, parity, data_bits, stop_bits); 64*2b2f23daSMarc-André Lureau #endif 65*2b2f23daSMarc-André Lureau tcgetattr(fd, &tty); 66*2b2f23daSMarc-André Lureau 67*2b2f23daSMarc-André Lureau #define check_speed(val) if (speed <= val) { spd = B##val; break; } 68*2b2f23daSMarc-André Lureau speed = speed * 10 / 11; 69*2b2f23daSMarc-André Lureau do { 70*2b2f23daSMarc-André Lureau check_speed(50); 71*2b2f23daSMarc-André Lureau check_speed(75); 72*2b2f23daSMarc-André Lureau check_speed(110); 73*2b2f23daSMarc-André Lureau check_speed(134); 74*2b2f23daSMarc-André Lureau check_speed(150); 75*2b2f23daSMarc-André Lureau check_speed(200); 76*2b2f23daSMarc-André Lureau check_speed(300); 77*2b2f23daSMarc-André Lureau check_speed(600); 78*2b2f23daSMarc-André Lureau check_speed(1200); 79*2b2f23daSMarc-André Lureau check_speed(1800); 80*2b2f23daSMarc-André Lureau check_speed(2400); 81*2b2f23daSMarc-André Lureau check_speed(4800); 82*2b2f23daSMarc-André Lureau check_speed(9600); 83*2b2f23daSMarc-André Lureau check_speed(19200); 84*2b2f23daSMarc-André Lureau check_speed(38400); 85*2b2f23daSMarc-André Lureau /* Non-Posix values follow. They may be unsupported on some systems. */ 86*2b2f23daSMarc-André Lureau check_speed(57600); 87*2b2f23daSMarc-André Lureau check_speed(115200); 88*2b2f23daSMarc-André Lureau #ifdef B230400 89*2b2f23daSMarc-André Lureau check_speed(230400); 90*2b2f23daSMarc-André Lureau #endif 91*2b2f23daSMarc-André Lureau #ifdef B460800 92*2b2f23daSMarc-André Lureau check_speed(460800); 93*2b2f23daSMarc-André Lureau #endif 94*2b2f23daSMarc-André Lureau #ifdef B500000 95*2b2f23daSMarc-André Lureau check_speed(500000); 96*2b2f23daSMarc-André Lureau #endif 97*2b2f23daSMarc-André Lureau #ifdef B576000 98*2b2f23daSMarc-André Lureau check_speed(576000); 99*2b2f23daSMarc-André Lureau #endif 100*2b2f23daSMarc-André Lureau #ifdef B921600 101*2b2f23daSMarc-André Lureau check_speed(921600); 102*2b2f23daSMarc-André Lureau #endif 103*2b2f23daSMarc-André Lureau #ifdef B1000000 104*2b2f23daSMarc-André Lureau check_speed(1000000); 105*2b2f23daSMarc-André Lureau #endif 106*2b2f23daSMarc-André Lureau #ifdef B1152000 107*2b2f23daSMarc-André Lureau check_speed(1152000); 108*2b2f23daSMarc-André Lureau #endif 109*2b2f23daSMarc-André Lureau #ifdef B1500000 110*2b2f23daSMarc-André Lureau check_speed(1500000); 111*2b2f23daSMarc-André Lureau #endif 112*2b2f23daSMarc-André Lureau #ifdef B2000000 113*2b2f23daSMarc-André Lureau check_speed(2000000); 114*2b2f23daSMarc-André Lureau #endif 115*2b2f23daSMarc-André Lureau #ifdef B2500000 116*2b2f23daSMarc-André Lureau check_speed(2500000); 117*2b2f23daSMarc-André Lureau #endif 118*2b2f23daSMarc-André Lureau #ifdef B3000000 119*2b2f23daSMarc-André Lureau check_speed(3000000); 120*2b2f23daSMarc-André Lureau #endif 121*2b2f23daSMarc-André Lureau #ifdef B3500000 122*2b2f23daSMarc-André Lureau check_speed(3500000); 123*2b2f23daSMarc-André Lureau #endif 124*2b2f23daSMarc-André Lureau #ifdef B4000000 125*2b2f23daSMarc-André Lureau check_speed(4000000); 126*2b2f23daSMarc-André Lureau #endif 127*2b2f23daSMarc-André Lureau spd = B115200; 128*2b2f23daSMarc-André Lureau } while (0); 129*2b2f23daSMarc-André Lureau 130*2b2f23daSMarc-André Lureau cfsetispeed(&tty, spd); 131*2b2f23daSMarc-André Lureau cfsetospeed(&tty, spd); 132*2b2f23daSMarc-André Lureau 133*2b2f23daSMarc-André Lureau tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP 134*2b2f23daSMarc-André Lureau | INLCR | IGNCR | ICRNL | IXON); 135*2b2f23daSMarc-André Lureau tty.c_oflag |= OPOST; 136*2b2f23daSMarc-André Lureau tty.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG); 137*2b2f23daSMarc-André Lureau tty.c_cflag &= ~(CSIZE | PARENB | PARODD | CRTSCTS | CSTOPB); 138*2b2f23daSMarc-André Lureau switch (data_bits) { 139*2b2f23daSMarc-André Lureau default: 140*2b2f23daSMarc-André Lureau case 8: 141*2b2f23daSMarc-André Lureau tty.c_cflag |= CS8; 142*2b2f23daSMarc-André Lureau break; 143*2b2f23daSMarc-André Lureau case 7: 144*2b2f23daSMarc-André Lureau tty.c_cflag |= CS7; 145*2b2f23daSMarc-André Lureau break; 146*2b2f23daSMarc-André Lureau case 6: 147*2b2f23daSMarc-André Lureau tty.c_cflag |= CS6; 148*2b2f23daSMarc-André Lureau break; 149*2b2f23daSMarc-André Lureau case 5: 150*2b2f23daSMarc-André Lureau tty.c_cflag |= CS5; 151*2b2f23daSMarc-André Lureau break; 152*2b2f23daSMarc-André Lureau } 153*2b2f23daSMarc-André Lureau switch (parity) { 154*2b2f23daSMarc-André Lureau default: 155*2b2f23daSMarc-André Lureau case 'N': 156*2b2f23daSMarc-André Lureau break; 157*2b2f23daSMarc-André Lureau case 'E': 158*2b2f23daSMarc-André Lureau tty.c_cflag |= PARENB; 159*2b2f23daSMarc-André Lureau break; 160*2b2f23daSMarc-André Lureau case 'O': 161*2b2f23daSMarc-André Lureau tty.c_cflag |= PARENB | PARODD; 162*2b2f23daSMarc-André Lureau break; 163*2b2f23daSMarc-André Lureau } 164*2b2f23daSMarc-André Lureau if (stop_bits == 2) { 165*2b2f23daSMarc-André Lureau tty.c_cflag |= CSTOPB; 166*2b2f23daSMarc-André Lureau } 167*2b2f23daSMarc-André Lureau 168*2b2f23daSMarc-André Lureau tcsetattr(fd, TCSANOW, &tty); 169*2b2f23daSMarc-André Lureau } 170*2b2f23daSMarc-André Lureau 171*2b2f23daSMarc-André Lureau static int tty_serial_ioctl(Chardev *chr, int cmd, void *arg) 172*2b2f23daSMarc-André Lureau { 173*2b2f23daSMarc-André Lureau FDChardev *s = FD_CHARDEV(chr); 174*2b2f23daSMarc-André Lureau QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc_in); 175*2b2f23daSMarc-André Lureau 176*2b2f23daSMarc-André Lureau switch (cmd) { 177*2b2f23daSMarc-André Lureau case CHR_IOCTL_SERIAL_SET_PARAMS: 178*2b2f23daSMarc-André Lureau { 179*2b2f23daSMarc-André Lureau QEMUSerialSetParams *ssp = arg; 180*2b2f23daSMarc-André Lureau tty_serial_init(fioc->fd, 181*2b2f23daSMarc-André Lureau ssp->speed, ssp->parity, 182*2b2f23daSMarc-André Lureau ssp->data_bits, ssp->stop_bits); 183*2b2f23daSMarc-André Lureau } 184*2b2f23daSMarc-André Lureau break; 185*2b2f23daSMarc-André Lureau case CHR_IOCTL_SERIAL_SET_BREAK: 186*2b2f23daSMarc-André Lureau { 187*2b2f23daSMarc-André Lureau int enable = *(int *)arg; 188*2b2f23daSMarc-André Lureau if (enable) { 189*2b2f23daSMarc-André Lureau tcsendbreak(fioc->fd, 1); 190*2b2f23daSMarc-André Lureau } 191*2b2f23daSMarc-André Lureau } 192*2b2f23daSMarc-André Lureau break; 193*2b2f23daSMarc-André Lureau case CHR_IOCTL_SERIAL_GET_TIOCM: 194*2b2f23daSMarc-André Lureau { 195*2b2f23daSMarc-André Lureau int sarg = 0; 196*2b2f23daSMarc-André Lureau int *targ = (int *)arg; 197*2b2f23daSMarc-André Lureau ioctl(fioc->fd, TIOCMGET, &sarg); 198*2b2f23daSMarc-André Lureau *targ = 0; 199*2b2f23daSMarc-André Lureau if (sarg & TIOCM_CTS) { 200*2b2f23daSMarc-André Lureau *targ |= CHR_TIOCM_CTS; 201*2b2f23daSMarc-André Lureau } 202*2b2f23daSMarc-André Lureau if (sarg & TIOCM_CAR) { 203*2b2f23daSMarc-André Lureau *targ |= CHR_TIOCM_CAR; 204*2b2f23daSMarc-André Lureau } 205*2b2f23daSMarc-André Lureau if (sarg & TIOCM_DSR) { 206*2b2f23daSMarc-André Lureau *targ |= CHR_TIOCM_DSR; 207*2b2f23daSMarc-André Lureau } 208*2b2f23daSMarc-André Lureau if (sarg & TIOCM_RI) { 209*2b2f23daSMarc-André Lureau *targ |= CHR_TIOCM_RI; 210*2b2f23daSMarc-André Lureau } 211*2b2f23daSMarc-André Lureau if (sarg & TIOCM_DTR) { 212*2b2f23daSMarc-André Lureau *targ |= CHR_TIOCM_DTR; 213*2b2f23daSMarc-André Lureau } 214*2b2f23daSMarc-André Lureau if (sarg & TIOCM_RTS) { 215*2b2f23daSMarc-André Lureau *targ |= CHR_TIOCM_RTS; 216*2b2f23daSMarc-André Lureau } 217*2b2f23daSMarc-André Lureau } 218*2b2f23daSMarc-André Lureau break; 219*2b2f23daSMarc-André Lureau case CHR_IOCTL_SERIAL_SET_TIOCM: 220*2b2f23daSMarc-André Lureau { 221*2b2f23daSMarc-André Lureau int sarg = *(int *)arg; 222*2b2f23daSMarc-André Lureau int targ = 0; 223*2b2f23daSMarc-André Lureau ioctl(fioc->fd, TIOCMGET, &targ); 224*2b2f23daSMarc-André Lureau targ &= ~(CHR_TIOCM_CTS | CHR_TIOCM_CAR | CHR_TIOCM_DSR 225*2b2f23daSMarc-André Lureau | CHR_TIOCM_RI | CHR_TIOCM_DTR | CHR_TIOCM_RTS); 226*2b2f23daSMarc-André Lureau if (sarg & CHR_TIOCM_CTS) { 227*2b2f23daSMarc-André Lureau targ |= TIOCM_CTS; 228*2b2f23daSMarc-André Lureau } 229*2b2f23daSMarc-André Lureau if (sarg & CHR_TIOCM_CAR) { 230*2b2f23daSMarc-André Lureau targ |= TIOCM_CAR; 231*2b2f23daSMarc-André Lureau } 232*2b2f23daSMarc-André Lureau if (sarg & CHR_TIOCM_DSR) { 233*2b2f23daSMarc-André Lureau targ |= TIOCM_DSR; 234*2b2f23daSMarc-André Lureau } 235*2b2f23daSMarc-André Lureau if (sarg & CHR_TIOCM_RI) { 236*2b2f23daSMarc-André Lureau targ |= TIOCM_RI; 237*2b2f23daSMarc-André Lureau } 238*2b2f23daSMarc-André Lureau if (sarg & CHR_TIOCM_DTR) { 239*2b2f23daSMarc-André Lureau targ |= TIOCM_DTR; 240*2b2f23daSMarc-André Lureau } 241*2b2f23daSMarc-André Lureau if (sarg & CHR_TIOCM_RTS) { 242*2b2f23daSMarc-André Lureau targ |= TIOCM_RTS; 243*2b2f23daSMarc-André Lureau } 244*2b2f23daSMarc-André Lureau ioctl(fioc->fd, TIOCMSET, &targ); 245*2b2f23daSMarc-André Lureau } 246*2b2f23daSMarc-André Lureau break; 247*2b2f23daSMarc-André Lureau default: 248*2b2f23daSMarc-André Lureau return -ENOTSUP; 249*2b2f23daSMarc-André Lureau } 250*2b2f23daSMarc-André Lureau return 0; 251*2b2f23daSMarc-André Lureau } 252*2b2f23daSMarc-André Lureau 253*2b2f23daSMarc-André Lureau static void qmp_chardev_open_serial(Chardev *chr, 254*2b2f23daSMarc-André Lureau ChardevBackend *backend, 255*2b2f23daSMarc-André Lureau bool *be_opened, 256*2b2f23daSMarc-André Lureau Error **errp) 257*2b2f23daSMarc-André Lureau { 258*2b2f23daSMarc-André Lureau ChardevHostdev *serial = backend->u.serial.data; 259*2b2f23daSMarc-André Lureau int fd; 260*2b2f23daSMarc-André Lureau 261*2b2f23daSMarc-André Lureau fd = qmp_chardev_open_file_source(serial->device, O_RDWR, errp); 262*2b2f23daSMarc-André Lureau if (fd < 0) { 263*2b2f23daSMarc-André Lureau return; 264*2b2f23daSMarc-André Lureau } 265*2b2f23daSMarc-André Lureau qemu_set_nonblock(fd); 266*2b2f23daSMarc-André Lureau tty_serial_init(fd, 115200, 'N', 8, 1); 267*2b2f23daSMarc-André Lureau 268*2b2f23daSMarc-André Lureau qemu_chr_open_fd(chr, fd, fd); 269*2b2f23daSMarc-André Lureau } 270*2b2f23daSMarc-André Lureau #endif /* __linux__ || __sun__ */ 271*2b2f23daSMarc-André Lureau 272*2b2f23daSMarc-André Lureau #ifdef HAVE_CHARDEV_SERIAL 273*2b2f23daSMarc-André Lureau static void qemu_chr_parse_serial(QemuOpts *opts, ChardevBackend *backend, 274*2b2f23daSMarc-André Lureau Error **errp) 275*2b2f23daSMarc-André Lureau { 276*2b2f23daSMarc-André Lureau const char *device = qemu_opt_get(opts, "path"); 277*2b2f23daSMarc-André Lureau ChardevHostdev *serial; 278*2b2f23daSMarc-André Lureau 279*2b2f23daSMarc-André Lureau if (device == NULL) { 280*2b2f23daSMarc-André Lureau error_setg(errp, "chardev: serial/tty: no device path given"); 281*2b2f23daSMarc-André Lureau return; 282*2b2f23daSMarc-André Lureau } 283*2b2f23daSMarc-André Lureau backend->type = CHARDEV_BACKEND_KIND_SERIAL; 284*2b2f23daSMarc-André Lureau serial = backend->u.serial.data = g_new0(ChardevHostdev, 1); 285*2b2f23daSMarc-André Lureau qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(serial)); 286*2b2f23daSMarc-André Lureau serial->device = g_strdup(device); 287*2b2f23daSMarc-André Lureau } 288*2b2f23daSMarc-André Lureau 289*2b2f23daSMarc-André Lureau static void char_serial_class_init(ObjectClass *oc, void *data) 290*2b2f23daSMarc-André Lureau { 291*2b2f23daSMarc-André Lureau ChardevClass *cc = CHARDEV_CLASS(oc); 292*2b2f23daSMarc-André Lureau 293*2b2f23daSMarc-André Lureau cc->parse = qemu_chr_parse_serial; 294*2b2f23daSMarc-André Lureau cc->open = qmp_chardev_open_serial; 295*2b2f23daSMarc-André Lureau #ifndef _WIN32 296*2b2f23daSMarc-André Lureau cc->chr_ioctl = tty_serial_ioctl; 297*2b2f23daSMarc-André Lureau #endif 298*2b2f23daSMarc-André Lureau } 299*2b2f23daSMarc-André Lureau 300*2b2f23daSMarc-André Lureau 301*2b2f23daSMarc-André Lureau static const TypeInfo char_serial_type_info = { 302*2b2f23daSMarc-André Lureau .name = TYPE_CHARDEV_SERIAL, 303*2b2f23daSMarc-André Lureau #ifdef _WIN32 304*2b2f23daSMarc-André Lureau .parent = TYPE_CHARDEV_WIN, 305*2b2f23daSMarc-André Lureau #else 306*2b2f23daSMarc-André Lureau .parent = TYPE_CHARDEV_FD, 307*2b2f23daSMarc-André Lureau #endif 308*2b2f23daSMarc-André Lureau .class_init = char_serial_class_init, 309*2b2f23daSMarc-André Lureau }; 310*2b2f23daSMarc-André Lureau 311*2b2f23daSMarc-André Lureau static void register_types(void) 312*2b2f23daSMarc-André Lureau { 313*2b2f23daSMarc-André Lureau type_register_static(&char_serial_type_info); 314*2b2f23daSMarc-André Lureau } 315*2b2f23daSMarc-André Lureau 316*2b2f23daSMarc-André Lureau type_init(register_types); 317*2b2f23daSMarc-André Lureau 318*2b2f23daSMarc-André Lureau #endif 319