1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | #include <termios.h> |
24 | |
25 | #include <assert.h> |
26 | #include <errno(*__errno_location ()).h> |
27 | #include <error.h> |
28 | #include <string.h> |
29 | #include <stdio.h> |
30 | |
31 | #include <pthread.h> |
32 | |
33 | #include <hurd.h> |
34 | #include <hurd/ports.h> |
35 | #include <hurd/io.h> |
36 | #include <hurd/tioctl.h> |
37 | |
38 | #include "term.h" |
39 | |
40 | |
41 | |
42 | |
43 | thread_t reader_thread = MACH_PORT_NULL((mach_port_t) 0); |
44 | |
45 | |
46 | |
47 | |
48 | static file_t ioport = MACH_PORT_NULL((mach_port_t) 0); |
49 | |
50 | |
51 | |
52 | |
53 | #define TIOC_CAP_OUTQ0x001 0x001 |
54 | #define TIOC_CAP_START0x002 0x002 |
55 | #define TIOC_CAP_STOP0x004 0x004 |
56 | #define TIOC_CAP_FLUSH0x008 0x008 |
57 | #define TIOC_CAP_CBRK0x010 0x010 |
58 | #define TIOC_CAP_SBRK0x020 0x020 |
59 | #define TIOC_CAP_MODG0x040 0x040 |
60 | #define TIOC_CAP_MODS0x080 0x080 |
61 | #define TIOC_CAP_GETA0x100 0x100 |
62 | #define TIOC_CAP_SETA0x200 0x200 |
63 | #define TIOC_CAP_GWINSZ0x400 0x400 |
64 | unsigned int tioc_caps; |
65 | |
66 | |
67 | |
68 | thread_t writer_thread = MACH_PORT_NULL((mach_port_t) 0); |
69 | |
70 | |
71 | static int output_stopped; |
72 | static pthread_cond_t hurdio_writer_condition; |
73 | |
74 | |
75 | |
76 | |
77 | size_t npending_output; |
78 | |
79 | |
80 | int assert_dtr; |
81 | static pthread_cond_t hurdio_assert_dtr_condition; |
82 | |
83 | |
84 | |
85 | static error_t hurdio_desert_dtr (); |
86 | static void *hurdio_reader_loop (void *arg); |
87 | static void *hurdio_writer_loop (void *arg); |
88 | static error_t hurdio_set_bits (struct termios *state); |
89 | |
90 | |
91 | static error_t |
92 | hurdio_init (void) |
93 | { |
94 | pthread_t thread; |
95 | error_t err; |
96 | |
97 | pthread_cond_init (&hurdio_writer_condition, NULL((void*)0)); |
98 | pthread_cond_init (&hurdio_assert_dtr_condition, NULL((void*)0)); |
99 | |
100 | err = pthread_create (&thread, NULL((void*)0), hurdio_reader_loop, NULL((void*)0)); |
101 | if (!err) |
102 | pthread_detach (thread); |
103 | else |
104 | { |
105 | errno(*__errno_location ()) = err; |
106 | perror ("pthread_create"); |
107 | } |
108 | err = pthread_create (&thread, NULL((void*)0), hurdio_writer_loop, NULL((void*)0)); |
109 | if (!err) |
110 | pthread_detach (thread); |
111 | else |
112 | { |
113 | errno(*__errno_location ()) = err; |
114 | perror ("pthread_create"); |
115 | } |
116 | return 0; |
117 | } |
118 | |
119 | static error_t |
120 | hurdio_fini (void) |
121 | { |
122 | hurdio_desert_dtr (); |
123 | writer_thread = MACH_PORT_NULL((mach_port_t) 0); |
124 | |
125 | return 0; |
126 | } |
127 | |
128 | static error_t |
129 | hurdio_gwinsz (struct winsize *size) |
130 | { |
131 | if (tioc_caps & TIOC_CAP_GWINSZ0x400) |
132 | { |
133 | error_t err = tioctl_tiocgwinsz (ioport, size); |
134 | if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)))) |
135 | { |
136 | tioc_caps &= ~TIOC_CAP_GWINSZ0x400; |
137 | err = EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)); |
138 | } |
139 | return err; |
140 | } |
141 | return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)); |
142 | } |
143 | |
144 | |
145 | |
146 | static void |
147 | wait_for_dtr (void) |
148 | { |
149 | while (!assert_dtr) |
150 | pthread_hurd_cond_wait_np (&hurdio_assert_dtr_condition, &global_lock); |
151 | assert_dtr = 0; |
152 | |
153 | if (tty_arg == 0) |
154 | ioport = termctl->underlying; |
155 | else |
156 | { |
157 | |
158 | |
159 | ioport = file_name_lookup (tty_arg, O_READ0x0001|O_WRITE0x0002, 0); |
160 | if (ioport == MACH_PORT_NULL((mach_port_t) 0)) |
161 | { |
162 | report_carrier_error (errno(*__errno_location ())); |
163 | return; |
164 | } |
165 | } |
166 | |
167 | |
168 | error_t err; |
169 | struct termios state = termstate; |
170 | |
171 | |
172 | tioc_caps = ~0; |
173 | |
174 | |
175 | err = hurdio_set_bits (&state); |
176 | if (err) |
177 | report_carrier_error (err); |
178 | else |
179 | { |
180 | termstate = state; |
181 | |
182 | |
183 | report_carrier_on (); |
184 | |
185 | |
186 | pthread_cond_broadcast (&hurdio_writer_condition); |
187 | } |
188 | } |
189 | |
190 | |
191 | |
192 | |
193 | static void * |
194 | hurdio_reader_loop (void *arg) |
195 | { |
196 | |
197 | #define BUFFER_SIZE 256 |
198 | char buffer[BUFFER_SIZE]; |
199 | char *data; |
200 | size_t datalen; |
201 | error_t err; |
202 | |
203 | pthread_mutex_lock (&global_lock); |
204 | reader_thread = mach_thread_self (); |
205 | |
206 | while (1) |
207 | { |
208 | |
209 | while (ioport == MACH_PORT_NULL((mach_port_t) 0)) |
210 | wait_for_dtr (); |
211 | pthread_mutex_unlock (&global_lock); |
212 | |
213 | data = buffer; |
214 | datalen = BUFFER_SIZE; |
215 | |
216 | err = io_read (ioport, &data, &datalen, -1, BUFFER_SIZE); |
217 | |
218 | pthread_mutex_lock (&global_lock); |
219 | |
220 | if (err || !datalen) |
221 | hurdio_desert_dtr (); |
222 | else |
223 | { |
224 | if (termstate.c_cflag & CREAD(1 << 11)) |
225 | { |
226 | int i; |
227 | |
228 | for (i = 0; i < datalen; i++) |
229 | if (input_character (data[i])) |
230 | break; |
231 | } |
232 | |
233 | if (data != buffer) |
234 | vm_deallocate (mach_task_self()((__mach_task_self_ + 0)), (vm_address_t) data, datalen); |
235 | } |
236 | } |
237 | #undef BUFFER_SIZE |
238 | |
239 | return 0; |
240 | } |
241 | |
242 | |
243 | |
244 | static void * |
245 | hurdio_writer_loop (void *arg) |
246 | { |
247 | |
248 | #define BUFFER_SIZE 256 |
249 | char *bufp; |
250 | char pending_output[BUFFER_SIZE]; |
251 | size_t amount; |
252 | error_t err; |
253 | int size; |
254 | int npending_output_copy; |
255 | mach_port_t ioport_copy; |
256 | |
257 | pthread_mutex_lock (&global_lock); |
258 | writer_thread = mach_thread_self (); |
259 | |
260 | while (1) |
261 | { |
262 | while (writer_thread != MACH_PORT_NULL((mach_port_t) 0) |
263 | && (ioport == MACH_PORT_NULL((mach_port_t) 0) || !qsize (outputq) |
264 | || output_stopped)) |
265 | pthread_hurd_cond_wait_np (&hurdio_writer_condition, &global_lock); |
266 | if (writer_thread == MACH_PORT_NULL((mach_port_t) 0)) |
267 | return 0; |
268 | |
269 | |
270 | |
271 | size = qsize (outputq); |
272 | |
273 | if (size + npending_output > BUFFER_SIZE) |
274 | size = BUFFER_SIZE - npending_output; |
275 | |
276 | bufp = pending_output + npending_output; |
277 | npending_output += size; |
278 | |
279 | |
280 | |
281 | npending_output_copy = npending_output; |
282 | ioport_copy = ioport; |
283 | mach_port_mod_refs (mach_task_self ()((__mach_task_self_ + 0)), ioport_copy, |
284 | MACH_PORT_RIGHT_SEND((mach_port_right_t) 0), 1); |
285 | |
286 | while (size--) |
287 | *bufp++ = dequeue (outputq); |
288 | |
289 | |
290 | pthread_mutex_unlock (&global_lock); |
291 | err = io_write (ioport_copy, pending_output, npending_output_copy, |
292 | -1, &amount); |
293 | pthread_mutex_lock (&global_lock); |
294 | |
295 | mach_port_mod_refs (mach_task_self ()((__mach_task_self_ + 0)), ioport_copy, |
296 | MACH_PORT_RIGHT_SEND((mach_port_right_t) 0), -1); |
297 | if (err) |
298 | hurdio_desert_dtr (); |
299 | else |
300 | { |
301 | |
302 | |
303 | if (amount >= npending_output) |
304 | { |
305 | npending_output = 0; |
306 | pthread_cond_broadcast (outputq->wait); |
307 | pthread_cond_broadcast (&select_alert); |
308 | } |
309 | else |
310 | { |
311 | |
312 | |
313 | npending_output -= amount; |
314 | memmove (pending_output, pending_output + amount, |
315 | npending_output); |
316 | } |
317 | } |
318 | } |
319 | #undef BUFFER_SIZE |
320 | |
321 | return 0; |
322 | } |
323 | |
324 | |
325 | |
326 | |
327 | static error_t |
328 | hurdio_start_output () |
329 | { |
330 | |
331 | |
332 | if (output_stopped && !(termflags & USER_OUTPUT_SUSP0x00000001)) |
333 | { |
334 | if (tioc_caps & TIOC_CAP_START0x002) |
335 | { |
336 | error_t err = tioctl_tiocstart (ioport); |
337 | if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)))) |
338 | tioc_caps &= ~TIOC_CAP_START0x002; |
339 | } |
340 | output_stopped = 0; |
341 | } |
342 | pthread_cond_broadcast (&hurdio_writer_condition); |
343 | return 0; |
344 | } |
345 | |
346 | |
347 | |
348 | static error_t |
349 | hurdio_set_break () |
350 | { |
351 | if (tioc_caps & TIOC_CAP_SBRK0x020) |
352 | { |
353 | error_t err = tioctl_tiocsbrk (ioport); |
354 | if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)))) |
355 | tioc_caps &= ~TIOC_CAP_SBRK0x020; |
356 | else if (err) |
357 | return err; |
358 | } |
359 | return 0; |
360 | } |
361 | |
362 | |
363 | |
364 | static error_t |
365 | hurdio_clear_break () |
366 | { |
367 | if (tioc_caps & TIOC_CAP_CBRK0x010) |
368 | { |
369 | error_t err = tioctl_tioccbrk (ioport); |
370 | if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)))) |
371 | tioc_caps &= ~TIOC_CAP_CBRK0x010; |
372 | else if (err) |
373 | return err; |
374 | } |
375 | return 0; |
376 | } |
377 | |
378 | |
379 | |
380 | |
381 | |
382 | |
383 | |
384 | static error_t |
385 | hurdio_abandon_physical_output () |
386 | { |
387 | if (tioc_caps & TIOC_CAP_FLUSH0x008) |
388 | { |
389 | error_t err = tioctl_tiocflush (ioport, O_WRITE0x0002); |
390 | if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)))) |
391 | tioc_caps &= ~TIOC_CAP_FLUSH0x008; |
392 | else if (err) |
393 | return err; |
394 | } |
395 | |
396 | |
397 | |
398 | |
399 | npending_output = 0; |
400 | return 0; |
401 | } |
402 | |
403 | |
404 | |
405 | |
406 | |
407 | static error_t |
408 | hurdio_suspend_physical_output () |
409 | { |
410 | if (!output_stopped) |
411 | { |
412 | if (tioc_caps & TIOC_CAP_STOP0x004) |
413 | { |
414 | error_t err = tioctl_tiocstop (ioport); |
415 | if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)))) |
416 | tioc_caps &= ~TIOC_CAP_STOP0x004; |
417 | else if (err) |
418 | return err; |
419 | } |
420 | output_stopped = 1; |
421 | } |
422 | return 0; |
423 | } |
424 | |
425 | |
426 | |
427 | static error_t |
428 | hurdio_notice_input_flushed () |
429 | { |
430 | if (tioc_caps & TIOC_CAP_FLUSH0x008) |
431 | { |
432 | error_t err = tioctl_tiocflush (ioport, O_READ0x0001); |
433 | if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)))) |
434 | tioc_caps &= ~TIOC_CAP_FLUSH0x008; |
435 | else if (err) |
436 | return err; |
437 | } |
438 | return 0; |
439 | } |
440 | |
441 | |
442 | |
443 | static int |
444 | hurdio_pending_output_size () |
445 | { |
446 | int queue_size = 0; |
447 | |
448 | if (tioc_caps & TIOC_CAP_OUTQ0x001) |
449 | { |
450 | error_t err = tioctl_tiocoutq (ioport, &queue_size); |
451 | if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)))) |
452 | tioc_caps &= ~TIOC_CAP_OUTQ0x001; |
453 | else if (err) |
454 | queue_size = 0; |
455 | } |
456 | |
457 | return queue_size + npending_output; |
458 | } |
459 | |
460 | |
461 | |
462 | static error_t |
463 | hurdio_desert_dtr () |
464 | { |
465 | if (writer_thread != MACH_PORT_NULL((mach_port_t) 0)) |
466 | hurd_thread_cancel (writer_thread); |
467 | if (reader_thread != MACH_PORT_NULL((mach_port_t) 0)) |
468 | hurd_thread_cancel (reader_thread); |
469 | if (ioport != MACH_PORT_NULL((mach_port_t) 0) && tty_arg) |
470 | { |
471 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), ioport); |
472 | ioport = MACH_PORT_NULL((mach_port_t) 0); |
473 | } |
474 | |
475 | |
476 | |
477 | assert_dtr = 0; |
478 | report_carrier_off (); |
479 | return 0; |
480 | } |
481 | |
482 | |
483 | static error_t |
484 | hurdio_assert_dtr () |
485 | { |
486 | if (ioport == MACH_PORT_NULL((mach_port_t) 0)) |
487 | { |
488 | assert_dtr = 1; |
489 | pthread_cond_signal (&hurdio_assert_dtr_condition); |
490 | } |
491 | |
492 | return 0; |
493 | } |
494 | |
495 | |
496 | |
497 | |
498 | |
499 | static error_t |
500 | hurdio_set_bits (struct termios *state) |
501 | { |
502 | error_t err; |
503 | struct termios ttystat; |
504 | |
505 | |
506 | struct hurd_termios |
507 | { |
508 | modes_t modes; |
509 | ccs_t ccs; |
510 | speeds_t speeds; |
511 | } *hurd_ttystat = (struct hurd_termios *) &ttystat; |
512 | |
513 | if (!(state->c_cflag & CIGNORE(1 << 0)) && ioport != MACH_PORT_NULL((mach_port_t) 0)) |
514 | { |
515 | |
516 | |
517 | |
518 | |
519 | if (!(tioc_caps & TIOC_CAP_GETA0x100)) |
520 | |
521 | |
522 | return 0; |
523 | |
524 | err = tioctl_tiocgeta (ioport, hurd_ttystat->modes, |
525 | hurd_ttystat->ccs, hurd_ttystat->speeds); |
526 | if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)))) |
527 | { |
528 | tioc_caps &= ~TIOC_CAP_GETA0x100; |
529 | |
530 | |
531 | return 0; |
532 | } |
533 | else if (err) |
534 | return err; |
535 | |
536 | |
537 | |
538 | if (tioc_caps & TIOC_CAP_SETA0x200) |
539 | { |
540 | if (state->__ispeed) |
541 | hurd_ttystat->speeds[0] = state->__ispeed; |
542 | if (state->__ospeed) |
543 | hurd_ttystat->speeds[1] = state->__ospeed; |
544 | cfmakeraw (&ttystat); |
545 | ttystat.c_cflag = state->c_cflag &~ HUPCL(1 << 14); |
546 | |
547 | err = tioctl_tiocseta (ioport, hurd_ttystat->modes, |
548 | hurd_ttystat->ccs, hurd_ttystat->speeds); |
549 | if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)))) |
550 | tioc_caps &= ~TIOC_CAP_SETA0x200; |
551 | else if (err) |
552 | return err; |
553 | |
554 | |
555 | err = tioctl_tiocgeta (ioport, hurd_ttystat->modes, |
556 | hurd_ttystat->ccs, hurd_ttystat->speeds); |
557 | if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)))) |
558 | tioc_caps &= ~TIOC_CAP_GETA0x100; |
559 | else if (err) |
560 | return err; |
561 | } |
562 | |
563 | |
564 | *state = ttystat; |
565 | } |
566 | |
567 | return 0; |
568 | } |
569 | |
570 | |
571 | |
572 | |
573 | |
574 | static error_t |
575 | hurdio_mdmctl (int how, int bits) |
576 | { |
577 | error_t err; |
578 | int oldbits, newbits; |
| 1 | Variable 'oldbits' declared without an initial value | |
|
579 | |
580 | if (tioc_caps & TIOC_CAP_MODS0x080) |
| 2 | | Assuming 'tioc_caps' is & 128 | |
|
| |
581 | { |
582 | if ((how == MDMCTL_BIS0) || (how == MDMCTL_BIC1)) |
| 4 | | Assuming 'how' is not equal to 0 | |
|
| 5 | | Assuming 'how' is equal to 1 | |
|
| |
583 | { |
584 | if (tioc_caps & TIOC_CAP_MODG0x040) |
| |
585 | { |
586 | error_t err = tioctl_tiocmodg (ioport, &oldbits); |
587 | if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)))) |
588 | tioc_caps &= ~TIOC_CAP_MODG0x040; |
589 | else if (err) |
590 | return err; |
591 | } |
592 | } |
593 | |
594 | if (how == MDMCTL_BIS0) |
| |
595 | newbits = (oldbits | bits); |
596 | else if (how == MDMCTL_BIC1) |
| |
597 | newbits = (oldbits &= ~bits); |
| 10 | | The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage |
|
598 | else |
599 | newbits = bits; |
600 | |
601 | err = tioctl_tiocmods (ioport, newbits); |
602 | if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)))) |
603 | tioc_caps &= ~TIOC_CAP_MODS0x080; |
604 | else if (err) |
605 | return err; |
606 | } |
607 | return 0; |
608 | } |
609 | |
610 | |
611 | static int |
612 | hurdio_mdmstate () |
613 | { |
614 | int oldbits; |
615 | |
616 | if (tioc_caps & TIOC_CAP_MODG0x040) |
617 | { |
618 | error_t err = tioctl_tiocmodg (ioport, &oldbits); |
619 | if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)))) |
620 | tioc_caps &= ~TIOC_CAP_MODG0x040; |
621 | else if (err) |
622 | return 0; |
623 | } |
624 | return 0; |
625 | } |
626 | |
627 | |
628 |
|
629 | const struct bottomhalf hurdio_bottom = |
630 | { |
631 | TERM_ON_HURDIO, |
632 | hurdio_init, |
633 | hurdio_fini, |
634 | hurdio_gwinsz, |
635 | hurdio_start_output, |
636 | hurdio_set_break, |
637 | hurdio_clear_break, |
638 | hurdio_abandon_physical_output, |
639 | hurdio_suspend_physical_output, |
640 | hurdio_pending_output_size, |
641 | hurdio_notice_input_flushed, |
642 | hurdio_assert_dtr, |
643 | hurdio_desert_dtr, |
644 | hurdio_set_bits, |
645 | hurdio_mdmctl, |
646 | hurdio_mdmstate, |
647 | }; |