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