xref: /openbmc/qemu/chardev/char-serial.c (revision b91a0fa7)
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/module.h"
27 #include "qemu/option.h"
28 #include "qemu/sockets.h"
29 #include "io/channel-file.h"
30 #include "qapi/error.h"
31 
32 #ifdef _WIN32
33 #include "chardev/char-win.h"
34 #else
35 #include <sys/ioctl.h>
36 #include <termios.h>
37 #include "chardev/char-fd.h"
38 #endif
39 
40 #include "chardev/char-serial.h"
41 
42 #ifdef _WIN32
43 
44 static void qmp_chardev_open_serial(Chardev *chr,
45                                     ChardevBackend *backend,
46                                     bool *be_opened,
47                                     Error **errp)
48 {
49     ChardevHostdev *serial = backend->u.serial.data;
50 
51     win_chr_serial_init(chr, serial->device, errp);
52 }
53 
54 #elif defined(__linux__) || defined(__sun__) || defined(__FreeBSD__)      \
55     || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
56     || defined(__GLIBC__) || defined(__APPLE__)
57 
58 static void tty_serial_init(int fd, int speed,
59                             int parity, int data_bits, int stop_bits)
60 {
61     struct termios tty = {0};
62     speed_t spd;
63 
64 #if 0
65     printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n",
66            speed, parity, data_bits, stop_bits);
67 #endif
68     tcgetattr(fd, &tty);
69 
70 #define check_speed(val) \
71     if (speed <= val) {  \
72         spd = B##val;    \
73         goto done;       \
74     }
75 
76     speed = speed * 10 / 11;
77     check_speed(50);
78     check_speed(75);
79     check_speed(110);
80     check_speed(134);
81     check_speed(150);
82     check_speed(200);
83     check_speed(300);
84     check_speed(600);
85     check_speed(1200);
86     check_speed(1800);
87     check_speed(2400);
88     check_speed(4800);
89     check_speed(9600);
90     check_speed(19200);
91     check_speed(38400);
92     /* Non-Posix values follow. They may be unsupported on some systems. */
93     check_speed(57600);
94     check_speed(115200);
95 #ifdef B230400
96     check_speed(230400);
97 #endif
98 #ifdef B460800
99     check_speed(460800);
100 #endif
101 #ifdef B500000
102     check_speed(500000);
103 #endif
104 #ifdef B576000
105     check_speed(576000);
106 #endif
107 #ifdef B921600
108     check_speed(921600);
109 #endif
110 #ifdef B1000000
111     check_speed(1000000);
112 #endif
113 #ifdef B1152000
114     check_speed(1152000);
115 #endif
116 #ifdef B1500000
117     check_speed(1500000);
118 #endif
119 #ifdef B2000000
120     check_speed(2000000);
121 #endif
122 #ifdef B2500000
123     check_speed(2500000);
124 #endif
125 #ifdef B3000000
126     check_speed(3000000);
127 #endif
128 #ifdef B3500000
129     check_speed(3500000);
130 #endif
131 #ifdef B4000000
132     check_speed(4000000);
133 #endif
134     spd = B115200;
135 
136 #undef check_speed
137  done:
138     cfsetispeed(&tty, spd);
139     cfsetospeed(&tty, spd);
140 
141     tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
142                      | INLCR | IGNCR | ICRNL | IXON);
143     tty.c_oflag &= ~OPOST;
144     tty.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);
145     tty.c_cflag &= ~(CSIZE | PARENB | PARODD | CRTSCTS | CSTOPB);
146     switch (data_bits) {
147     default:
148     case 8:
149         tty.c_cflag |= CS8;
150         break;
151     case 7:
152         tty.c_cflag |= CS7;
153         break;
154     case 6:
155         tty.c_cflag |= CS6;
156         break;
157     case 5:
158         tty.c_cflag |= CS5;
159         break;
160     }
161     switch (parity) {
162     default:
163     case 'N':
164         break;
165     case 'E':
166         tty.c_cflag |= PARENB;
167         break;
168     case 'O':
169         tty.c_cflag |= PARENB | PARODD;
170         break;
171     }
172     if (stop_bits == 2) {
173         tty.c_cflag |= CSTOPB;
174     }
175 
176     tcsetattr(fd, TCSANOW, &tty);
177 }
178 
179 static int tty_serial_ioctl(Chardev *chr, int cmd, void *arg)
180 {
181     FDChardev *s = FD_CHARDEV(chr);
182     QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc_in);
183 
184     switch (cmd) {
185     case CHR_IOCTL_SERIAL_SET_PARAMS:
186         {
187             QEMUSerialSetParams *ssp = arg;
188             tty_serial_init(fioc->fd,
189                             ssp->speed, ssp->parity,
190                             ssp->data_bits, ssp->stop_bits);
191         }
192         break;
193     case CHR_IOCTL_SERIAL_SET_BREAK:
194         {
195             int enable = *(int *)arg;
196             if (enable) {
197                 tcsendbreak(fioc->fd, 1);
198             }
199         }
200         break;
201     case CHR_IOCTL_SERIAL_GET_TIOCM:
202         {
203             int sarg = 0;
204             int *targ = (int *)arg;
205             ioctl(fioc->fd, TIOCMGET, &sarg);
206             *targ = 0;
207             if (sarg & TIOCM_CTS) {
208                 *targ |= CHR_TIOCM_CTS;
209             }
210             if (sarg & TIOCM_CAR) {
211                 *targ |= CHR_TIOCM_CAR;
212             }
213             if (sarg & TIOCM_DSR) {
214                 *targ |= CHR_TIOCM_DSR;
215             }
216             if (sarg & TIOCM_RI) {
217                 *targ |= CHR_TIOCM_RI;
218             }
219             if (sarg & TIOCM_DTR) {
220                 *targ |= CHR_TIOCM_DTR;
221             }
222             if (sarg & TIOCM_RTS) {
223                 *targ |= CHR_TIOCM_RTS;
224             }
225         }
226         break;
227     case CHR_IOCTL_SERIAL_SET_TIOCM:
228         {
229             int sarg = *(int *)arg;
230             int targ = 0;
231             ioctl(fioc->fd, TIOCMGET, &targ);
232             targ &= ~(CHR_TIOCM_CTS | CHR_TIOCM_CAR | CHR_TIOCM_DSR
233                      | CHR_TIOCM_RI | CHR_TIOCM_DTR | CHR_TIOCM_RTS);
234             if (sarg & CHR_TIOCM_CTS) {
235                 targ |= TIOCM_CTS;
236             }
237             if (sarg & CHR_TIOCM_CAR) {
238                 targ |= TIOCM_CAR;
239             }
240             if (sarg & CHR_TIOCM_DSR) {
241                 targ |= TIOCM_DSR;
242             }
243             if (sarg & CHR_TIOCM_RI) {
244                 targ |= TIOCM_RI;
245             }
246             if (sarg & CHR_TIOCM_DTR) {
247                 targ |= TIOCM_DTR;
248             }
249             if (sarg & CHR_TIOCM_RTS) {
250                 targ |= TIOCM_RTS;
251             }
252             ioctl(fioc->fd, TIOCMSET, &targ);
253         }
254         break;
255     default:
256         return -ENOTSUP;
257     }
258     return 0;
259 }
260 
261 static void qmp_chardev_open_serial(Chardev *chr,
262                                     ChardevBackend *backend,
263                                     bool *be_opened,
264                                     Error **errp)
265 {
266     ChardevHostdev *serial = backend->u.serial.data;
267     int fd;
268 
269     fd = qmp_chardev_open_file_source(serial->device, O_RDWR | O_NONBLOCK,
270                                       errp);
271     if (fd < 0) {
272         return;
273     }
274     qemu_set_nonblock(fd);
275     tty_serial_init(fd, 115200, 'N', 8, 1);
276 
277     qemu_chr_open_fd(chr, fd, fd);
278 }
279 #endif /* __linux__ || __sun__ */
280 
281 #ifdef HAVE_CHARDEV_SERIAL
282 static void qemu_chr_parse_serial(QemuOpts *opts, ChardevBackend *backend,
283                                   Error **errp)
284 {
285     const char *device = qemu_opt_get(opts, "path");
286     ChardevHostdev *serial;
287 
288     if (device == NULL) {
289         error_setg(errp, "chardev: serial/tty: no device path given");
290         return;
291     }
292     backend->type = CHARDEV_BACKEND_KIND_SERIAL;
293     serial = backend->u.serial.data = g_new0(ChardevHostdev, 1);
294     qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(serial));
295     serial->device = g_strdup(device);
296 }
297 
298 static void char_serial_class_init(ObjectClass *oc, void *data)
299 {
300     ChardevClass *cc = CHARDEV_CLASS(oc);
301 
302     cc->parse = qemu_chr_parse_serial;
303     cc->open = qmp_chardev_open_serial;
304 #ifndef _WIN32
305     cc->chr_ioctl = tty_serial_ioctl;
306 #endif
307 }
308 
309 
310 static const TypeInfo char_serial_type_info = {
311     .name = TYPE_CHARDEV_SERIAL,
312 #ifdef _WIN32
313     .parent = TYPE_CHARDEV_WIN,
314 #else
315     .parent = TYPE_CHARDEV_FD,
316 #endif
317     .class_init = char_serial_class_init,
318 };
319 
320 static void register_types(void)
321 {
322     type_register_static(&char_serial_type_info);
323 }
324 
325 type_init(register_types);
326 
327 #endif
328