Commit | Line | Data |
---|---|---|
c906108c | 1 | /* Serial interface for local (hardwired) serial ports on Un*x like systems |
1e4728e7 | 2 | |
b811d2c2 | 3 | Copyright (C) 1992-2020 Free Software Foundation, Inc. |
c906108c | 4 | |
c5aa993b | 5 | This file is part of GDB. |
c906108c | 6 | |
c5aa993b JM |
7 | This program is free software; you can redistribute it and/or modify |
8 | it under the terms of the GNU General Public License as published by | |
a9762ec7 | 9 | the Free Software Foundation; either version 3 of the License, or |
c5aa993b | 10 | (at your option) any later version. |
c906108c | 11 | |
c5aa993b JM |
12 | This program is distributed in the hope that it will be useful, |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
c906108c | 16 | |
c5aa993b | 17 | You should have received a copy of the GNU General Public License |
a9762ec7 | 18 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
c906108c SS |
19 | |
20 | #include "defs.h" | |
21 | #include "serial.h" | |
3eb25fda | 22 | #include "ser-base.h" |
c2c6d25f JM |
23 | #include "ser-unix.h" |
24 | ||
c906108c SS |
25 | #include <fcntl.h> |
26 | #include <sys/types.h> | |
27 | #include "terminal.h" | |
c2c6d25f | 28 | #include <sys/socket.h> |
268a13a5 | 29 | #include "gdbsupport/gdb_sys_time.h" |
c2c6d25f | 30 | |
0ea3f30e | 31 | #include "gdb_select.h" |
23776285 | 32 | #include "gdbcmd.h" |
268a13a5 | 33 | #include "gdbsupport/filestuff.h" |
726e1356 | 34 | #include <termios.h> |
766f8836 | 35 | #include "inflow.h" |
c906108c SS |
36 | |
37 | struct hardwire_ttystate | |
c5aa993b JM |
38 | { |
39 | struct termios termios; | |
40 | }; | |
23776285 MR |
41 | |
42 | #ifdef CRTSCTS | |
43 | /* Boolean to explicitly enable or disable h/w flow control. */ | |
491144b5 | 44 | static bool serial_hwflow; |
23776285 MR |
45 | static void |
46 | show_serial_hwflow (struct ui_file *file, int from_tty, | |
47 | struct cmd_list_element *c, const char *value) | |
48 | { | |
49 | fprintf_filtered (file, _("Hardware flow control is %s.\n"), value); | |
50 | } | |
51 | #endif | |
52 | ||
819cc324 AC |
53 | static int hardwire_open (struct serial *scb, const char *name); |
54 | static void hardwire_raw (struct serial *scb); | |
c2c6d25f | 55 | static int rate_to_code (int rate); |
819cc324 | 56 | static int hardwire_setbaudrate (struct serial *scb, int rate); |
236af5e3 | 57 | static int hardwire_setparity (struct serial *scb, int parity); |
819cc324 AC |
58 | static void hardwire_close (struct serial *scb); |
59 | static int get_tty_state (struct serial *scb, | |
60 | struct hardwire_ttystate * state); | |
61 | static int set_tty_state (struct serial *scb, | |
62 | struct hardwire_ttystate * state); | |
63 | static serial_ttystate hardwire_get_tty_state (struct serial *scb); | |
64 | static int hardwire_set_tty_state (struct serial *scb, serial_ttystate state); | |
819cc324 AC |
65 | static void hardwire_print_tty_state (struct serial *, serial_ttystate, |
66 | struct ui_file *); | |
67 | static int hardwire_drain_output (struct serial *); | |
68 | static int hardwire_flush_output (struct serial *); | |
69 | static int hardwire_flush_input (struct serial *); | |
70 | static int hardwire_send_break (struct serial *); | |
71 | static int hardwire_setstopbits (struct serial *, int); | |
72 | ||
c378eb4e | 73 | /* Open up a real live device for serial I/O. */ |
c906108c SS |
74 | |
75 | static int | |
819cc324 | 76 | hardwire_open (struct serial *scb, const char *name) |
c906108c | 77 | { |
614c279d | 78 | scb->fd = gdb_open_cloexec (name, O_RDWR, 0); |
c906108c SS |
79 | if (scb->fd < 0) |
80 | return -1; | |
81 | ||
82 | return 0; | |
83 | } | |
84 | ||
85 | static int | |
819cc324 | 86 | get_tty_state (struct serial *scb, struct hardwire_ttystate *state) |
c906108c | 87 | { |
c5aa993b | 88 | if (tcgetattr (scb->fd, &state->termios) < 0) |
c906108c SS |
89 | return -1; |
90 | ||
91 | return 0; | |
c906108c SS |
92 | } |
93 | ||
94 | static int | |
819cc324 | 95 | set_tty_state (struct serial *scb, struct hardwire_ttystate *state) |
c906108c | 96 | { |
c5aa993b | 97 | if (tcsetattr (scb->fd, TCSANOW, &state->termios) < 0) |
c906108c SS |
98 | return -1; |
99 | ||
100 | return 0; | |
c906108c SS |
101 | } |
102 | ||
103 | static serial_ttystate | |
819cc324 | 104 | hardwire_get_tty_state (struct serial *scb) |
c906108c | 105 | { |
8d749320 | 106 | struct hardwire_ttystate *state = XNEW (struct hardwire_ttystate); |
c906108c | 107 | |
c5aa993b | 108 | if (get_tty_state (scb, state)) |
0b2381f5 MS |
109 | { |
110 | xfree (state); | |
111 | return NULL; | |
112 | } | |
c906108c | 113 | |
c5aa993b | 114 | return (serial_ttystate) state; |
c906108c SS |
115 | } |
116 | ||
1e182ce8 UW |
117 | static serial_ttystate |
118 | hardwire_copy_tty_state (struct serial *scb, serial_ttystate ttystate) | |
119 | { | |
8d749320 | 120 | struct hardwire_ttystate *state = XNEW (struct hardwire_ttystate); |
1e182ce8 | 121 | |
1e182ce8 UW |
122 | *state = *(struct hardwire_ttystate *) ttystate; |
123 | ||
124 | return (serial_ttystate) state; | |
125 | } | |
126 | ||
c906108c | 127 | static int |
819cc324 | 128 | hardwire_set_tty_state (struct serial *scb, serial_ttystate ttystate) |
c906108c SS |
129 | { |
130 | struct hardwire_ttystate *state; | |
131 | ||
c5aa993b | 132 | state = (struct hardwire_ttystate *) ttystate; |
c906108c | 133 | |
c5aa993b | 134 | return set_tty_state (scb, state); |
c906108c SS |
135 | } |
136 | ||
c906108c | 137 | static void |
819cc324 | 138 | hardwire_print_tty_state (struct serial *scb, |
c2c6d25f | 139 | serial_ttystate ttystate, |
d9fcf2fb | 140 | struct ui_file *stream) |
c906108c SS |
141 | { |
142 | struct hardwire_ttystate *state = (struct hardwire_ttystate *) ttystate; | |
143 | int i; | |
144 | ||
c2c6d25f | 145 | fprintf_filtered (stream, "c_iflag = 0x%x, c_oflag = 0x%x,\n", |
2acceee2 JM |
146 | (int) state->termios.c_iflag, |
147 | (int) state->termios.c_oflag); | |
c2c6d25f | 148 | fprintf_filtered (stream, "c_cflag = 0x%x, c_lflag = 0x%x\n", |
2acceee2 JM |
149 | (int) state->termios.c_cflag, |
150 | (int) state->termios.c_lflag); | |
c906108c SS |
151 | #if 0 |
152 | /* This not in POSIX, and is not really documented by those systems | |
153 | which have it (at least not Sun). */ | |
c2c6d25f | 154 | fprintf_filtered (stream, "c_line = 0x%x.\n", state->termios.c_line); |
c906108c | 155 | #endif |
c2c6d25f | 156 | fprintf_filtered (stream, "c_cc: "); |
c906108c | 157 | for (i = 0; i < NCCS; i += 1) |
c2c6d25f JM |
158 | fprintf_filtered (stream, "0x%x ", state->termios.c_cc[i]); |
159 | fprintf_filtered (stream, "\n"); | |
c906108c SS |
160 | } |
161 | ||
c378eb4e MS |
162 | /* Wait for the output to drain away, as opposed to flushing |
163 | (discarding) it. */ | |
c906108c SS |
164 | |
165 | static int | |
819cc324 | 166 | hardwire_drain_output (struct serial *scb) |
c906108c | 167 | { |
766f8836 AH |
168 | /* Ignore SIGTTOU which may occur during the drain. */ |
169 | scoped_ignore_sigttou ignore_sigttou; | |
170 | ||
c906108c | 171 | return tcdrain (scb->fd); |
c906108c SS |
172 | } |
173 | ||
174 | static int | |
819cc324 | 175 | hardwire_flush_output (struct serial *scb) |
c906108c | 176 | { |
c906108c | 177 | return tcflush (scb->fd, TCOFLUSH); |
c906108c SS |
178 | } |
179 | ||
180 | static int | |
819cc324 | 181 | hardwire_flush_input (struct serial *scb) |
c906108c | 182 | { |
dd5da072 | 183 | ser_base_flush_input (scb); |
c906108c | 184 | |
c906108c | 185 | return tcflush (scb->fd, TCIFLUSH); |
c906108c SS |
186 | } |
187 | ||
188 | static int | |
819cc324 | 189 | hardwire_send_break (struct serial *scb) |
c906108c | 190 | { |
c906108c | 191 | return tcsendbreak (scb->fd, 0); |
c906108c SS |
192 | } |
193 | ||
194 | static void | |
819cc324 | 195 | hardwire_raw (struct serial *scb) |
c906108c SS |
196 | { |
197 | struct hardwire_ttystate state; | |
198 | ||
c5aa993b | 199 | if (get_tty_state (scb, &state)) |
3e43a32a MS |
200 | fprintf_unfiltered (gdb_stderr, "get_tty_state failed: %s\n", |
201 | safe_strerror (errno)); | |
c906108c | 202 | |
c906108c SS |
203 | state.termios.c_iflag = 0; |
204 | state.termios.c_oflag = 0; | |
205 | state.termios.c_lflag = 0; | |
236af5e3 | 206 | state.termios.c_cflag &= ~CSIZE; |
c906108c | 207 | state.termios.c_cflag |= CLOCAL | CS8; |
23776285 MR |
208 | #ifdef CRTSCTS |
209 | /* h/w flow control. */ | |
210 | if (serial_hwflow) | |
211 | state.termios.c_cflag |= CRTSCTS; | |
212 | else | |
213 | state.termios.c_cflag &= ~CRTSCTS; | |
214 | #ifdef CRTS_IFLOW | |
215 | if (serial_hwflow) | |
216 | state.termios.c_cflag |= CRTS_IFLOW; | |
217 | else | |
218 | state.termios.c_cflag &= ~CRTS_IFLOW; | |
219 | #endif | |
220 | #endif | |
c906108c SS |
221 | state.termios.c_cc[VMIN] = 0; |
222 | state.termios.c_cc[VTIME] = 0; | |
c906108c | 223 | |
c906108c | 224 | if (set_tty_state (scb, &state)) |
3e43a32a MS |
225 | fprintf_unfiltered (gdb_stderr, "set_tty_state failed: %s\n", |
226 | safe_strerror (errno)); | |
c906108c SS |
227 | } |
228 | ||
c906108c SS |
229 | #ifndef B19200 |
230 | #define B19200 EXTA | |
231 | #endif | |
232 | ||
233 | #ifndef B38400 | |
234 | #define B38400 EXTB | |
235 | #endif | |
236 | ||
237 | /* Translate baud rates from integers to damn B_codes. Unix should | |
238 | have outgrown this crap years ago, but even POSIX wouldn't buck it. */ | |
239 | ||
240 | static struct | |
241 | { | |
242 | int rate; | |
243 | int code; | |
244 | } | |
245 | baudtab[] = | |
246 | { | |
c5aa993b JM |
247 | { |
248 | 50, B50 | |
249 | } | |
250 | , | |
251 | { | |
252 | 75, B75 | |
253 | } | |
254 | , | |
255 | { | |
256 | 110, B110 | |
257 | } | |
258 | , | |
259 | { | |
260 | 134, B134 | |
261 | } | |
262 | , | |
263 | { | |
264 | 150, B150 | |
265 | } | |
266 | , | |
267 | { | |
268 | 200, B200 | |
269 | } | |
270 | , | |
271 | { | |
272 | 300, B300 | |
273 | } | |
274 | , | |
275 | { | |
276 | 600, B600 | |
277 | } | |
278 | , | |
279 | { | |
280 | 1200, B1200 | |
281 | } | |
282 | , | |
283 | { | |
284 | 1800, B1800 | |
285 | } | |
286 | , | |
287 | { | |
288 | 2400, B2400 | |
289 | } | |
290 | , | |
291 | { | |
292 | 4800, B4800 | |
293 | } | |
294 | , | |
295 | { | |
296 | 9600, B9600 | |
297 | } | |
298 | , | |
299 | { | |
300 | 19200, B19200 | |
301 | } | |
302 | , | |
303 | { | |
304 | 38400, B38400 | |
305 | } | |
306 | , | |
c906108c | 307 | #ifdef B57600 |
c5aa993b JM |
308 | { |
309 | 57600, B57600 | |
310 | } | |
311 | , | |
c906108c SS |
312 | #endif |
313 | #ifdef B115200 | |
c5aa993b JM |
314 | { |
315 | 115200, B115200 | |
316 | } | |
317 | , | |
c906108c SS |
318 | #endif |
319 | #ifdef B230400 | |
c5aa993b JM |
320 | { |
321 | 230400, B230400 | |
322 | } | |
323 | , | |
c906108c SS |
324 | #endif |
325 | #ifdef B460800 | |
c5aa993b JM |
326 | { |
327 | 460800, B460800 | |
328 | } | |
329 | , | |
c906108c | 330 | #endif |
c5aa993b JM |
331 | { |
332 | -1, -1 | |
333 | } | |
334 | , | |
c906108c SS |
335 | }; |
336 | ||
c5aa993b | 337 | static int |
c2c6d25f | 338 | rate_to_code (int rate) |
c906108c SS |
339 | { |
340 | int i; | |
341 | ||
342 | for (i = 0; baudtab[i].rate != -1; i++) | |
08b4f080 | 343 | { |
c378eb4e | 344 | /* test for perfect macth. */ |
08b4f080 FN |
345 | if (rate == baudtab[i].rate) |
346 | return baudtab[i].code; | |
347 | else | |
348 | { | |
c378eb4e | 349 | /* check if it is in between valid values. */ |
08b4f080 FN |
350 | if (rate < baudtab[i].rate) |
351 | { | |
352 | if (i) | |
353 | { | |
3e43a32a MS |
354 | warning (_("Invalid baud rate %d. " |
355 | "Closest values are %d and %d."), | |
356 | rate, baudtab[i - 1].rate, baudtab[i].rate); | |
08b4f080 FN |
357 | } |
358 | else | |
359 | { | |
8a3fe4f8 | 360 | warning (_("Invalid baud rate %d. Minimum value is %d."), |
3e43a32a | 361 | rate, baudtab[0].rate); |
08b4f080 FN |
362 | } |
363 | return -1; | |
364 | } | |
365 | } | |
366 | } | |
367 | ||
c378eb4e | 368 | /* The requested speed was too large. */ |
8a3fe4f8 | 369 | warning (_("Invalid baud rate %d. Maximum value is %d."), |
08b4f080 | 370 | rate, baudtab[i - 1].rate); |
c906108c SS |
371 | return -1; |
372 | } | |
373 | ||
374 | static int | |
819cc324 | 375 | hardwire_setbaudrate (struct serial *scb, int rate) |
c906108c SS |
376 | { |
377 | struct hardwire_ttystate state; | |
08b4f080 FN |
378 | int baud_code = rate_to_code (rate); |
379 | ||
380 | if (baud_code < 0) | |
381 | { | |
382 | /* The baud rate was not valid. | |
c378eb4e | 383 | A warning has already been issued. */ |
08b4f080 FN |
384 | errno = EINVAL; |
385 | return -1; | |
386 | } | |
c906108c | 387 | |
c5aa993b | 388 | if (get_tty_state (scb, &state)) |
c906108c SS |
389 | return -1; |
390 | ||
08b4f080 FN |
391 | cfsetospeed (&state.termios, baud_code); |
392 | cfsetispeed (&state.termios, baud_code); | |
c906108c SS |
393 | |
394 | return set_tty_state (scb, &state); | |
395 | } | |
396 | ||
397 | static int | |
819cc324 | 398 | hardwire_setstopbits (struct serial *scb, int num) |
c906108c SS |
399 | { |
400 | struct hardwire_ttystate state; | |
401 | int newbit; | |
402 | ||
c5aa993b | 403 | if (get_tty_state (scb, &state)) |
c906108c SS |
404 | return -1; |
405 | ||
406 | switch (num) | |
407 | { | |
408 | case SERIAL_1_STOPBITS: | |
409 | newbit = 0; | |
410 | break; | |
411 | case SERIAL_1_AND_A_HALF_STOPBITS: | |
412 | case SERIAL_2_STOPBITS: | |
413 | newbit = 1; | |
414 | break; | |
415 | default: | |
416 | return 1; | |
417 | } | |
418 | ||
c906108c SS |
419 | if (!newbit) |
420 | state.termios.c_cflag &= ~CSTOPB; | |
421 | else | |
c5aa993b | 422 | state.termios.c_cflag |= CSTOPB; /* two bits */ |
c906108c SS |
423 | |
424 | return set_tty_state (scb, &state); | |
425 | } | |
426 | ||
236af5e3 YG |
427 | /* Implement the "setparity" serial_ops callback. */ |
428 | ||
429 | static int | |
430 | hardwire_setparity (struct serial *scb, int parity) | |
431 | { | |
432 | struct hardwire_ttystate state; | |
433 | int newparity = 0; | |
434 | ||
435 | if (get_tty_state (scb, &state)) | |
436 | return -1; | |
437 | ||
438 | switch (parity) | |
439 | { | |
440 | case GDBPARITY_NONE: | |
441 | newparity = 0; | |
442 | break; | |
443 | case GDBPARITY_ODD: | |
444 | newparity = PARENB | PARODD; | |
445 | break; | |
446 | case GDBPARITY_EVEN: | |
447 | newparity = PARENB; | |
448 | break; | |
449 | default: | |
450 | internal_warning (__FILE__, __LINE__, | |
8a4506c0 | 451 | "Incorrect parity value: %d", parity); |
236af5e3 YG |
452 | return -1; |
453 | } | |
454 | ||
236af5e3 YG |
455 | state.termios.c_cflag &= ~(PARENB | PARODD); |
456 | state.termios.c_cflag |= newparity; | |
236af5e3 | 457 | |
236af5e3 YG |
458 | return set_tty_state (scb, &state); |
459 | } | |
460 | ||
461 | ||
c906108c | 462 | static void |
819cc324 | 463 | hardwire_close (struct serial *scb) |
c906108c SS |
464 | { |
465 | if (scb->fd < 0) | |
466 | return; | |
467 | ||
c5aa993b | 468 | close (scb->fd); |
c906108c SS |
469 | scb->fd = -1; |
470 | } | |
c2c6d25f | 471 | \f |
2acceee2 | 472 | \f |
433759f7 | 473 | |
12e8c7d7 TT |
474 | /* The hardwire ops. */ |
475 | ||
476 | static const struct serial_ops hardwire_ops = | |
477 | { | |
478 | "hardwire", | |
479 | hardwire_open, | |
480 | hardwire_close, | |
481 | NULL, | |
9bcbdca8 | 482 | ser_base_readchar, |
12e8c7d7 TT |
483 | ser_base_write, |
484 | hardwire_flush_output, | |
485 | hardwire_flush_input, | |
486 | hardwire_send_break, | |
487 | hardwire_raw, | |
488 | hardwire_get_tty_state, | |
489 | hardwire_copy_tty_state, | |
490 | hardwire_set_tty_state, | |
491 | hardwire_print_tty_state, | |
12e8c7d7 TT |
492 | hardwire_setbaudrate, |
493 | hardwire_setstopbits, | |
236af5e3 | 494 | hardwire_setparity, |
12e8c7d7 TT |
495 | hardwire_drain_output, |
496 | ser_base_async, | |
497 | ser_unix_read_prim, | |
498 | ser_unix_write_prim | |
499 | }; | |
500 | ||
501 | void | |
502 | _initialize_ser_hardwire (void) | |
503 | { | |
504 | serial_add_interface (&hardwire_ops); | |
23776285 | 505 | |
23776285 MR |
506 | #ifdef CRTSCTS |
507 | add_setshow_boolean_cmd ("remoteflow", no_class, | |
508 | &serial_hwflow, _("\ | |
509 | Set use of hardware flow control for remote serial I/O."), _("\ | |
510 | Show use of hardware flow control for remote serial I/O."), _("\ | |
511 | Enable or disable hardware flow control (RTS/CTS) on the serial port\n\ | |
512 | when debugging using remote targets."), | |
513 | NULL, | |
514 | show_serial_hwflow, | |
515 | &setlist, &showlist); | |
516 | #endif | |
c906108c | 517 | } |
b4505029 MM |
518 | |
519 | int | |
520 | ser_unix_read_prim (struct serial *scb, size_t count) | |
521 | { | |
75ee5925 | 522 | return read (scb->fd, scb->buf, count); |
b4505029 MM |
523 | } |
524 | ||
525 | int | |
526 | ser_unix_write_prim (struct serial *scb, const void *buf, size_t len) | |
527 | { | |
b4505029 MM |
528 | return write (scb->fd, buf, len); |
529 | } |