xref: /qemu/chardev/char-serial.c (revision 2b2f23da)
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