]>
Commit | Line | Data |
---|---|---|
c906108c | 1 | /* Serial interface for local (hardwired) serial ports on Un*x like systems |
1e4728e7 | 2 | |
1d506c26 | 3 | Copyright (C) 1992-2024 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 | |
06cc9596 | 31 | #include "gdbsupport/gdb_select.h" |
23776285 | 32 | #include "gdbcmd.h" |
268a13a5 | 33 | #include "gdbsupport/filestuff.h" |
726e1356 | 34 | #include <termios.h> |
965febe5 | 35 | #include "gdbsupport/scoped_ignore_sigttou.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 | { | |
6cb06a8c | 49 | gdb_printf (file, _("Hardware flow control is %s.\n"), value); |
23776285 MR |
50 | } |
51 | #endif | |
52 | ||
819cc324 | 53 | static void hardwire_raw (struct serial *scb); |
c2c6d25f | 54 | static int rate_to_code (int rate); |
ad3cf8c6 | 55 | static void hardwire_setbaudrate (struct serial *scb, int rate); |
236af5e3 | 56 | static int hardwire_setparity (struct serial *scb, int parity); |
819cc324 AC |
57 | static void hardwire_close (struct serial *scb); |
58 | static int get_tty_state (struct serial *scb, | |
59 | struct hardwire_ttystate * state); | |
60 | static int set_tty_state (struct serial *scb, | |
61 | struct hardwire_ttystate * state); | |
62 | static serial_ttystate hardwire_get_tty_state (struct serial *scb); | |
63 | static int hardwire_set_tty_state (struct serial *scb, serial_ttystate state); | |
819cc324 AC |
64 | static void hardwire_print_tty_state (struct serial *, serial_ttystate, |
65 | struct ui_file *); | |
66 | static int hardwire_drain_output (struct serial *); | |
67 | static int hardwire_flush_output (struct serial *); | |
68 | static int hardwire_flush_input (struct serial *); | |
d69939bd | 69 | static void hardwire_send_break (struct serial *); |
819cc324 AC |
70 | static int hardwire_setstopbits (struct serial *, int); |
71 | ||
c378eb4e | 72 | /* Open up a real live device for serial I/O. */ |
c906108c | 73 | |
a2e0acea | 74 | static void |
819cc324 | 75 | hardwire_open (struct serial *scb, const char *name) |
c906108c | 76 | { |
13084383 | 77 | scb->fd = gdb_open_cloexec (name, O_RDWR, 0).release (); |
c906108c | 78 | if (scb->fd < 0) |
a2e0acea | 79 | perror_with_name ("could not open device"); |
c906108c SS |
80 | } |
81 | ||
82 | static int | |
819cc324 | 83 | get_tty_state (struct serial *scb, struct hardwire_ttystate *state) |
c906108c | 84 | { |
c5aa993b | 85 | if (tcgetattr (scb->fd, &state->termios) < 0) |
c906108c SS |
86 | return -1; |
87 | ||
88 | return 0; | |
c906108c SS |
89 | } |
90 | ||
91 | static int | |
819cc324 | 92 | set_tty_state (struct serial *scb, struct hardwire_ttystate *state) |
c906108c | 93 | { |
c5aa993b | 94 | if (tcsetattr (scb->fd, TCSANOW, &state->termios) < 0) |
c906108c SS |
95 | return -1; |
96 | ||
97 | return 0; | |
c906108c SS |
98 | } |
99 | ||
100 | static serial_ttystate | |
819cc324 | 101 | hardwire_get_tty_state (struct serial *scb) |
c906108c | 102 | { |
8d749320 | 103 | struct hardwire_ttystate *state = XNEW (struct hardwire_ttystate); |
c906108c | 104 | |
c5aa993b | 105 | if (get_tty_state (scb, state)) |
0b2381f5 MS |
106 | { |
107 | xfree (state); | |
108 | return NULL; | |
109 | } | |
c906108c | 110 | |
c5aa993b | 111 | return (serial_ttystate) state; |
c906108c SS |
112 | } |
113 | ||
1e182ce8 UW |
114 | static serial_ttystate |
115 | hardwire_copy_tty_state (struct serial *scb, serial_ttystate ttystate) | |
116 | { | |
8d749320 | 117 | struct hardwire_ttystate *state = XNEW (struct hardwire_ttystate); |
1e182ce8 | 118 | |
1e182ce8 UW |
119 | *state = *(struct hardwire_ttystate *) ttystate; |
120 | ||
121 | return (serial_ttystate) state; | |
122 | } | |
123 | ||
c906108c | 124 | static int |
819cc324 | 125 | hardwire_set_tty_state (struct serial *scb, serial_ttystate ttystate) |
c906108c SS |
126 | { |
127 | struct hardwire_ttystate *state; | |
128 | ||
c5aa993b | 129 | state = (struct hardwire_ttystate *) ttystate; |
c906108c | 130 | |
c5aa993b | 131 | return set_tty_state (scb, state); |
c906108c SS |
132 | } |
133 | ||
c906108c | 134 | static void |
819cc324 | 135 | hardwire_print_tty_state (struct serial *scb, |
c2c6d25f | 136 | serial_ttystate ttystate, |
d9fcf2fb | 137 | struct ui_file *stream) |
c906108c SS |
138 | { |
139 | struct hardwire_ttystate *state = (struct hardwire_ttystate *) ttystate; | |
140 | int i; | |
141 | ||
6cb06a8c TT |
142 | gdb_printf (stream, "c_iflag = 0x%x, c_oflag = 0x%x,\n", |
143 | (int) state->termios.c_iflag, | |
144 | (int) state->termios.c_oflag); | |
145 | gdb_printf (stream, "c_cflag = 0x%x, c_lflag = 0x%x\n", | |
146 | (int) state->termios.c_cflag, | |
147 | (int) state->termios.c_lflag); | |
c906108c SS |
148 | #if 0 |
149 | /* This not in POSIX, and is not really documented by those systems | |
150 | which have it (at least not Sun). */ | |
6cb06a8c | 151 | gdb_printf (stream, "c_line = 0x%x.\n", state->termios.c_line); |
c906108c | 152 | #endif |
6cb06a8c | 153 | gdb_printf (stream, "c_cc: "); |
c906108c | 154 | for (i = 0; i < NCCS; i += 1) |
6cb06a8c TT |
155 | gdb_printf (stream, "0x%x ", state->termios.c_cc[i]); |
156 | gdb_printf (stream, "\n"); | |
c906108c SS |
157 | } |
158 | ||
c378eb4e MS |
159 | /* Wait for the output to drain away, as opposed to flushing |
160 | (discarding) it. */ | |
c906108c SS |
161 | |
162 | static int | |
819cc324 | 163 | hardwire_drain_output (struct serial *scb) |
c906108c | 164 | { |
766f8836 AH |
165 | /* Ignore SIGTTOU which may occur during the drain. */ |
166 | scoped_ignore_sigttou ignore_sigttou; | |
167 | ||
c906108c | 168 | return tcdrain (scb->fd); |
c906108c SS |
169 | } |
170 | ||
171 | static int | |
819cc324 | 172 | hardwire_flush_output (struct serial *scb) |
c906108c | 173 | { |
c906108c | 174 | return tcflush (scb->fd, TCOFLUSH); |
c906108c SS |
175 | } |
176 | ||
177 | static int | |
819cc324 | 178 | hardwire_flush_input (struct serial *scb) |
c906108c | 179 | { |
dd5da072 | 180 | ser_base_flush_input (scb); |
c906108c | 181 | |
c906108c | 182 | return tcflush (scb->fd, TCIFLUSH); |
c906108c SS |
183 | } |
184 | ||
d69939bd | 185 | static void |
819cc324 | 186 | hardwire_send_break (struct serial *scb) |
c906108c | 187 | { |
d69939bd TT |
188 | if (tcsendbreak (scb->fd, 0) == -1) |
189 | perror_with_name ("sending break"); | |
c906108c SS |
190 | } |
191 | ||
192 | static void | |
819cc324 | 193 | hardwire_raw (struct serial *scb) |
c906108c SS |
194 | { |
195 | struct hardwire_ttystate state; | |
196 | ||
c5aa993b | 197 | if (get_tty_state (scb, &state)) |
6cb06a8c TT |
198 | gdb_printf (gdb_stderr, "get_tty_state failed: %s\n", |
199 | safe_strerror (errno)); | |
c906108c | 200 | |
c906108c SS |
201 | state.termios.c_iflag = 0; |
202 | state.termios.c_oflag = 0; | |
203 | state.termios.c_lflag = 0; | |
236af5e3 | 204 | state.termios.c_cflag &= ~CSIZE; |
c906108c | 205 | state.termios.c_cflag |= CLOCAL | CS8; |
23776285 MR |
206 | #ifdef CRTSCTS |
207 | /* h/w flow control. */ | |
208 | if (serial_hwflow) | |
209 | state.termios.c_cflag |= CRTSCTS; | |
210 | else | |
211 | state.termios.c_cflag &= ~CRTSCTS; | |
212 | #ifdef CRTS_IFLOW | |
213 | if (serial_hwflow) | |
214 | state.termios.c_cflag |= CRTS_IFLOW; | |
215 | else | |
216 | state.termios.c_cflag &= ~CRTS_IFLOW; | |
217 | #endif | |
218 | #endif | |
c906108c SS |
219 | state.termios.c_cc[VMIN] = 0; |
220 | state.termios.c_cc[VTIME] = 0; | |
c906108c | 221 | |
c906108c | 222 | if (set_tty_state (scb, &state)) |
6cb06a8c TT |
223 | gdb_printf (gdb_stderr, "set_tty_state failed: %s\n", |
224 | safe_strerror (errno)); | |
c906108c SS |
225 | } |
226 | ||
c906108c SS |
227 | #ifndef B19200 |
228 | #define B19200 EXTA | |
229 | #endif | |
230 | ||
231 | #ifndef B38400 | |
232 | #define B38400 EXTB | |
233 | #endif | |
234 | ||
235 | /* Translate baud rates from integers to damn B_codes. Unix should | |
236 | have outgrown this crap years ago, but even POSIX wouldn't buck it. */ | |
237 | ||
238 | static struct | |
239 | { | |
240 | int rate; | |
241 | int code; | |
242 | } | |
243 | baudtab[] = | |
244 | { | |
c5aa993b JM |
245 | { |
246 | 50, B50 | |
247 | } | |
248 | , | |
249 | { | |
250 | 75, B75 | |
251 | } | |
252 | , | |
253 | { | |
254 | 110, B110 | |
255 | } | |
256 | , | |
257 | { | |
258 | 134, B134 | |
259 | } | |
260 | , | |
261 | { | |
262 | 150, B150 | |
263 | } | |
264 | , | |
265 | { | |
266 | 200, B200 | |
267 | } | |
268 | , | |
269 | { | |
270 | 300, B300 | |
271 | } | |
272 | , | |
273 | { | |
274 | 600, B600 | |
275 | } | |
276 | , | |
277 | { | |
278 | 1200, B1200 | |
279 | } | |
280 | , | |
281 | { | |
282 | 1800, B1800 | |
283 | } | |
284 | , | |
285 | { | |
286 | 2400, B2400 | |
287 | } | |
288 | , | |
289 | { | |
290 | 4800, B4800 | |
291 | } | |
292 | , | |
293 | { | |
294 | 9600, B9600 | |
295 | } | |
296 | , | |
297 | { | |
298 | 19200, B19200 | |
299 | } | |
300 | , | |
301 | { | |
302 | 38400, B38400 | |
303 | } | |
304 | , | |
c906108c | 305 | #ifdef B57600 |
c5aa993b JM |
306 | { |
307 | 57600, B57600 | |
308 | } | |
309 | , | |
c906108c SS |
310 | #endif |
311 | #ifdef B115200 | |
c5aa993b JM |
312 | { |
313 | 115200, B115200 | |
314 | } | |
315 | , | |
c906108c SS |
316 | #endif |
317 | #ifdef B230400 | |
c5aa993b JM |
318 | { |
319 | 230400, B230400 | |
320 | } | |
321 | , | |
c906108c SS |
322 | #endif |
323 | #ifdef B460800 | |
c5aa993b JM |
324 | { |
325 | 460800, B460800 | |
326 | } | |
327 | , | |
78d16865 DC |
328 | #endif |
329 | #ifdef B500000 | |
330 | { | |
331 | 500000, B500000 | |
332 | } | |
333 | , | |
334 | #endif | |
335 | #ifdef B576000 | |
336 | { | |
337 | 576000, B576000 | |
338 | } | |
339 | , | |
340 | #endif | |
341 | #ifdef B921600 | |
342 | { | |
343 | 921600, B921600 | |
344 | } | |
345 | , | |
346 | #endif | |
347 | #ifdef B1000000 | |
348 | { | |
349 | 1000000, B1000000 | |
350 | } | |
351 | , | |
352 | #endif | |
353 | #ifdef B1152000 | |
354 | { | |
355 | 1152000, B1152000 | |
356 | } | |
357 | , | |
358 | #endif | |
359 | #ifdef B1500000 | |
360 | { | |
361 | 1500000, B1500000 | |
362 | } | |
363 | , | |
364 | #endif | |
365 | #ifdef B2000000 | |
366 | { | |
367 | 2000000, B2000000 | |
368 | } | |
369 | , | |
370 | #endif | |
371 | #ifdef B2500000 | |
372 | { | |
373 | 2500000, B2500000 | |
374 | } | |
375 | , | |
376 | #endif | |
377 | #ifdef B3000000 | |
378 | { | |
379 | 3000000, B3000000 | |
380 | } | |
381 | , | |
382 | #endif | |
383 | #ifdef B3500000 | |
384 | { | |
385 | 3500000, B3500000 | |
386 | } | |
387 | , | |
388 | #endif | |
389 | #ifdef B4000000 | |
390 | { | |
391 | 4000000, B4000000 | |
392 | } | |
393 | , | |
c906108c | 394 | #endif |
c5aa993b JM |
395 | { |
396 | -1, -1 | |
397 | } | |
398 | , | |
c906108c SS |
399 | }; |
400 | ||
c5aa993b | 401 | static int |
c2c6d25f | 402 | rate_to_code (int rate) |
c906108c SS |
403 | { |
404 | int i; | |
405 | ||
406 | for (i = 0; baudtab[i].rate != -1; i++) | |
08b4f080 | 407 | { |
c378eb4e | 408 | /* test for perfect macth. */ |
08b4f080 | 409 | if (rate == baudtab[i].rate) |
dda83cd7 | 410 | return baudtab[i].code; |
08b4f080 | 411 | else |
dda83cd7 | 412 | { |
c378eb4e | 413 | /* check if it is in between valid values. */ |
dda83cd7 | 414 | if (rate < baudtab[i].rate) |
08b4f080 FN |
415 | { |
416 | if (i) | |
dda83cd7 | 417 | { |
ad3cf8c6 TT |
418 | error (_("Invalid baud rate %d. " |
419 | "Closest values are %d and %d."), | |
420 | rate, baudtab[i - 1].rate, baudtab[i].rate); | |
08b4f080 FN |
421 | } |
422 | else | |
dda83cd7 | 423 | { |
ad3cf8c6 TT |
424 | error (_("Invalid baud rate %d. Minimum value is %d."), |
425 | rate, baudtab[0].rate); | |
08b4f080 | 426 | } |
08b4f080 | 427 | } |
dda83cd7 | 428 | } |
08b4f080 FN |
429 | } |
430 | ||
c378eb4e | 431 | /* The requested speed was too large. */ |
ad3cf8c6 TT |
432 | error (_("Invalid baud rate %d. Maximum value is %d."), |
433 | rate, baudtab[i - 1].rate); | |
c906108c SS |
434 | } |
435 | ||
ad3cf8c6 | 436 | static void |
819cc324 | 437 | hardwire_setbaudrate (struct serial *scb, int rate) |
c906108c SS |
438 | { |
439 | struct hardwire_ttystate state; | |
08b4f080 FN |
440 | int baud_code = rate_to_code (rate); |
441 | ||
c5aa993b | 442 | if (get_tty_state (scb, &state)) |
ad3cf8c6 | 443 | perror_with_name ("could not get tty state"); |
c906108c | 444 | |
08b4f080 FN |
445 | cfsetospeed (&state.termios, baud_code); |
446 | cfsetispeed (&state.termios, baud_code); | |
c906108c | 447 | |
ad3cf8c6 TT |
448 | if (set_tty_state (scb, &state)) |
449 | perror_with_name ("could not set tty state"); | |
c906108c SS |
450 | } |
451 | ||
452 | static int | |
819cc324 | 453 | hardwire_setstopbits (struct serial *scb, int num) |
c906108c SS |
454 | { |
455 | struct hardwire_ttystate state; | |
456 | int newbit; | |
457 | ||
c5aa993b | 458 | if (get_tty_state (scb, &state)) |
c906108c SS |
459 | return -1; |
460 | ||
461 | switch (num) | |
462 | { | |
463 | case SERIAL_1_STOPBITS: | |
464 | newbit = 0; | |
465 | break; | |
466 | case SERIAL_1_AND_A_HALF_STOPBITS: | |
467 | case SERIAL_2_STOPBITS: | |
468 | newbit = 1; | |
469 | break; | |
470 | default: | |
471 | return 1; | |
472 | } | |
473 | ||
c906108c SS |
474 | if (!newbit) |
475 | state.termios.c_cflag &= ~CSTOPB; | |
476 | else | |
c5aa993b | 477 | state.termios.c_cflag |= CSTOPB; /* two bits */ |
c906108c SS |
478 | |
479 | return set_tty_state (scb, &state); | |
480 | } | |
481 | ||
236af5e3 YG |
482 | /* Implement the "setparity" serial_ops callback. */ |
483 | ||
484 | static int | |
485 | hardwire_setparity (struct serial *scb, int parity) | |
486 | { | |
487 | struct hardwire_ttystate state; | |
488 | int newparity = 0; | |
489 | ||
490 | if (get_tty_state (scb, &state)) | |
491 | return -1; | |
492 | ||
493 | switch (parity) | |
494 | { | |
495 | case GDBPARITY_NONE: | |
496 | newparity = 0; | |
497 | break; | |
498 | case GDBPARITY_ODD: | |
499 | newparity = PARENB | PARODD; | |
500 | break; | |
501 | case GDBPARITY_EVEN: | |
502 | newparity = PARENB; | |
503 | break; | |
504 | default: | |
f34652de | 505 | internal_warning ("Incorrect parity value: %d", parity); |
236af5e3 YG |
506 | return -1; |
507 | } | |
508 | ||
236af5e3 YG |
509 | state.termios.c_cflag &= ~(PARENB | PARODD); |
510 | state.termios.c_cflag |= newparity; | |
236af5e3 | 511 | |
236af5e3 YG |
512 | return set_tty_state (scb, &state); |
513 | } | |
514 | ||
515 | ||
c906108c | 516 | static void |
819cc324 | 517 | hardwire_close (struct serial *scb) |
c906108c SS |
518 | { |
519 | if (scb->fd < 0) | |
520 | return; | |
521 | ||
c5aa993b | 522 | close (scb->fd); |
c906108c SS |
523 | scb->fd = -1; |
524 | } | |
c2c6d25f | 525 | \f |
2acceee2 | 526 | \f |
433759f7 | 527 | |
12e8c7d7 TT |
528 | /* The hardwire ops. */ |
529 | ||
530 | static const struct serial_ops hardwire_ops = | |
531 | { | |
532 | "hardwire", | |
533 | hardwire_open, | |
534 | hardwire_close, | |
535 | NULL, | |
9bcbdca8 | 536 | ser_base_readchar, |
12e8c7d7 TT |
537 | ser_base_write, |
538 | hardwire_flush_output, | |
539 | hardwire_flush_input, | |
540 | hardwire_send_break, | |
541 | hardwire_raw, | |
542 | hardwire_get_tty_state, | |
543 | hardwire_copy_tty_state, | |
544 | hardwire_set_tty_state, | |
545 | hardwire_print_tty_state, | |
12e8c7d7 TT |
546 | hardwire_setbaudrate, |
547 | hardwire_setstopbits, | |
236af5e3 | 548 | hardwire_setparity, |
12e8c7d7 TT |
549 | hardwire_drain_output, |
550 | ser_base_async, | |
551 | ser_unix_read_prim, | |
552 | ser_unix_write_prim | |
553 | }; | |
554 | ||
6c265988 | 555 | void _initialize_ser_hardwire (); |
12e8c7d7 | 556 | void |
6c265988 | 557 | _initialize_ser_hardwire () |
12e8c7d7 TT |
558 | { |
559 | serial_add_interface (&hardwire_ops); | |
23776285 | 560 | |
23776285 MR |
561 | #ifdef CRTSCTS |
562 | add_setshow_boolean_cmd ("remoteflow", no_class, | |
563 | &serial_hwflow, _("\ | |
564 | Set use of hardware flow control for remote serial I/O."), _("\ | |
565 | Show use of hardware flow control for remote serial I/O."), _("\ | |
566 | Enable or disable hardware flow control (RTS/CTS) on the serial port\n\ | |
567 | when debugging using remote targets."), | |
568 | NULL, | |
569 | show_serial_hwflow, | |
570 | &setlist, &showlist); | |
571 | #endif | |
c906108c | 572 | } |
b4505029 MM |
573 | |
574 | int | |
575 | ser_unix_read_prim (struct serial *scb, size_t count) | |
576 | { | |
0da23004 TT |
577 | int result = recv (scb->fd, scb->buf, count, 0); |
578 | if (result == -1 && errno != EINTR) | |
579 | perror_with_name ("error while reading"); | |
580 | return result; | |
b4505029 MM |
581 | } |
582 | ||
583 | int | |
584 | ser_unix_write_prim (struct serial *scb, const void *buf, size_t len) | |
585 | { | |
d69939bd TT |
586 | int result = write (scb->fd, buf, len); |
587 | if (result == -1 && errno != EINTR) | |
588 | perror_with_name ("error while writing"); | |
589 | return result; | |
b4505029 | 590 | } |