123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- /*
- * QEMU System Emulator
- *
- * Copyright (c) 2003-2008 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #include "qemu/osdep.h"
- #include "qemu/module.h"
- #include "qemu/option.h"
- #include "qemu/sockets.h"
- #include "io/channel-file.h"
- #include "qapi/error.h"
- #ifdef _WIN32
- #include "chardev/char-win.h"
- #else
- #include <sys/ioctl.h>
- #include <termios.h>
- #include "chardev/char-fd.h"
- #endif
- #include "chardev/char-serial.h"
- #ifdef _WIN32
- static void qmp_chardev_open_serial(Chardev *chr,
- ChardevBackend *backend,
- bool *be_opened,
- Error **errp)
- {
- ChardevHostdev *serial = backend->u.serial.data;
- win_chr_serial_init(chr, serial->device, errp);
- }
- #elif defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
- || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
- || defined(__GLIBC__) || defined(__APPLE__)
- static void tty_serial_init(int fd, int speed,
- int parity, int data_bits, int stop_bits)
- {
- struct termios tty = {0};
- speed_t spd;
- #if 0
- printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n",
- speed, parity, data_bits, stop_bits);
- #endif
- tcgetattr(fd, &tty);
- #define check_speed(val) \
- if (speed <= val) { \
- spd = B##val; \
- goto done; \
- }
- speed = speed * 10 / 11;
- check_speed(50);
- check_speed(75);
- check_speed(110);
- check_speed(134);
- check_speed(150);
- check_speed(200);
- check_speed(300);
- check_speed(600);
- check_speed(1200);
- check_speed(1800);
- check_speed(2400);
- check_speed(4800);
- check_speed(9600);
- check_speed(19200);
- check_speed(38400);
- /* Non-Posix values follow. They may be unsupported on some systems. */
- check_speed(57600);
- check_speed(115200);
- #ifdef B230400
- check_speed(230400);
- #endif
- #ifdef B460800
- check_speed(460800);
- #endif
- #ifdef B500000
- check_speed(500000);
- #endif
- #ifdef B576000
- check_speed(576000);
- #endif
- #ifdef B921600
- check_speed(921600);
- #endif
- #ifdef B1000000
- check_speed(1000000);
- #endif
- #ifdef B1152000
- check_speed(1152000);
- #endif
- #ifdef B1500000
- check_speed(1500000);
- #endif
- #ifdef B2000000
- check_speed(2000000);
- #endif
- #ifdef B2500000
- check_speed(2500000);
- #endif
- #ifdef B3000000
- check_speed(3000000);
- #endif
- #ifdef B3500000
- check_speed(3500000);
- #endif
- #ifdef B4000000
- check_speed(4000000);
- #endif
- spd = B115200;
- #undef check_speed
- done:
- cfsetispeed(&tty, spd);
- cfsetospeed(&tty, spd);
- tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
- | INLCR | IGNCR | ICRNL | IXON);
- tty.c_oflag &= ~OPOST;
- tty.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);
- tty.c_cflag &= ~(CSIZE | PARENB | PARODD | CRTSCTS | CSTOPB);
- switch (data_bits) {
- default:
- case 8:
- tty.c_cflag |= CS8;
- break;
- case 7:
- tty.c_cflag |= CS7;
- break;
- case 6:
- tty.c_cflag |= CS6;
- break;
- case 5:
- tty.c_cflag |= CS5;
- break;
- }
- switch (parity) {
- default:
- case 'N':
- break;
- case 'E':
- tty.c_cflag |= PARENB;
- break;
- case 'O':
- tty.c_cflag |= PARENB | PARODD;
- break;
- }
- if (stop_bits == 2) {
- tty.c_cflag |= CSTOPB;
- }
- tcsetattr(fd, TCSANOW, &tty);
- }
- static int tty_serial_ioctl(Chardev *chr, int cmd, void *arg)
- {
- FDChardev *s = FD_CHARDEV(chr);
- QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc_in);
- switch (cmd) {
- case CHR_IOCTL_SERIAL_SET_PARAMS:
- {
- QEMUSerialSetParams *ssp = arg;
- tty_serial_init(fioc->fd,
- ssp->speed, ssp->parity,
- ssp->data_bits, ssp->stop_bits);
- }
- break;
- case CHR_IOCTL_SERIAL_SET_BREAK:
- {
- int enable = *(int *)arg;
- if (enable) {
- tcsendbreak(fioc->fd, 1);
- }
- }
- break;
- case CHR_IOCTL_SERIAL_GET_TIOCM:
- {
- int sarg = 0;
- int *targ = (int *)arg;
- ioctl(fioc->fd, TIOCMGET, &sarg);
- *targ = 0;
- if (sarg & TIOCM_CTS) {
- *targ |= CHR_TIOCM_CTS;
- }
- if (sarg & TIOCM_CAR) {
- *targ |= CHR_TIOCM_CAR;
- }
- if (sarg & TIOCM_DSR) {
- *targ |= CHR_TIOCM_DSR;
- }
- if (sarg & TIOCM_RI) {
- *targ |= CHR_TIOCM_RI;
- }
- if (sarg & TIOCM_DTR) {
- *targ |= CHR_TIOCM_DTR;
- }
- if (sarg & TIOCM_RTS) {
- *targ |= CHR_TIOCM_RTS;
- }
- }
- break;
- case CHR_IOCTL_SERIAL_SET_TIOCM:
- {
- int sarg = *(int *)arg;
- int targ = 0;
- ioctl(fioc->fd, TIOCMGET, &targ);
- targ &= ~(CHR_TIOCM_CTS | CHR_TIOCM_CAR | CHR_TIOCM_DSR
- | CHR_TIOCM_RI | CHR_TIOCM_DTR | CHR_TIOCM_RTS);
- if (sarg & CHR_TIOCM_CTS) {
- targ |= TIOCM_CTS;
- }
- if (sarg & CHR_TIOCM_CAR) {
- targ |= TIOCM_CAR;
- }
- if (sarg & CHR_TIOCM_DSR) {
- targ |= TIOCM_DSR;
- }
- if (sarg & CHR_TIOCM_RI) {
- targ |= TIOCM_RI;
- }
- if (sarg & CHR_TIOCM_DTR) {
- targ |= TIOCM_DTR;
- }
- if (sarg & CHR_TIOCM_RTS) {
- targ |= TIOCM_RTS;
- }
- ioctl(fioc->fd, TIOCMSET, &targ);
- }
- break;
- default:
- return -ENOTSUP;
- }
- return 0;
- }
- static void qmp_chardev_open_serial(Chardev *chr,
- ChardevBackend *backend,
- bool *be_opened,
- Error **errp)
- {
- ChardevHostdev *serial = backend->u.serial.data;
- int fd;
- fd = qmp_chardev_open_file_source(serial->device, O_RDWR | O_NONBLOCK,
- errp);
- if (fd < 0) {
- return;
- }
- if (!g_unix_set_fd_nonblocking(fd, true, NULL)) {
- error_setg_errno(errp, errno, "Failed to set FD nonblocking");
- return;
- }
- tty_serial_init(fd, 115200, 'N', 8, 1);
- qemu_chr_open_fd(chr, fd, fd);
- }
- #endif /* __linux__ || __sun__ */
- #ifdef HAVE_CHARDEV_SERIAL
- static void qemu_chr_parse_serial(QemuOpts *opts, ChardevBackend *backend,
- Error **errp)
- {
- const char *device = qemu_opt_get(opts, "path");
- ChardevHostdev *serial;
- if (device == NULL) {
- error_setg(errp, "chardev: serial/tty: no device path given");
- return;
- }
- backend->type = CHARDEV_BACKEND_KIND_SERIAL;
- serial = backend->u.serial.data = g_new0(ChardevHostdev, 1);
- qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(serial));
- serial->device = g_strdup(device);
- }
- static void char_serial_class_init(ObjectClass *oc, void *data)
- {
- ChardevClass *cc = CHARDEV_CLASS(oc);
- cc->parse = qemu_chr_parse_serial;
- cc->open = qmp_chardev_open_serial;
- #ifndef _WIN32
- cc->chr_ioctl = tty_serial_ioctl;
- #endif
- }
- static const TypeInfo char_serial_type_info = {
- .name = TYPE_CHARDEV_SERIAL,
- #ifdef _WIN32
- .parent = TYPE_CHARDEV_WIN,
- #else
- .parent = TYPE_CHARDEV_FD,
- #endif
- .class_init = char_serial_class_init,
- };
- static void register_types(void)
- {
- type_register_static(&char_serial_type_info);
- }
- type_init(register_types);
- #endif
|