Changeset e2af631 in rtems
- Timestamp:
- 11/25/00 19:35:53 (23 years ago)
- Branches:
- 4.10, 4.11, 4.8, 4.9, 5, master
- Children:
- a6abd67
- Parents:
- c8471315
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
c/src/exec/libcsupport/src/Makefile.am
rc8471315 re2af631 82 82 83 83 EXTRA_DIST = $(DOC_FILES) $(COMMON_C_FILES) $(EMBEDDED_C_FILES) \ 84 $(UNIX_C_FILES) 84 $(UNIX_C_FILES) termiostypes.h 85 85 86 86 include $(top_srcdir)/../../../automake/local.am -
c/src/exec/libcsupport/src/termios.c
rc8471315 re2af631 24 24 #include <termios.h> 25 25 #include <unistd.h> 26 #include <sys/ttycom.h> 27 28 #include "termiostypes.h" 26 29 27 30 /* … … 61 64 #define RAW_OUTPUT_BUFFER_SIZE 64 62 65 63 /*64 * Variables associated with each termios instance.65 * One structure for each hardware I/O device.66 */67 struct rtems_termios_tty {68 /*69 * Linked-list of active TERMIOS devices70 */71 struct rtems_termios_tty *forw;72 struct rtems_termios_tty *back;73 74 /*75 * How many times has this device been opened76 */77 int refcount;78 79 /*80 * This device81 */82 rtems_device_major_number major;83 rtems_device_major_number minor;84 85 /*86 * Mutual-exclusion semaphores87 */88 rtems_id isem;89 rtems_id osem;90 91 /*92 * The canonical (cooked) character buffer93 */94 char cbuf[CBUFSIZE];95 int ccount;96 int cindex;97 98 /*99 * Keep track of cursor (printhead) position100 */101 int column;102 int read_start_column;103 104 /*105 * The ioctl settings106 */107 struct termios termios;108 rtems_interval vtimeTicks;109 110 /*111 * Raw input character buffer112 */113 volatile char rawInBuf[RAW_INPUT_BUFFER_SIZE];114 volatile unsigned int rawInBufHead;115 volatile unsigned int rawInBufTail;116 rtems_id rawInBufSemaphore;117 rtems_unsigned32 rawInBufSemaphoreOptions;118 rtems_interval rawInBufSemaphoreTimeout;119 rtems_interval rawInBufSemaphoreFirstTimeout;120 unsigned int rawInBufDropped; /* Statistics */121 122 /*123 * Raw output character buffer124 */125 volatile char rawOutBuf[RAW_OUTPUT_BUFFER_SIZE];126 volatile unsigned int rawOutBufHead;127 volatile unsigned int rawOutBufTail;128 rtems_id rawOutBufSemaphore;129 volatile enum {rob_idle, rob_busy, rob_wait } rawOutBufState;130 131 /*132 * Callbacks to device-specific routines133 */134 rtems_termios_callbacks device;135 volatile unsigned int flow_ctrl;136 unsigned int lowwater,highwater;137 };138 139 66 /* fields for "flow_ctrl" status */ 140 67 #define FL_IREQXOF 1 /* input queue requests stop of incoming data */ … … 149 76 #define FL_MDXOF 0x400 /* output controlled with XON/XOFF protocol */ 150 77 78 #define NODISC(n) \ 79 { NULL, NULL, NULL, NULL, \ 80 NULL, NULL, NULL, NULL } 81 /* 82 * FIXME: change linesw entries consistant with linesw entry usage... 83 */ 84 struct linesw linesw[MAXLDISC] = 85 { 86 NODISC(0), /* 0- termios-built-in */ 87 NODISC(1), /* 1- defunct */ 88 NODISC(2), /* 2- NTTYDISC */ 89 NODISC(3), /* TABLDISC */ 90 NODISC(4), /* SLIPDISC */ 91 NODISC(5), /* PPPDISC */ 92 NODISC(6), /* loadable */ 93 NODISC(7), /* loadable */ 94 }; 95 96 int nlinesw = sizeof (linesw) / sizeof (linesw[0]); 97 151 98 extern struct rtems_termios_tty *rtems_termios_ttyHead; 152 99 extern struct rtems_termios_tty *rtems_termios_ttyTail; 153 100 extern rtems_id rtems_termios_ttyMutex; 101 102 static rtems_task rtems_termios_rxdaemon(rtems_task_argument argument); 103 static rtems_task rtems_termios_txdaemon(rtems_task_argument argument); 104 /* 105 * some constants for I/O daemon task creation 106 */ 107 #define TERMIOS_TXTASK_PRIO 10 108 #define TERMIOS_RXTASK_PRIO 9 109 #define TERMIOS_TXTASK_STACKSIZE 1024 110 #define TERMIOS_RXTASK_STACKSIZE 1024 111 /* 112 * some events to be sent to the I/O tasks 113 */ 114 #define TERMIOS_TX_START_EVENT RTEMS_EVENT_1 115 #define TERMIOS_TX_TERMINATE_EVENT RTEMS_EVENT_0 116 117 #define TERMIOS_RX_PROC_EVENT RTEMS_EVENT_1 118 #define TERMIOS_RX_TERMINATE_EVENT RTEMS_EVENT_0 154 119 155 120 /* … … 171 136 * See if the device has already been opened 172 137 */ 173 sc = rtems_semaphore_obtain (rtems_termios_ttyMutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT); 138 sc = rtems_semaphore_obtain (rtems_termios_ttyMutex, 139 RTEMS_WAIT, RTEMS_NO_TIMEOUT); 174 140 if (sc != RTEMS_SUCCESSFUL) 175 141 return sc; … … 189 155 return RTEMS_NO_MEMORY; 190 156 } 157 /* 158 * allocate raw input buffer 159 */ 160 tty->rawInBuf.Size = RAW_INPUT_BUFFER_SIZE; 161 tty->rawInBuf.theBuf = malloc (tty->rawInBuf.Size); 162 if (tty->rawInBuf.theBuf == NULL) { 163 free(tty); 164 rtems_semaphore_release (rtems_termios_ttyMutex); 165 return RTEMS_NO_MEMORY; 166 } 167 /* 168 * allocate raw output buffer 169 */ 170 tty->rawOutBuf.Size = RAW_OUTPUT_BUFFER_SIZE; 171 tty->rawOutBuf.theBuf = malloc (tty->rawOutBuf.Size); 172 if (tty->rawInBuf.theBuf == NULL) { 173 free((void *)(tty->rawInBuf.theBuf)); 174 free(tty); 175 rtems_semaphore_release (rtems_termios_ttyMutex); 176 return RTEMS_NO_MEMORY; 177 } 178 /* 179 * allocate cooked buffer 180 */ 181 tty->cbuf = malloc (CBUFSIZE); 182 if (tty->cbuf == NULL) { 183 free((void *)(tty->rawOutBuf.theBuf)); 184 free((void *)(tty->rawInBuf.theBuf)); 185 free(tty); 186 rtems_semaphore_release (rtems_termios_ttyMutex); 187 return RTEMS_NO_MEMORY; 188 } 189 /* 190 * link tty 191 */ 191 192 if (rtems_termios_ttyHead) 192 193 rtems_termios_ttyHead->back = tty; … … 222 223 RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_FIFO, 223 224 RTEMS_NO_PRIORITY, 224 &tty->rawOutBuf Semaphore);225 &tty->rawOutBuf.Semaphore); 225 226 if (sc != RTEMS_SUCCESSFUL) 226 227 rtems_fatal_error_occurred (sc); … … 231 232 */ 232 233 tty->device = *callbacks; 233 if (!tty->device.pollRead) { 234 235 /* 236 * Create I/O tasks 237 */ 238 if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) { 239 sc = rtems_task_create ( 240 rtems_build_name ('T', 'x', 'T', c), 241 TERMIOS_TXTASK_PRIO, 242 TERMIOS_TXTASK_STACKSIZE, 243 RTEMS_NO_PREEMPT | RTEMS_NO_TIMESLICE | 244 RTEMS_NO_ASR, 245 RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL, 246 &tty->txTaskId); 247 if (sc != RTEMS_SUCCESSFUL) 248 rtems_fatal_error_occurred (sc); 249 sc = rtems_task_create ( 250 rtems_build_name ('R', 'x', 'T', c), 251 TERMIOS_RXTASK_PRIO, 252 TERMIOS_RXTASK_STACKSIZE, 253 RTEMS_NO_PREEMPT | RTEMS_NO_TIMESLICE | 254 RTEMS_NO_ASR, 255 RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL, 256 &tty->rxTaskId); 257 if (sc != RTEMS_SUCCESSFUL) 258 rtems_fatal_error_occurred (sc); 259 260 } 261 if ((tty->device.pollRead == NULL) || 262 (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN)){ 234 263 sc = rtems_semaphore_create ( 235 264 rtems_build_name ('T', 'R', 'r', c), … … 237 266 RTEMS_COUNTING_SEMAPHORE | RTEMS_PRIORITY, 238 267 RTEMS_NO_PRIORITY, 239 &tty->rawInBuf Semaphore);268 &tty->rawInBuf.Semaphore); 240 269 if (sc != RTEMS_SUCCESSFUL) 241 270 rtems_fatal_error_occurred (sc); … … 270 299 * set low/highwater mark for XON/XOFF support 271 300 */ 272 tty->lowwater = RAW_INPUT_BUFFER_SIZE* 1/2;273 tty->highwater = RAW_INPUT_BUFFER_SIZE* 3/4;301 tty->lowwater = tty->rawInBuf.Size * 1/2; 302 tty->highwater = tty->rawInBuf.Size * 3/4; 274 303 /* 275 304 * Bump name characer … … 280 309 } 281 310 args->iop->data1 = tty; 282 if (!tty->refcount++ && tty->device.firstOpen) 311 if (!tty->refcount++) { 312 if (tty->device.firstOpen) 283 313 (*tty->device.firstOpen)(major, minor, arg); 314 /* 315 * start I/O tasks, if needed 316 */ 317 if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) { 318 sc = rtems_task_start(tty->rxTaskId, 319 rtems_termios_rxdaemon, 320 (rtems_task_argument)tty); 321 if (sc != RTEMS_SUCCESSFUL) 322 rtems_fatal_error_occurred (sc); 323 324 sc = rtems_task_start(tty->txTaskId, 325 rtems_termios_txdaemon, 326 (rtems_task_argument)tty); 327 if (sc != RTEMS_SUCCESSFUL) 328 rtems_fatal_error_occurred (sc); 329 } 330 } 284 331 rtems_semaphore_release (rtems_termios_ttyMutex); 285 332 return RTEMS_SUCCESSFUL; … … 295 342 rtems_status_code sc; 296 343 297 if (tty->device.outputUsesInterrupts ) {344 if (tty->device.outputUsesInterrupts != TERMIOS_POLLED) { 298 345 rtems_interrupt_disable (level); 299 while (tty->rawOutBuf Tail != tty->rawOutBufHead) {346 while (tty->rawOutBuf.Tail != tty->rawOutBuf.Head) { 300 347 tty->rawOutBufState = rob_wait; 301 348 rtems_interrupt_enable (level); 302 sc = rtems_semaphore_obtain (tty->rawOutBuf Semaphore,349 sc = rtems_semaphore_obtain (tty->rawOutBuf.Semaphore, 303 350 RTEMS_WAIT, 304 351 RTEMS_NO_TIMEOUT); … … 322 369 rtems_fatal_error_occurred (sc); 323 370 if (--tty->refcount == 0) { 324 drainOutput (tty); 371 if (linesw[tty->t_line].l_close != NULL) { 372 /* 373 * call discipline-specific close 374 */ 375 sc = linesw[tty->t_line].l_close(tty); 376 } 377 else { 378 /* 379 * default: just flush output buffer 380 */ 381 drainOutput (tty); 382 } 383 384 if (tty->device.outputUsesInterrupts 385 == TERMIOS_TASK_DRIVEN) { 386 /* 387 * send "terminate" to I/O tasks 388 */ 389 sc = rtems_event_send( 390 tty->rxTaskId, 391 TERMIOS_RX_TERMINATE_EVENT); 392 if (sc != RTEMS_SUCCESSFUL) 393 rtems_fatal_error_occurred (sc); 394 sc = rtems_event_send( 395 tty->txTaskId, 396 TERMIOS_TX_TERMINATE_EVENT); 397 if (sc != RTEMS_SUCCESSFUL) 398 rtems_fatal_error_occurred (sc); 399 } 325 400 if (tty->device.lastClose) 326 401 (*tty->device.lastClose)(tty->major, tty->minor, arg); … … 335 410 rtems_semaphore_delete (tty->isem); 336 411 rtems_semaphore_delete (tty->osem); 337 rtems_semaphore_delete (tty->rawOutBufSemaphore); 338 if (!tty->device.pollRead) 339 rtems_semaphore_delete (tty->rawInBufSemaphore); 412 rtems_semaphore_delete (tty->rawOutBuf.Semaphore); 413 if ((tty->device.pollRead == NULL) || 414 (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN)) 415 rtems_semaphore_delete (tty->rawInBuf.Semaphore); 340 416 free (tty); 341 417 } … … 367 443 /* if chars available, call write function... */ 368 444 (*tty->device.write)(tty->minor, 369 (char *)&tty->rawOutBuf[tty->rawOutBufTail],1);445 (char *)&tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail],1); 370 446 } 371 447 /* reenable interrupts */ … … 428 504 switch (args->command) { 429 505 default: 430 sc = RTEMS_INVALID_NUMBER; 506 if (linesw[tty->t_line].l_ioctl != NULL) { 507 sc = linesw[tty->t_line].l_ioctl(tty,args); 508 } 509 else { 510 sc = RTEMS_INVALID_NUMBER; 511 } 431 512 break; 432 513 … … 477 558 break; 478 559 560 /* 561 * FIXME: add various ioctl code handlers 562 */ 563 564 #if 1 /* FIXME */ 565 case TIOCSETD: 566 /* 567 * close old line discipline 568 */ 569 if (linesw[tty->t_line].l_close != NULL) { 570 sc = linesw[tty->t_line].l_close(tty); 571 } 572 tty->t_line=*(int*)(args->buffer); 573 tty->t_sc = NULL; /* ensure that no more valid data */ 574 /* 575 * open new line discipline 576 */ 577 if (linesw[tty->t_line].l_open != NULL) { 578 sc = linesw[tty->t_line].l_open(tty); 579 } 580 break; 581 case TIOCGETD: 582 *(int*)(args->buffer)=tty->t_line; 583 break; 584 #endif 479 585 case FIONREAD: 480 586 /* Half guess that this is the right operation */ … … 490 596 * Send characters to device-specific code 491 597 */ 492 staticvoid493 osend(const char *buf, int len, struct rtems_termios_tty *tty)598 void 599 rtems_termios_puts (const char *buf, int len, struct rtems_termios_tty *tty) 494 600 { 495 601 unsigned int newHead; … … 497 603 rtems_status_code sc; 498 604 499 if ( !tty->device.outputUsesInterrupts) {605 if (tty->device.outputUsesInterrupts == TERMIOS_POLLED) { 500 606 (*tty->device.write)(tty->minor, buf, len); 501 607 return; 502 608 } 503 newHead = tty->rawOutBuf Head;609 newHead = tty->rawOutBuf.Head; 504 610 while (len) { 505 611 /* … … 515 621 * with interrupts enabled. 516 622 */ 517 newHead = (newHead + 1) % RAW_OUTPUT_BUFFER_SIZE;623 newHead = (newHead + 1) % tty->rawOutBuf.Size; 518 624 rtems_interrupt_disable (level); 519 while (newHead == tty->rawOutBuf Tail) {625 while (newHead == tty->rawOutBuf.Tail) { 520 626 tty->rawOutBufState = rob_wait; 521 627 rtems_interrupt_enable (level); 522 sc = rtems_semaphore_obtain (tty->rawOutBuf Semaphore,628 sc = rtems_semaphore_obtain (tty->rawOutBuf.Semaphore, 523 629 RTEMS_WAIT, 524 630 RTEMS_NO_TIMEOUT); … … 527 633 rtems_interrupt_disable (level); 528 634 } 529 tty->rawOutBuf [tty->rawOutBufHead] = *buf++;530 tty->rawOutBuf Head = newHead;635 tty->rawOutBuf.theBuf[tty->rawOutBuf.Head] = *buf++; 636 tty->rawOutBuf.Head = newHead; 531 637 if (tty->rawOutBufState == rob_idle) { 532 638 /* check, whether XOFF has been received */ 533 639 if (!(tty->flow_ctrl & FL_ORCVXOF)) { 534 640 (*tty->device.write)(tty->minor, 535 (char *)&tty->rawOutBuf[tty->rawOutBufTail],1);641 (char *)&tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail],1); 536 642 } 537 643 else { … … 560 666 tty->column = 0; 561 667 if (tty->termios.c_oflag & ONLCR) { 562 osend("\r", 1, tty);668 rtems_termios_puts ("\r", 1, tty); 563 669 tty->column = 0; 564 670 } … … 581 687 if ((tty->termios.c_oflag & TABDLY) == XTABS) { 582 688 tty->column += i; 583 osend( " ", i, tty);689 rtems_termios_puts ( " ", i, tty); 584 690 return; 585 691 } … … 600 706 } 601 707 } 602 osend(&c, 1, tty);708 rtems_termios_puts (&c, 1, tty); 603 709 } 604 710 … … 613 719 if (sc != RTEMS_SUCCESSFUL) 614 720 return sc; 721 if (linesw[tty->t_line].l_write != NULL) { 722 sc = linesw[tty->t_line].l_write(tty,args); 723 rtems_semaphore_release (tty->osem); 724 return sc; 725 } 615 726 if (tty->termios.c_oflag & OPOST) { 616 727 unsigned32 count = args->count; … … 621 732 } 622 733 else { 623 osend(args->buffer, args->count, tty);734 rtems_termios_puts (args->buffer, args->count, tty); 624 735 args->bytes_moved = args->count; 625 736 } … … 639 750 echobuf[0] = '^'; 640 751 echobuf[1] = c ^ 0x40; 641 osend(echobuf, 2, tty);752 rtems_termios_puts (echobuf, 2, tty); 642 753 tty->column += 2; 643 754 } … … 702 813 */ 703 814 while (tty->column > col) { 704 osend("\b", 1, tty);815 rtems_termios_puts ("\b", 1, tty); 705 816 tty->column--; 706 817 } … … 708 819 else { 709 820 if (iscntrl (c) && (tty->termios.c_lflag & ECHOCTL)) { 710 osend("\b \b", 3, tty);821 rtems_termios_puts ("\b \b", 3, tty); 711 822 if (tty->column) 712 823 tty->column--; 713 824 } 714 825 if (!iscntrl (c) || (tty->termios.c_lflag & ECHOCTL)) { 715 osend("\b \b", 3, tty);826 rtems_termios_puts ("\b \b", 3, tty); 716 827 if (tty->column) 717 828 tty->column--; … … 873 984 * Process characters read from raw queue 874 985 */ 875 while (tty->rawInBuf Head != tty->rawInBufTail) {986 while (tty->rawInBuf.Head != tty->rawInBuf.Tail) { 876 987 unsigned char c; 877 988 unsigned int newHead; 878 989 879 newHead = (tty->rawInBuf Head + 1) % RAW_INPUT_BUFFER_SIZE;880 c = tty->rawInBuf [newHead];881 tty->rawInBuf Head = newHead;882 if(((tty->rawInBuf Tail-newHead+RAW_INPUT_BUFFER_SIZE)883 % RAW_INPUT_BUFFER_SIZE)990 newHead = (tty->rawInBuf.Head + 1) % tty->rawInBuf.Size; 991 c = tty->rawInBuf.theBuf[newHead]; 992 tty->rawInBuf.Head = newHead; 993 if(((tty->rawInBuf.Tail-newHead+tty->rawInBuf.Size) 994 % tty->rawInBuf.Size) 884 995 < tty->lowwater) { 885 996 tty->flow_ctrl &= ~FL_IREQXOF; … … 919 1030 * Wait for characters 920 1031 */ 921 sc = rtems_semaphore_obtain (tty->rawInBuf Semaphore,1032 sc = rtems_semaphore_obtain (tty->rawInBuf.Semaphore, 922 1033 tty->rawInBufSemaphoreOptions, 923 1034 timeout); … … 940 1051 if (sc != RTEMS_SUCCESSFUL) 941 1052 return sc; 1053 if (linesw[tty->t_line].l_read != NULL) { 1054 sc = linesw[tty->t_line].l_read(tty,args); 1055 rtems_semaphore_release (tty->isem); 1056 return sc; 1057 } 942 1058 if (tty->cindex == tty->ccount) { 943 1059 tty->cindex = tty->ccount = 0; 944 1060 tty->read_start_column = tty->column; 945 if (tty->device.pollRead) 1061 if (tty->device.pollRead != NULL 1062 && tty->device.outputUsesInterrupts == TERMIOS_POLLED) 946 1063 sc = fillBufferPoll (tty); 947 1064 else … … 957 1074 rtems_semaphore_release (tty->isem); 958 1075 return sc; 1076 } 1077 1078 /* 1079 * signal receive interrupt to rx daemon 1080 * NOTE: This routine runs in the context of the 1081 * device receive interrupt handler. 1082 */ 1083 void rtems_termios_rxirq_occured(struct rtems_termios_tty *tty) 1084 { 1085 /* 1086 * send event to rx daemon task 1087 */ 1088 rtems_event_send(tty->rxTaskId,TERMIOS_RX_PROC_EVENT); 959 1089 } 960 1090 … … 974 1104 boolean flow_rcv = FALSE; /* TRUE, if flow control char received */ 975 1105 rtems_interrupt_level level; 1106 1107 if (linesw[tty->t_line].l_rint != NULL) { 1108 while (len--) { 1109 c = *buf++; 1110 linesw[tty->t_line].l_rint(c,tty); 1111 } 1112 return 0; 1113 } 976 1114 977 1115 while (len--) { … … 1011 1149 /* if chars available, call write function... */ 1012 1150 (*tty->device.write)(tty->minor, 1013 (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1);1151 (char *)&tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail], 1); 1014 1152 } 1015 1153 /* reenable interrupts */ … … 1018 1156 } 1019 1157 else { 1020 newTail = (tty->rawInBuf Tail + 1) % RAW_INPUT_BUFFER_SIZE;1158 newTail = (tty->rawInBuf.Tail + 1) % tty->rawInBuf.Size; 1021 1159 /* if chars_in_buffer > highwater */ 1022 1160 rtems_interrupt_disable(level); 1023 if ((((newTail - tty->rawInBuf Head + RAW_INPUT_BUFFER_SIZE)1024 % RAW_INPUT_BUFFER_SIZE)1161 if ((((newTail - tty->rawInBuf.Head + tty->rawInBuf.Size) 1162 % tty->rawInBuf.Size) 1025 1163 > tty->highwater) && 1026 1164 !(tty->flow_ctrl & FL_IREQXOF)) { … … 1051 1189 rtems_interrupt_enable(level); 1052 1190 1053 if (newTail == tty->rawInBuf Head) {1191 if (newTail == tty->rawInBuf.Head) { 1054 1192 dropped++; 1055 1193 } 1056 1194 else { 1057 tty->rawInBuf [newTail] = c;1058 tty->rawInBuf Tail = newTail;1195 tty->rawInBuf.theBuf[newTail] = c; 1196 tty->rawInBuf.Tail = newTail; 1059 1197 } 1060 1198 } 1061 1199 } 1062 1200 tty->rawInBufDropped += dropped; 1063 rtems_semaphore_release (tty->rawInBuf Semaphore);1201 rtems_semaphore_release (tty->rawInBuf.Semaphore); 1064 1202 return dropped; 1203 } 1204 1205 /* 1206 * in task-driven mode, this function is called in Tx task context 1207 * in interrupt-driven mode, this function is called in TxIRQ context 1208 */ 1209 int 1210 rtems_termios_refill_transmitter (struct rtems_termios_tty *tty) 1211 { 1212 unsigned int newTail; 1213 int nToSend; 1214 rtems_interrupt_level level; 1215 int len; 1216 1217 /* check for XOF/XON to send */ 1218 if ((tty->flow_ctrl & (FL_MDXOF | FL_IREQXOF | FL_ISNTXOF)) 1219 == (FL_MDXOF | FL_IREQXOF)) { 1220 /* XOFF should be sent now... */ 1221 (*tty->device.write)(tty->minor, 1222 &(tty->termios.c_cc[VSTOP]), 1); 1223 1224 rtems_interrupt_disable(level); 1225 tty->t_dqlen--; 1226 tty->flow_ctrl |= FL_ISNTXOF; 1227 rtems_interrupt_enable(level); 1228 1229 nToSend = 1; 1230 } 1231 else if ((tty->flow_ctrl & (FL_IREQXOF | FL_ISNTXOF)) 1232 == FL_ISNTXOF) { 1233 /* NOTE: send XON even, if no longer in XON/XOFF mode... */ 1234 /* XON should be sent now... */ 1235 /* 1236 * FIXME: this .write call will generate another 1237 * dequeue callback. This will advance the "Tail" in the data 1238 * buffer, although the corresponding data is not yet out! 1239 * Therefore the dequeue "length" should be reduced by 1 1240 */ 1241 (*tty->device.write)(tty->minor, 1242 &(tty->termios.c_cc[VSTART]), 1); 1243 1244 rtems_interrupt_disable(level); 1245 tty->t_dqlen--; 1246 tty->flow_ctrl &= ~FL_ISNTXOF; 1247 rtems_interrupt_enable(level); 1248 1249 nToSend = 1; 1250 } 1251 else { 1252 if ( tty->rawOutBuf.Head == tty->rawOutBuf.Tail ) { 1253 /* 1254 * buffer was empty 1255 */ 1256 if (tty->rawOutBufState == rob_wait) { 1257 /* 1258 * this should never happen... 1259 */ 1260 rtems_semaphore_release (tty->rawOutBuf.Semaphore); 1261 } 1262 return 0; 1263 } 1264 1265 rtems_interrupt_disable(level); 1266 len = tty->t_dqlen; 1267 tty->t_dqlen = 0; 1268 rtems_interrupt_enable(level); 1269 1270 newTail = (tty->rawOutBuf.Tail + len) % tty->rawOutBuf.Size; 1271 tty->rawOutBuf.Tail = newTail; 1272 if (tty->rawOutBufState == rob_wait) { 1273 /* 1274 * wake up any pending writer task 1275 */ 1276 rtems_semaphore_release (tty->rawOutBuf.Semaphore); 1277 } 1278 if (newTail == tty->rawOutBuf.Head) { 1279 /* 1280 * Buffer has become empty 1281 */ 1282 tty->rawOutBufState = rob_idle; 1283 nToSend = 0; 1284 } 1285 /* check, whether output should stop due to received XOFF */ 1286 else if ((tty->flow_ctrl & (FL_MDXON | FL_ORCVXOF)) 1287 == (FL_MDXON | FL_ORCVXOF)) { 1288 /* Buffer not empty, but output stops due to XOFF */ 1289 /* set flag, that output has been stopped */ 1290 rtems_interrupt_disable(level); 1291 tty->flow_ctrl |= FL_OSTOP; 1292 tty->rawOutBufState = rob_busy; /*apm*/ 1293 rtems_interrupt_enable(level); 1294 nToSend = 0; 1295 } 1296 else { 1297 /* 1298 * Buffer not empty, start tranmitter 1299 */ 1300 if (newTail > tty->rawOutBuf.Head) 1301 nToSend = tty->rawOutBuf.Size - newTail; 1302 else 1303 nToSend = tty->rawOutBuf.Head - newTail; 1304 /* when flow control XON or XOF, don't send blocks of data */ 1305 /* to allow fast reaction on incoming flow ctrl and low latency*/ 1306 /* for outgoing flow control */ 1307 if (tty->flow_ctrl & (FL_MDXON | FL_MDXOF)) { 1308 nToSend = 1; 1309 } 1310 tty->rawOutBufState = rob_busy; /*apm*/ 1311 (*tty->device.write)(tty->minor, 1312 (char *)&tty->rawOutBuf.theBuf[newTail], 1313 nToSend); 1314 } 1315 tty->rawOutBuf.Tail = newTail; /*apm*/ 1316 } 1317 return nToSend; 1065 1318 } 1066 1319 … … 1078 1331 { 1079 1332 struct rtems_termios_tty *tty = ttyp; 1080 unsigned int newTail; 1081 int nToSend; 1082 1083 /* check for XOF/XON to send */ 1084 if ((tty->flow_ctrl & (FL_MDXOF | FL_IREQXOF | FL_ISNTXOF)) 1085 == (FL_MDXOF | FL_IREQXOF)) { 1086 /* XOFF should be sent now... */ 1087 (*tty->device.write)(tty->minor, 1088 &(tty->termios.c_cc[VSTOP]), 1); 1089 tty->flow_ctrl |= FL_ISNTXOF; 1090 nToSend = 1; 1091 } 1092 else if ((tty->flow_ctrl & (FL_IREQXOF | FL_ISNTXOF)) 1093 == FL_ISNTXOF) { 1094 /* NOTE: send XON even, if no longer in XON/XOFF mode... */ 1095 /* XON should be sent now... */ 1096 (*tty->device.write)(tty->minor, 1097 &(tty->termios.c_cc[VSTART]), 1); 1098 tty->flow_ctrl &= ~FL_ISNTXOF; 1099 nToSend = 1; 1333 rtems_status_code sc; 1334 1335 /* 1336 * sum up character count already sent 1337 */ 1338 tty->t_dqlen += len; 1339 1340 if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) { 1341 /* 1342 * send wake up to transmitter task 1343 */ 1344 sc = rtems_event_send(tty->txTaskId, 1345 TERMIOS_TX_START_EVENT); 1346 if (sc != RTEMS_SUCCESSFUL) 1347 rtems_fatal_error_occurred (sc); 1348 return 0; /* nothing to output in IRQ... */ 1100 1349 } 1101 1350 else { 1102 if (tty->rawOutBufState == rob_wait) 1103 rtems_semaphore_release (tty->rawOutBufSemaphore); 1104 if ( tty->rawOutBufHead == tty->rawOutBufTail ) { 1105 tty->rawOutBufState = rob_idle; 1106 return 0; 1107 } 1108 newTail = (tty->rawOutBufTail + len) % RAW_OUTPUT_BUFFER_SIZE; 1109 if (newTail == tty->rawOutBufHead) { 1110 /* 1111 * Buffer empty 1112 */ 1113 tty->rawOutBufState = rob_idle; 1114 nToSend = 0; 1115 } 1116 /* check, whether output should stop due to received XOFF */ 1117 else if ((tty->flow_ctrl & (FL_MDXON | FL_ORCVXOF)) 1118 == (FL_MDXON | FL_ORCVXOF)) { 1119 /* Buffer not empty, but output stops due to XOFF */ 1120 /* set flag, that output has been stopped */ 1121 tty->flow_ctrl |= FL_OSTOP; 1122 tty->rawOutBufState = rob_busy; 1123 nToSend = 0; 1124 } 1125 else { 1126 /* 1127 * Buffer not empty, start tranmitter 1128 */ 1129 if (newTail > tty->rawOutBufHead) 1130 nToSend = RAW_OUTPUT_BUFFER_SIZE - newTail; 1131 else 1132 nToSend = tty->rawOutBufHead - newTail; 1133 /* when flow control XON or XOF, don't send blocks of data */ 1134 /* to allow fast reaction on incoming flow ctrl and low latency*/ 1135 /* for outgoing flow control */ 1136 if (tty->flow_ctrl & (FL_MDXON | FL_MDXOF)) 1137 nToSend = 1; 1138 tty->rawOutBufState = rob_busy; 1139 (*tty->device.write)(tty->minor, (char *)&tty->rawOutBuf[newTail], nToSend); 1140 } 1141 tty->rawOutBufTail = newTail; 1142 } 1143 return nToSend; 1144 } 1351 return rtems_termios_refill_transmitter(tty); 1352 } 1353 } 1354 1355 /* 1356 * this task actually processes any transmit events 1357 */ 1358 static rtems_task rtems_termios_txdaemon(rtems_task_argument argument) 1359 { 1360 struct rtems_termios_tty *tty = (struct rtems_termios_tty *)argument; 1361 rtems_event_set the_event; 1362 1363 while (1) { 1364 /* 1365 * wait for rtems event 1366 */ 1367 rtems_event_receive((TERMIOS_TX_START_EVENT | 1368 TERMIOS_TX_TERMINATE_EVENT), 1369 RTEMS_EVENT_ANY | RTEMS_WAIT, 1370 RTEMS_NO_TIMEOUT, 1371 &the_event); 1372 if ((the_event & TERMIOS_TX_TERMINATE_EVENT) != 0) { 1373 tty->txTaskId = 0; 1374 rtems_task_delete(RTEMS_SELF); 1375 } 1376 else { 1377 /* 1378 * call any line discipline start function 1379 */ 1380 if (linesw[tty->t_line].l_start != NULL) { 1381 linesw[tty->t_line].l_start(tty); 1382 } 1383 /* 1384 * try to push further characters to device 1385 */ 1386 rtems_termios_refill_transmitter(tty); 1387 } 1388 } 1389 } 1390 1391 /* 1392 * this task actually processes any receive events 1393 */ 1394 static rtems_task rtems_termios_rxdaemon(rtems_task_argument argument) 1395 { 1396 struct rtems_termios_tty *tty = (struct rtems_termios_tty *)argument; 1397 rtems_event_set the_event; 1398 int c; 1399 char c_buf; 1400 while (1) { 1401 /* 1402 * wait for rtems event 1403 */ 1404 rtems_event_receive((TERMIOS_RX_PROC_EVENT | 1405 TERMIOS_RX_TERMINATE_EVENT), 1406 RTEMS_EVENT_ANY | RTEMS_WAIT, 1407 RTEMS_NO_TIMEOUT, 1408 &the_event); 1409 if ((the_event & TERMIOS_RX_TERMINATE_EVENT) != 0) { 1410 tty->rxTaskId = 0; 1411 rtems_task_delete(RTEMS_SELF); 1412 } 1413 else { 1414 /* 1415 * do something 1416 */ 1417 c = tty->device.pollRead(tty->minor); 1418 if (c != EOF) { 1419 /* 1420 * pollRead did call enqueue on its own 1421 */ 1422 c_buf = c; 1423 rtems_termios_enqueue_raw_characters ( 1424 tty,&c_buf,1); 1425 } 1426 } 1427 } 1428 } -
c/src/lib/ChangeLog
rc8471315 re2af631 1 2 2000-11-25 Antti P Miettinen <antti.p.miettinen@nokia.com> 3 4 * libc/termios.c, libc/termiostypes.h: Task driver driver model 5 and line discipline support from Thomas Doerfler 6 <Thomas.Doerfler@imd-systems.de>. 1 7 2 8 2000-11-20 Dmitry Kargapolov <dk@gentex.ru> -
c/src/lib/libc/Makefile.am
rc8471315 re2af631 82 82 83 83 EXTRA_DIST = $(DOC_FILES) $(COMMON_C_FILES) $(EMBEDDED_C_FILES) \ 84 $(UNIX_C_FILES) 84 $(UNIX_C_FILES) termiostypes.h 85 85 86 86 include $(top_srcdir)/../../../automake/local.am -
c/src/lib/libc/termios.c
rc8471315 re2af631 24 24 #include <termios.h> 25 25 #include <unistd.h> 26 #include <sys/ttycom.h> 27 28 #include "termiostypes.h" 26 29 27 30 /* … … 61 64 #define RAW_OUTPUT_BUFFER_SIZE 64 62 65 63 /*64 * Variables associated with each termios instance.65 * One structure for each hardware I/O device.66 */67 struct rtems_termios_tty {68 /*69 * Linked-list of active TERMIOS devices70 */71 struct rtems_termios_tty *forw;72 struct rtems_termios_tty *back;73 74 /*75 * How many times has this device been opened76 */77 int refcount;78 79 /*80 * This device81 */82 rtems_device_major_number major;83 rtems_device_major_number minor;84 85 /*86 * Mutual-exclusion semaphores87 */88 rtems_id isem;89 rtems_id osem;90 91 /*92 * The canonical (cooked) character buffer93 */94 char cbuf[CBUFSIZE];95 int ccount;96 int cindex;97 98 /*99 * Keep track of cursor (printhead) position100 */101 int column;102 int read_start_column;103 104 /*105 * The ioctl settings106 */107 struct termios termios;108 rtems_interval vtimeTicks;109 110 /*111 * Raw input character buffer112 */113 volatile char rawInBuf[RAW_INPUT_BUFFER_SIZE];114 volatile unsigned int rawInBufHead;115 volatile unsigned int rawInBufTail;116 rtems_id rawInBufSemaphore;117 rtems_unsigned32 rawInBufSemaphoreOptions;118 rtems_interval rawInBufSemaphoreTimeout;119 rtems_interval rawInBufSemaphoreFirstTimeout;120 unsigned int rawInBufDropped; /* Statistics */121 122 /*123 * Raw output character buffer124 */125 volatile char rawOutBuf[RAW_OUTPUT_BUFFER_SIZE];126 volatile unsigned int rawOutBufHead;127 volatile unsigned int rawOutBufTail;128 rtems_id rawOutBufSemaphore;129 volatile enum {rob_idle, rob_busy, rob_wait } rawOutBufState;130 131 /*132 * Callbacks to device-specific routines133 */134 rtems_termios_callbacks device;135 volatile unsigned int flow_ctrl;136 unsigned int lowwater,highwater;137 };138 139 66 /* fields for "flow_ctrl" status */ 140 67 #define FL_IREQXOF 1 /* input queue requests stop of incoming data */ … … 149 76 #define FL_MDXOF 0x400 /* output controlled with XON/XOFF protocol */ 150 77 78 #define NODISC(n) \ 79 { NULL, NULL, NULL, NULL, \ 80 NULL, NULL, NULL, NULL } 81 /* 82 * FIXME: change linesw entries consistant with linesw entry usage... 83 */ 84 struct linesw linesw[MAXLDISC] = 85 { 86 NODISC(0), /* 0- termios-built-in */ 87 NODISC(1), /* 1- defunct */ 88 NODISC(2), /* 2- NTTYDISC */ 89 NODISC(3), /* TABLDISC */ 90 NODISC(4), /* SLIPDISC */ 91 NODISC(5), /* PPPDISC */ 92 NODISC(6), /* loadable */ 93 NODISC(7), /* loadable */ 94 }; 95 96 int nlinesw = sizeof (linesw) / sizeof (linesw[0]); 97 151 98 extern struct rtems_termios_tty *rtems_termios_ttyHead; 152 99 extern struct rtems_termios_tty *rtems_termios_ttyTail; 153 100 extern rtems_id rtems_termios_ttyMutex; 101 102 static rtems_task rtems_termios_rxdaemon(rtems_task_argument argument); 103 static rtems_task rtems_termios_txdaemon(rtems_task_argument argument); 104 /* 105 * some constants for I/O daemon task creation 106 */ 107 #define TERMIOS_TXTASK_PRIO 10 108 #define TERMIOS_RXTASK_PRIO 9 109 #define TERMIOS_TXTASK_STACKSIZE 1024 110 #define TERMIOS_RXTASK_STACKSIZE 1024 111 /* 112 * some events to be sent to the I/O tasks 113 */ 114 #define TERMIOS_TX_START_EVENT RTEMS_EVENT_1 115 #define TERMIOS_TX_TERMINATE_EVENT RTEMS_EVENT_0 116 117 #define TERMIOS_RX_PROC_EVENT RTEMS_EVENT_1 118 #define TERMIOS_RX_TERMINATE_EVENT RTEMS_EVENT_0 154 119 155 120 /* … … 171 136 * See if the device has already been opened 172 137 */ 173 sc = rtems_semaphore_obtain (rtems_termios_ttyMutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT); 138 sc = rtems_semaphore_obtain (rtems_termios_ttyMutex, 139 RTEMS_WAIT, RTEMS_NO_TIMEOUT); 174 140 if (sc != RTEMS_SUCCESSFUL) 175 141 return sc; … … 189 155 return RTEMS_NO_MEMORY; 190 156 } 157 /* 158 * allocate raw input buffer 159 */ 160 tty->rawInBuf.Size = RAW_INPUT_BUFFER_SIZE; 161 tty->rawInBuf.theBuf = malloc (tty->rawInBuf.Size); 162 if (tty->rawInBuf.theBuf == NULL) { 163 free(tty); 164 rtems_semaphore_release (rtems_termios_ttyMutex); 165 return RTEMS_NO_MEMORY; 166 } 167 /* 168 * allocate raw output buffer 169 */ 170 tty->rawOutBuf.Size = RAW_OUTPUT_BUFFER_SIZE; 171 tty->rawOutBuf.theBuf = malloc (tty->rawOutBuf.Size); 172 if (tty->rawInBuf.theBuf == NULL) { 173 free((void *)(tty->rawInBuf.theBuf)); 174 free(tty); 175 rtems_semaphore_release (rtems_termios_ttyMutex); 176 return RTEMS_NO_MEMORY; 177 } 178 /* 179 * allocate cooked buffer 180 */ 181 tty->cbuf = malloc (CBUFSIZE); 182 if (tty->cbuf == NULL) { 183 free((void *)(tty->rawOutBuf.theBuf)); 184 free((void *)(tty->rawInBuf.theBuf)); 185 free(tty); 186 rtems_semaphore_release (rtems_termios_ttyMutex); 187 return RTEMS_NO_MEMORY; 188 } 189 /* 190 * link tty 191 */ 191 192 if (rtems_termios_ttyHead) 192 193 rtems_termios_ttyHead->back = tty; … … 222 223 RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_FIFO, 223 224 RTEMS_NO_PRIORITY, 224 &tty->rawOutBuf Semaphore);225 &tty->rawOutBuf.Semaphore); 225 226 if (sc != RTEMS_SUCCESSFUL) 226 227 rtems_fatal_error_occurred (sc); … … 231 232 */ 232 233 tty->device = *callbacks; 233 if (!tty->device.pollRead) { 234 235 /* 236 * Create I/O tasks 237 */ 238 if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) { 239 sc = rtems_task_create ( 240 rtems_build_name ('T', 'x', 'T', c), 241 TERMIOS_TXTASK_PRIO, 242 TERMIOS_TXTASK_STACKSIZE, 243 RTEMS_NO_PREEMPT | RTEMS_NO_TIMESLICE | 244 RTEMS_NO_ASR, 245 RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL, 246 &tty->txTaskId); 247 if (sc != RTEMS_SUCCESSFUL) 248 rtems_fatal_error_occurred (sc); 249 sc = rtems_task_create ( 250 rtems_build_name ('R', 'x', 'T', c), 251 TERMIOS_RXTASK_PRIO, 252 TERMIOS_RXTASK_STACKSIZE, 253 RTEMS_NO_PREEMPT | RTEMS_NO_TIMESLICE | 254 RTEMS_NO_ASR, 255 RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL, 256 &tty->rxTaskId); 257 if (sc != RTEMS_SUCCESSFUL) 258 rtems_fatal_error_occurred (sc); 259 260 } 261 if ((tty->device.pollRead == NULL) || 262 (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN)){ 234 263 sc = rtems_semaphore_create ( 235 264 rtems_build_name ('T', 'R', 'r', c), … … 237 266 RTEMS_COUNTING_SEMAPHORE | RTEMS_PRIORITY, 238 267 RTEMS_NO_PRIORITY, 239 &tty->rawInBuf Semaphore);268 &tty->rawInBuf.Semaphore); 240 269 if (sc != RTEMS_SUCCESSFUL) 241 270 rtems_fatal_error_occurred (sc); … … 270 299 * set low/highwater mark for XON/XOFF support 271 300 */ 272 tty->lowwater = RAW_INPUT_BUFFER_SIZE* 1/2;273 tty->highwater = RAW_INPUT_BUFFER_SIZE* 3/4;301 tty->lowwater = tty->rawInBuf.Size * 1/2; 302 tty->highwater = tty->rawInBuf.Size * 3/4; 274 303 /* 275 304 * Bump name characer … … 280 309 } 281 310 args->iop->data1 = tty; 282 if (!tty->refcount++ && tty->device.firstOpen) 311 if (!tty->refcount++) { 312 if (tty->device.firstOpen) 283 313 (*tty->device.firstOpen)(major, minor, arg); 314 /* 315 * start I/O tasks, if needed 316 */ 317 if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) { 318 sc = rtems_task_start(tty->rxTaskId, 319 rtems_termios_rxdaemon, 320 (rtems_task_argument)tty); 321 if (sc != RTEMS_SUCCESSFUL) 322 rtems_fatal_error_occurred (sc); 323 324 sc = rtems_task_start(tty->txTaskId, 325 rtems_termios_txdaemon, 326 (rtems_task_argument)tty); 327 if (sc != RTEMS_SUCCESSFUL) 328 rtems_fatal_error_occurred (sc); 329 } 330 } 284 331 rtems_semaphore_release (rtems_termios_ttyMutex); 285 332 return RTEMS_SUCCESSFUL; … … 295 342 rtems_status_code sc; 296 343 297 if (tty->device.outputUsesInterrupts ) {344 if (tty->device.outputUsesInterrupts != TERMIOS_POLLED) { 298 345 rtems_interrupt_disable (level); 299 while (tty->rawOutBuf Tail != tty->rawOutBufHead) {346 while (tty->rawOutBuf.Tail != tty->rawOutBuf.Head) { 300 347 tty->rawOutBufState = rob_wait; 301 348 rtems_interrupt_enable (level); 302 sc = rtems_semaphore_obtain (tty->rawOutBuf Semaphore,349 sc = rtems_semaphore_obtain (tty->rawOutBuf.Semaphore, 303 350 RTEMS_WAIT, 304 351 RTEMS_NO_TIMEOUT); … … 322 369 rtems_fatal_error_occurred (sc); 323 370 if (--tty->refcount == 0) { 324 drainOutput (tty); 371 if (linesw[tty->t_line].l_close != NULL) { 372 /* 373 * call discipline-specific close 374 */ 375 sc = linesw[tty->t_line].l_close(tty); 376 } 377 else { 378 /* 379 * default: just flush output buffer 380 */ 381 drainOutput (tty); 382 } 383 384 if (tty->device.outputUsesInterrupts 385 == TERMIOS_TASK_DRIVEN) { 386 /* 387 * send "terminate" to I/O tasks 388 */ 389 sc = rtems_event_send( 390 tty->rxTaskId, 391 TERMIOS_RX_TERMINATE_EVENT); 392 if (sc != RTEMS_SUCCESSFUL) 393 rtems_fatal_error_occurred (sc); 394 sc = rtems_event_send( 395 tty->txTaskId, 396 TERMIOS_TX_TERMINATE_EVENT); 397 if (sc != RTEMS_SUCCESSFUL) 398 rtems_fatal_error_occurred (sc); 399 } 325 400 if (tty->device.lastClose) 326 401 (*tty->device.lastClose)(tty->major, tty->minor, arg); … … 335 410 rtems_semaphore_delete (tty->isem); 336 411 rtems_semaphore_delete (tty->osem); 337 rtems_semaphore_delete (tty->rawOutBufSemaphore); 338 if (!tty->device.pollRead) 339 rtems_semaphore_delete (tty->rawInBufSemaphore); 412 rtems_semaphore_delete (tty->rawOutBuf.Semaphore); 413 if ((tty->device.pollRead == NULL) || 414 (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN)) 415 rtems_semaphore_delete (tty->rawInBuf.Semaphore); 340 416 free (tty); 341 417 } … … 367 443 /* if chars available, call write function... */ 368 444 (*tty->device.write)(tty->minor, 369 (char *)&tty->rawOutBuf[tty->rawOutBufTail],1);445 (char *)&tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail],1); 370 446 } 371 447 /* reenable interrupts */ … … 428 504 switch (args->command) { 429 505 default: 430 sc = RTEMS_INVALID_NUMBER; 506 if (linesw[tty->t_line].l_ioctl != NULL) { 507 sc = linesw[tty->t_line].l_ioctl(tty,args); 508 } 509 else { 510 sc = RTEMS_INVALID_NUMBER; 511 } 431 512 break; 432 513 … … 477 558 break; 478 559 560 /* 561 * FIXME: add various ioctl code handlers 562 */ 563 564 #if 1 /* FIXME */ 565 case TIOCSETD: 566 /* 567 * close old line discipline 568 */ 569 if (linesw[tty->t_line].l_close != NULL) { 570 sc = linesw[tty->t_line].l_close(tty); 571 } 572 tty->t_line=*(int*)(args->buffer); 573 tty->t_sc = NULL; /* ensure that no more valid data */ 574 /* 575 * open new line discipline 576 */ 577 if (linesw[tty->t_line].l_open != NULL) { 578 sc = linesw[tty->t_line].l_open(tty); 579 } 580 break; 581 case TIOCGETD: 582 *(int*)(args->buffer)=tty->t_line; 583 break; 584 #endif 479 585 case FIONREAD: 480 586 /* Half guess that this is the right operation */ … … 490 596 * Send characters to device-specific code 491 597 */ 492 staticvoid493 osend(const char *buf, int len, struct rtems_termios_tty *tty)598 void 599 rtems_termios_puts (const char *buf, int len, struct rtems_termios_tty *tty) 494 600 { 495 601 unsigned int newHead; … … 497 603 rtems_status_code sc; 498 604 499 if ( !tty->device.outputUsesInterrupts) {605 if (tty->device.outputUsesInterrupts == TERMIOS_POLLED) { 500 606 (*tty->device.write)(tty->minor, buf, len); 501 607 return; 502 608 } 503 newHead = tty->rawOutBuf Head;609 newHead = tty->rawOutBuf.Head; 504 610 while (len) { 505 611 /* … … 515 621 * with interrupts enabled. 516 622 */ 517 newHead = (newHead + 1) % RAW_OUTPUT_BUFFER_SIZE;623 newHead = (newHead + 1) % tty->rawOutBuf.Size; 518 624 rtems_interrupt_disable (level); 519 while (newHead == tty->rawOutBuf Tail) {625 while (newHead == tty->rawOutBuf.Tail) { 520 626 tty->rawOutBufState = rob_wait; 521 627 rtems_interrupt_enable (level); 522 sc = rtems_semaphore_obtain (tty->rawOutBuf Semaphore,628 sc = rtems_semaphore_obtain (tty->rawOutBuf.Semaphore, 523 629 RTEMS_WAIT, 524 630 RTEMS_NO_TIMEOUT); … … 527 633 rtems_interrupt_disable (level); 528 634 } 529 tty->rawOutBuf [tty->rawOutBufHead] = *buf++;530 tty->rawOutBuf Head = newHead;635 tty->rawOutBuf.theBuf[tty->rawOutBuf.Head] = *buf++; 636 tty->rawOutBuf.Head = newHead; 531 637 if (tty->rawOutBufState == rob_idle) { 532 638 /* check, whether XOFF has been received */ 533 639 if (!(tty->flow_ctrl & FL_ORCVXOF)) { 534 640 (*tty->device.write)(tty->minor, 535 (char *)&tty->rawOutBuf[tty->rawOutBufTail],1);641 (char *)&tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail],1); 536 642 } 537 643 else { … … 560 666 tty->column = 0; 561 667 if (tty->termios.c_oflag & ONLCR) { 562 osend("\r", 1, tty);668 rtems_termios_puts ("\r", 1, tty); 563 669 tty->column = 0; 564 670 } … … 581 687 if ((tty->termios.c_oflag & TABDLY) == XTABS) { 582 688 tty->column += i; 583 osend( " ", i, tty);689 rtems_termios_puts ( " ", i, tty); 584 690 return; 585 691 } … … 600 706 } 601 707 } 602 osend(&c, 1, tty);708 rtems_termios_puts (&c, 1, tty); 603 709 } 604 710 … … 613 719 if (sc != RTEMS_SUCCESSFUL) 614 720 return sc; 721 if (linesw[tty->t_line].l_write != NULL) { 722 sc = linesw[tty->t_line].l_write(tty,args); 723 rtems_semaphore_release (tty->osem); 724 return sc; 725 } 615 726 if (tty->termios.c_oflag & OPOST) { 616 727 unsigned32 count = args->count; … … 621 732 } 622 733 else { 623 osend(args->buffer, args->count, tty);734 rtems_termios_puts (args->buffer, args->count, tty); 624 735 args->bytes_moved = args->count; 625 736 } … … 639 750 echobuf[0] = '^'; 640 751 echobuf[1] = c ^ 0x40; 641 osend(echobuf, 2, tty);752 rtems_termios_puts (echobuf, 2, tty); 642 753 tty->column += 2; 643 754 } … … 702 813 */ 703 814 while (tty->column > col) { 704 osend("\b", 1, tty);815 rtems_termios_puts ("\b", 1, tty); 705 816 tty->column--; 706 817 } … … 708 819 else { 709 820 if (iscntrl (c) && (tty->termios.c_lflag & ECHOCTL)) { 710 osend("\b \b", 3, tty);821 rtems_termios_puts ("\b \b", 3, tty); 711 822 if (tty->column) 712 823 tty->column--; 713 824 } 714 825 if (!iscntrl (c) || (tty->termios.c_lflag & ECHOCTL)) { 715 osend("\b \b", 3, tty);826 rtems_termios_puts ("\b \b", 3, tty); 716 827 if (tty->column) 717 828 tty->column--; … … 873 984 * Process characters read from raw queue 874 985 */ 875 while (tty->rawInBuf Head != tty->rawInBufTail) {986 while (tty->rawInBuf.Head != tty->rawInBuf.Tail) { 876 987 unsigned char c; 877 988 unsigned int newHead; 878 989 879 newHead = (tty->rawInBuf Head + 1) % RAW_INPUT_BUFFER_SIZE;880 c = tty->rawInBuf [newHead];881 tty->rawInBuf Head = newHead;882 if(((tty->rawInBuf Tail-newHead+RAW_INPUT_BUFFER_SIZE)883 % RAW_INPUT_BUFFER_SIZE)990 newHead = (tty->rawInBuf.Head + 1) % tty->rawInBuf.Size; 991 c = tty->rawInBuf.theBuf[newHead]; 992 tty->rawInBuf.Head = newHead; 993 if(((tty->rawInBuf.Tail-newHead+tty->rawInBuf.Size) 994 % tty->rawInBuf.Size) 884 995 < tty->lowwater) { 885 996 tty->flow_ctrl &= ~FL_IREQXOF; … … 919 1030 * Wait for characters 920 1031 */ 921 sc = rtems_semaphore_obtain (tty->rawInBuf Semaphore,1032 sc = rtems_semaphore_obtain (tty->rawInBuf.Semaphore, 922 1033 tty->rawInBufSemaphoreOptions, 923 1034 timeout); … … 940 1051 if (sc != RTEMS_SUCCESSFUL) 941 1052 return sc; 1053 if (linesw[tty->t_line].l_read != NULL) { 1054 sc = linesw[tty->t_line].l_read(tty,args); 1055 rtems_semaphore_release (tty->isem); 1056 return sc; 1057 } 942 1058 if (tty->cindex == tty->ccount) { 943 1059 tty->cindex = tty->ccount = 0; 944 1060 tty->read_start_column = tty->column; 945 if (tty->device.pollRead) 1061 if (tty->device.pollRead != NULL 1062 && tty->device.outputUsesInterrupts == TERMIOS_POLLED) 946 1063 sc = fillBufferPoll (tty); 947 1064 else … … 957 1074 rtems_semaphore_release (tty->isem); 958 1075 return sc; 1076 } 1077 1078 /* 1079 * signal receive interrupt to rx daemon 1080 * NOTE: This routine runs in the context of the 1081 * device receive interrupt handler. 1082 */ 1083 void rtems_termios_rxirq_occured(struct rtems_termios_tty *tty) 1084 { 1085 /* 1086 * send event to rx daemon task 1087 */ 1088 rtems_event_send(tty->rxTaskId,TERMIOS_RX_PROC_EVENT); 959 1089 } 960 1090 … … 974 1104 boolean flow_rcv = FALSE; /* TRUE, if flow control char received */ 975 1105 rtems_interrupt_level level; 1106 1107 if (linesw[tty->t_line].l_rint != NULL) { 1108 while (len--) { 1109 c = *buf++; 1110 linesw[tty->t_line].l_rint(c,tty); 1111 } 1112 return 0; 1113 } 976 1114 977 1115 while (len--) { … … 1011 1149 /* if chars available, call write function... */ 1012 1150 (*tty->device.write)(tty->minor, 1013 (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1);1151 (char *)&tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail], 1); 1014 1152 } 1015 1153 /* reenable interrupts */ … … 1018 1156 } 1019 1157 else { 1020 newTail = (tty->rawInBuf Tail + 1) % RAW_INPUT_BUFFER_SIZE;1158 newTail = (tty->rawInBuf.Tail + 1) % tty->rawInBuf.Size; 1021 1159 /* if chars_in_buffer > highwater */ 1022 1160 rtems_interrupt_disable(level); 1023 if ((((newTail - tty->rawInBuf Head + RAW_INPUT_BUFFER_SIZE)1024 % RAW_INPUT_BUFFER_SIZE)1161 if ((((newTail - tty->rawInBuf.Head + tty->rawInBuf.Size) 1162 % tty->rawInBuf.Size) 1025 1163 > tty->highwater) && 1026 1164 !(tty->flow_ctrl & FL_IREQXOF)) { … … 1051 1189 rtems_interrupt_enable(level); 1052 1190 1053 if (newTail == tty->rawInBuf Head) {1191 if (newTail == tty->rawInBuf.Head) { 1054 1192 dropped++; 1055 1193 } 1056 1194 else { 1057 tty->rawInBuf [newTail] = c;1058 tty->rawInBuf Tail = newTail;1195 tty->rawInBuf.theBuf[newTail] = c; 1196 tty->rawInBuf.Tail = newTail; 1059 1197 } 1060 1198 } 1061 1199 } 1062 1200 tty->rawInBufDropped += dropped; 1063 rtems_semaphore_release (tty->rawInBuf Semaphore);1201 rtems_semaphore_release (tty->rawInBuf.Semaphore); 1064 1202 return dropped; 1203 } 1204 1205 /* 1206 * in task-driven mode, this function is called in Tx task context 1207 * in interrupt-driven mode, this function is called in TxIRQ context 1208 */ 1209 int 1210 rtems_termios_refill_transmitter (struct rtems_termios_tty *tty) 1211 { 1212 unsigned int newTail; 1213 int nToSend; 1214 rtems_interrupt_level level; 1215 int len; 1216 1217 /* check for XOF/XON to send */ 1218 if ((tty->flow_ctrl & (FL_MDXOF | FL_IREQXOF | FL_ISNTXOF)) 1219 == (FL_MDXOF | FL_IREQXOF)) { 1220 /* XOFF should be sent now... */ 1221 (*tty->device.write)(tty->minor, 1222 &(tty->termios.c_cc[VSTOP]), 1); 1223 1224 rtems_interrupt_disable(level); 1225 tty->t_dqlen--; 1226 tty->flow_ctrl |= FL_ISNTXOF; 1227 rtems_interrupt_enable(level); 1228 1229 nToSend = 1; 1230 } 1231 else if ((tty->flow_ctrl & (FL_IREQXOF | FL_ISNTXOF)) 1232 == FL_ISNTXOF) { 1233 /* NOTE: send XON even, if no longer in XON/XOFF mode... */ 1234 /* XON should be sent now... */ 1235 /* 1236 * FIXME: this .write call will generate another 1237 * dequeue callback. This will advance the "Tail" in the data 1238 * buffer, although the corresponding data is not yet out! 1239 * Therefore the dequeue "length" should be reduced by 1 1240 */ 1241 (*tty->device.write)(tty->minor, 1242 &(tty->termios.c_cc[VSTART]), 1); 1243 1244 rtems_interrupt_disable(level); 1245 tty->t_dqlen--; 1246 tty->flow_ctrl &= ~FL_ISNTXOF; 1247 rtems_interrupt_enable(level); 1248 1249 nToSend = 1; 1250 } 1251 else { 1252 if ( tty->rawOutBuf.Head == tty->rawOutBuf.Tail ) { 1253 /* 1254 * buffer was empty 1255 */ 1256 if (tty->rawOutBufState == rob_wait) { 1257 /* 1258 * this should never happen... 1259 */ 1260 rtems_semaphore_release (tty->rawOutBuf.Semaphore); 1261 } 1262 return 0; 1263 } 1264 1265 rtems_interrupt_disable(level); 1266 len = tty->t_dqlen; 1267 tty->t_dqlen = 0; 1268 rtems_interrupt_enable(level); 1269 1270 newTail = (tty->rawOutBuf.Tail + len) % tty->rawOutBuf.Size; 1271 tty->rawOutBuf.Tail = newTail; 1272 if (tty->rawOutBufState == rob_wait) { 1273 /* 1274 * wake up any pending writer task 1275 */ 1276 rtems_semaphore_release (tty->rawOutBuf.Semaphore); 1277 } 1278 if (newTail == tty->rawOutBuf.Head) { 1279 /* 1280 * Buffer has become empty 1281 */ 1282 tty->rawOutBufState = rob_idle; 1283 nToSend = 0; 1284 } 1285 /* check, whether output should stop due to received XOFF */ 1286 else if ((tty->flow_ctrl & (FL_MDXON | FL_ORCVXOF)) 1287 == (FL_MDXON | FL_ORCVXOF)) { 1288 /* Buffer not empty, but output stops due to XOFF */ 1289 /* set flag, that output has been stopped */ 1290 rtems_interrupt_disable(level); 1291 tty->flow_ctrl |= FL_OSTOP; 1292 tty->rawOutBufState = rob_busy; /*apm*/ 1293 rtems_interrupt_enable(level); 1294 nToSend = 0; 1295 } 1296 else { 1297 /* 1298 * Buffer not empty, start tranmitter 1299 */ 1300 if (newTail > tty->rawOutBuf.Head) 1301 nToSend = tty->rawOutBuf.Size - newTail; 1302 else 1303 nToSend = tty->rawOutBuf.Head - newTail; 1304 /* when flow control XON or XOF, don't send blocks of data */ 1305 /* to allow fast reaction on incoming flow ctrl and low latency*/ 1306 /* for outgoing flow control */ 1307 if (tty->flow_ctrl & (FL_MDXON | FL_MDXOF)) { 1308 nToSend = 1; 1309 } 1310 tty->rawOutBufState = rob_busy; /*apm*/ 1311 (*tty->device.write)(tty->minor, 1312 (char *)&tty->rawOutBuf.theBuf[newTail], 1313 nToSend); 1314 } 1315 tty->rawOutBuf.Tail = newTail; /*apm*/ 1316 } 1317 return nToSend; 1065 1318 } 1066 1319 … … 1078 1331 { 1079 1332 struct rtems_termios_tty *tty = ttyp; 1080 unsigned int newTail; 1081 int nToSend; 1082 1083 /* check for XOF/XON to send */ 1084 if ((tty->flow_ctrl & (FL_MDXOF | FL_IREQXOF | FL_ISNTXOF)) 1085 == (FL_MDXOF | FL_IREQXOF)) { 1086 /* XOFF should be sent now... */ 1087 (*tty->device.write)(tty->minor, 1088 &(tty->termios.c_cc[VSTOP]), 1); 1089 tty->flow_ctrl |= FL_ISNTXOF; 1090 nToSend = 1; 1091 } 1092 else if ((tty->flow_ctrl & (FL_IREQXOF | FL_ISNTXOF)) 1093 == FL_ISNTXOF) { 1094 /* NOTE: send XON even, if no longer in XON/XOFF mode... */ 1095 /* XON should be sent now... */ 1096 (*tty->device.write)(tty->minor, 1097 &(tty->termios.c_cc[VSTART]), 1); 1098 tty->flow_ctrl &= ~FL_ISNTXOF; 1099 nToSend = 1; 1333 rtems_status_code sc; 1334 1335 /* 1336 * sum up character count already sent 1337 */ 1338 tty->t_dqlen += len; 1339 1340 if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) { 1341 /* 1342 * send wake up to transmitter task 1343 */ 1344 sc = rtems_event_send(tty->txTaskId, 1345 TERMIOS_TX_START_EVENT); 1346 if (sc != RTEMS_SUCCESSFUL) 1347 rtems_fatal_error_occurred (sc); 1348 return 0; /* nothing to output in IRQ... */ 1100 1349 } 1101 1350 else { 1102 if (tty->rawOutBufState == rob_wait) 1103 rtems_semaphore_release (tty->rawOutBufSemaphore); 1104 if ( tty->rawOutBufHead == tty->rawOutBufTail ) { 1105 tty->rawOutBufState = rob_idle; 1106 return 0; 1107 } 1108 newTail = (tty->rawOutBufTail + len) % RAW_OUTPUT_BUFFER_SIZE; 1109 if (newTail == tty->rawOutBufHead) { 1110 /* 1111 * Buffer empty 1112 */ 1113 tty->rawOutBufState = rob_idle; 1114 nToSend = 0; 1115 } 1116 /* check, whether output should stop due to received XOFF */ 1117 else if ((tty->flow_ctrl & (FL_MDXON | FL_ORCVXOF)) 1118 == (FL_MDXON | FL_ORCVXOF)) { 1119 /* Buffer not empty, but output stops due to XOFF */ 1120 /* set flag, that output has been stopped */ 1121 tty->flow_ctrl |= FL_OSTOP; 1122 tty->rawOutBufState = rob_busy; 1123 nToSend = 0; 1124 } 1125 else { 1126 /* 1127 * Buffer not empty, start tranmitter 1128 */ 1129 if (newTail > tty->rawOutBufHead) 1130 nToSend = RAW_OUTPUT_BUFFER_SIZE - newTail; 1131 else 1132 nToSend = tty->rawOutBufHead - newTail; 1133 /* when flow control XON or XOF, don't send blocks of data */ 1134 /* to allow fast reaction on incoming flow ctrl and low latency*/ 1135 /* for outgoing flow control */ 1136 if (tty->flow_ctrl & (FL_MDXON | FL_MDXOF)) 1137 nToSend = 1; 1138 tty->rawOutBufState = rob_busy; 1139 (*tty->device.write)(tty->minor, (char *)&tty->rawOutBuf[newTail], nToSend); 1140 } 1141 tty->rawOutBufTail = newTail; 1142 } 1143 return nToSend; 1144 } 1351 return rtems_termios_refill_transmitter(tty); 1352 } 1353 } 1354 1355 /* 1356 * this task actually processes any transmit events 1357 */ 1358 static rtems_task rtems_termios_txdaemon(rtems_task_argument argument) 1359 { 1360 struct rtems_termios_tty *tty = (struct rtems_termios_tty *)argument; 1361 rtems_event_set the_event; 1362 1363 while (1) { 1364 /* 1365 * wait for rtems event 1366 */ 1367 rtems_event_receive((TERMIOS_TX_START_EVENT | 1368 TERMIOS_TX_TERMINATE_EVENT), 1369 RTEMS_EVENT_ANY | RTEMS_WAIT, 1370 RTEMS_NO_TIMEOUT, 1371 &the_event); 1372 if ((the_event & TERMIOS_TX_TERMINATE_EVENT) != 0) { 1373 tty->txTaskId = 0; 1374 rtems_task_delete(RTEMS_SELF); 1375 } 1376 else { 1377 /* 1378 * call any line discipline start function 1379 */ 1380 if (linesw[tty->t_line].l_start != NULL) { 1381 linesw[tty->t_line].l_start(tty); 1382 } 1383 /* 1384 * try to push further characters to device 1385 */ 1386 rtems_termios_refill_transmitter(tty); 1387 } 1388 } 1389 } 1390 1391 /* 1392 * this task actually processes any receive events 1393 */ 1394 static rtems_task rtems_termios_rxdaemon(rtems_task_argument argument) 1395 { 1396 struct rtems_termios_tty *tty = (struct rtems_termios_tty *)argument; 1397 rtems_event_set the_event; 1398 int c; 1399 char c_buf; 1400 while (1) { 1401 /* 1402 * wait for rtems event 1403 */ 1404 rtems_event_receive((TERMIOS_RX_PROC_EVENT | 1405 TERMIOS_RX_TERMINATE_EVENT), 1406 RTEMS_EVENT_ANY | RTEMS_WAIT, 1407 RTEMS_NO_TIMEOUT, 1408 &the_event); 1409 if ((the_event & TERMIOS_RX_TERMINATE_EVENT) != 0) { 1410 tty->rxTaskId = 0; 1411 rtems_task_delete(RTEMS_SELF); 1412 } 1413 else { 1414 /* 1415 * do something 1416 */ 1417 c = tty->device.pollRead(tty->minor); 1418 if (c != EOF) { 1419 /* 1420 * pollRead did call enqueue on its own 1421 */ 1422 c_buf = c; 1423 rtems_termios_enqueue_raw_characters ( 1424 tty,&c_buf,1); 1425 } 1426 } 1427 } 1428 } -
cpukit/libcsupport/src/termios.c
rc8471315 re2af631 24 24 #include <termios.h> 25 25 #include <unistd.h> 26 #include <sys/ttycom.h> 27 28 #include "termiostypes.h" 26 29 27 30 /* … … 61 64 #define RAW_OUTPUT_BUFFER_SIZE 64 62 65 63 /*64 * Variables associated with each termios instance.65 * One structure for each hardware I/O device.66 */67 struct rtems_termios_tty {68 /*69 * Linked-list of active TERMIOS devices70 */71 struct rtems_termios_tty *forw;72 struct rtems_termios_tty *back;73 74 /*75 * How many times has this device been opened76 */77 int refcount;78 79 /*80 * This device81 */82 rtems_device_major_number major;83 rtems_device_major_number minor;84 85 /*86 * Mutual-exclusion semaphores87 */88 rtems_id isem;89 rtems_id osem;90 91 /*92 * The canonical (cooked) character buffer93 */94 char cbuf[CBUFSIZE];95 int ccount;96 int cindex;97 98 /*99 * Keep track of cursor (printhead) position100 */101 int column;102 int read_start_column;103 104 /*105 * The ioctl settings106 */107 struct termios termios;108 rtems_interval vtimeTicks;109 110 /*111 * Raw input character buffer112 */113 volatile char rawInBuf[RAW_INPUT_BUFFER_SIZE];114 volatile unsigned int rawInBufHead;115 volatile unsigned int rawInBufTail;116 rtems_id rawInBufSemaphore;117 rtems_unsigned32 rawInBufSemaphoreOptions;118 rtems_interval rawInBufSemaphoreTimeout;119 rtems_interval rawInBufSemaphoreFirstTimeout;120 unsigned int rawInBufDropped; /* Statistics */121 122 /*123 * Raw output character buffer124 */125 volatile char rawOutBuf[RAW_OUTPUT_BUFFER_SIZE];126 volatile unsigned int rawOutBufHead;127 volatile unsigned int rawOutBufTail;128 rtems_id rawOutBufSemaphore;129 volatile enum {rob_idle, rob_busy, rob_wait } rawOutBufState;130 131 /*132 * Callbacks to device-specific routines133 */134 rtems_termios_callbacks device;135 volatile unsigned int flow_ctrl;136 unsigned int lowwater,highwater;137 };138 139 66 /* fields for "flow_ctrl" status */ 140 67 #define FL_IREQXOF 1 /* input queue requests stop of incoming data */ … … 149 76 #define FL_MDXOF 0x400 /* output controlled with XON/XOFF protocol */ 150 77 78 #define NODISC(n) \ 79 { NULL, NULL, NULL, NULL, \ 80 NULL, NULL, NULL, NULL } 81 /* 82 * FIXME: change linesw entries consistant with linesw entry usage... 83 */ 84 struct linesw linesw[MAXLDISC] = 85 { 86 NODISC(0), /* 0- termios-built-in */ 87 NODISC(1), /* 1- defunct */ 88 NODISC(2), /* 2- NTTYDISC */ 89 NODISC(3), /* TABLDISC */ 90 NODISC(4), /* SLIPDISC */ 91 NODISC(5), /* PPPDISC */ 92 NODISC(6), /* loadable */ 93 NODISC(7), /* loadable */ 94 }; 95 96 int nlinesw = sizeof (linesw) / sizeof (linesw[0]); 97 151 98 extern struct rtems_termios_tty *rtems_termios_ttyHead; 152 99 extern struct rtems_termios_tty *rtems_termios_ttyTail; 153 100 extern rtems_id rtems_termios_ttyMutex; 101 102 static rtems_task rtems_termios_rxdaemon(rtems_task_argument argument); 103 static rtems_task rtems_termios_txdaemon(rtems_task_argument argument); 104 /* 105 * some constants for I/O daemon task creation 106 */ 107 #define TERMIOS_TXTASK_PRIO 10 108 #define TERMIOS_RXTASK_PRIO 9 109 #define TERMIOS_TXTASK_STACKSIZE 1024 110 #define TERMIOS_RXTASK_STACKSIZE 1024 111 /* 112 * some events to be sent to the I/O tasks 113 */ 114 #define TERMIOS_TX_START_EVENT RTEMS_EVENT_1 115 #define TERMIOS_TX_TERMINATE_EVENT RTEMS_EVENT_0 116 117 #define TERMIOS_RX_PROC_EVENT RTEMS_EVENT_1 118 #define TERMIOS_RX_TERMINATE_EVENT RTEMS_EVENT_0 154 119 155 120 /* … … 171 136 * See if the device has already been opened 172 137 */ 173 sc = rtems_semaphore_obtain (rtems_termios_ttyMutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT); 138 sc = rtems_semaphore_obtain (rtems_termios_ttyMutex, 139 RTEMS_WAIT, RTEMS_NO_TIMEOUT); 174 140 if (sc != RTEMS_SUCCESSFUL) 175 141 return sc; … … 189 155 return RTEMS_NO_MEMORY; 190 156 } 157 /* 158 * allocate raw input buffer 159 */ 160 tty->rawInBuf.Size = RAW_INPUT_BUFFER_SIZE; 161 tty->rawInBuf.theBuf = malloc (tty->rawInBuf.Size); 162 if (tty->rawInBuf.theBuf == NULL) { 163 free(tty); 164 rtems_semaphore_release (rtems_termios_ttyMutex); 165 return RTEMS_NO_MEMORY; 166 } 167 /* 168 * allocate raw output buffer 169 */ 170 tty->rawOutBuf.Size = RAW_OUTPUT_BUFFER_SIZE; 171 tty->rawOutBuf.theBuf = malloc (tty->rawOutBuf.Size); 172 if (tty->rawInBuf.theBuf == NULL) { 173 free((void *)(tty->rawInBuf.theBuf)); 174 free(tty); 175 rtems_semaphore_release (rtems_termios_ttyMutex); 176 return RTEMS_NO_MEMORY; 177 } 178 /* 179 * allocate cooked buffer 180 */ 181 tty->cbuf = malloc (CBUFSIZE); 182 if (tty->cbuf == NULL) { 183 free((void *)(tty->rawOutBuf.theBuf)); 184 free((void *)(tty->rawInBuf.theBuf)); 185 free(tty); 186 rtems_semaphore_release (rtems_termios_ttyMutex); 187 return RTEMS_NO_MEMORY; 188 } 189 /* 190 * link tty 191 */ 191 192 if (rtems_termios_ttyHead) 192 193 rtems_termios_ttyHead->back = tty; … … 222 223 RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_FIFO, 223 224 RTEMS_NO_PRIORITY, 224 &tty->rawOutBuf Semaphore);225 &tty->rawOutBuf.Semaphore); 225 226 if (sc != RTEMS_SUCCESSFUL) 226 227 rtems_fatal_error_occurred (sc); … … 231 232 */ 232 233 tty->device = *callbacks; 233 if (!tty->device.pollRead) { 234 235 /* 236 * Create I/O tasks 237 */ 238 if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) { 239 sc = rtems_task_create ( 240 rtems_build_name ('T', 'x', 'T', c), 241 TERMIOS_TXTASK_PRIO, 242 TERMIOS_TXTASK_STACKSIZE, 243 RTEMS_NO_PREEMPT | RTEMS_NO_TIMESLICE | 244 RTEMS_NO_ASR, 245 RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL, 246 &tty->txTaskId); 247 if (sc != RTEMS_SUCCESSFUL) 248 rtems_fatal_error_occurred (sc); 249 sc = rtems_task_create ( 250 rtems_build_name ('R', 'x', 'T', c), 251 TERMIOS_RXTASK_PRIO, 252 TERMIOS_RXTASK_STACKSIZE, 253 RTEMS_NO_PREEMPT | RTEMS_NO_TIMESLICE | 254 RTEMS_NO_ASR, 255 RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL, 256 &tty->rxTaskId); 257 if (sc != RTEMS_SUCCESSFUL) 258 rtems_fatal_error_occurred (sc); 259 260 } 261 if ((tty->device.pollRead == NULL) || 262 (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN)){ 234 263 sc = rtems_semaphore_create ( 235 264 rtems_build_name ('T', 'R', 'r', c), … … 237 266 RTEMS_COUNTING_SEMAPHORE | RTEMS_PRIORITY, 238 267 RTEMS_NO_PRIORITY, 239 &tty->rawInBuf Semaphore);268 &tty->rawInBuf.Semaphore); 240 269 if (sc != RTEMS_SUCCESSFUL) 241 270 rtems_fatal_error_occurred (sc); … … 270 299 * set low/highwater mark for XON/XOFF support 271 300 */ 272 tty->lowwater = RAW_INPUT_BUFFER_SIZE* 1/2;273 tty->highwater = RAW_INPUT_BUFFER_SIZE* 3/4;301 tty->lowwater = tty->rawInBuf.Size * 1/2; 302 tty->highwater = tty->rawInBuf.Size * 3/4; 274 303 /* 275 304 * Bump name characer … … 280 309 } 281 310 args->iop->data1 = tty; 282 if (!tty->refcount++ && tty->device.firstOpen) 311 if (!tty->refcount++) { 312 if (tty->device.firstOpen) 283 313 (*tty->device.firstOpen)(major, minor, arg); 314 /* 315 * start I/O tasks, if needed 316 */ 317 if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) { 318 sc = rtems_task_start(tty->rxTaskId, 319 rtems_termios_rxdaemon, 320 (rtems_task_argument)tty); 321 if (sc != RTEMS_SUCCESSFUL) 322 rtems_fatal_error_occurred (sc); 323 324 sc = rtems_task_start(tty->txTaskId, 325 rtems_termios_txdaemon, 326 (rtems_task_argument)tty); 327 if (sc != RTEMS_SUCCESSFUL) 328 rtems_fatal_error_occurred (sc); 329 } 330 } 284 331 rtems_semaphore_release (rtems_termios_ttyMutex); 285 332 return RTEMS_SUCCESSFUL; … … 295 342 rtems_status_code sc; 296 343 297 if (tty->device.outputUsesInterrupts ) {344 if (tty->device.outputUsesInterrupts != TERMIOS_POLLED) { 298 345 rtems_interrupt_disable (level); 299 while (tty->rawOutBuf Tail != tty->rawOutBufHead) {346 while (tty->rawOutBuf.Tail != tty->rawOutBuf.Head) { 300 347 tty->rawOutBufState = rob_wait; 301 348 rtems_interrupt_enable (level); 302 sc = rtems_semaphore_obtain (tty->rawOutBuf Semaphore,349 sc = rtems_semaphore_obtain (tty->rawOutBuf.Semaphore, 303 350 RTEMS_WAIT, 304 351 RTEMS_NO_TIMEOUT); … … 322 369 rtems_fatal_error_occurred (sc); 323 370 if (--tty->refcount == 0) { 324 drainOutput (tty); 371 if (linesw[tty->t_line].l_close != NULL) { 372 /* 373 * call discipline-specific close 374 */ 375 sc = linesw[tty->t_line].l_close(tty); 376 } 377 else { 378 /* 379 * default: just flush output buffer 380 */ 381 drainOutput (tty); 382 } 383 384 if (tty->device.outputUsesInterrupts 385 == TERMIOS_TASK_DRIVEN) { 386 /* 387 * send "terminate" to I/O tasks 388 */ 389 sc = rtems_event_send( 390 tty->rxTaskId, 391 TERMIOS_RX_TERMINATE_EVENT); 392 if (sc != RTEMS_SUCCESSFUL) 393 rtems_fatal_error_occurred (sc); 394 sc = rtems_event_send( 395 tty->txTaskId, 396 TERMIOS_TX_TERMINATE_EVENT); 397 if (sc != RTEMS_SUCCESSFUL) 398 rtems_fatal_error_occurred (sc); 399 } 325 400 if (tty->device.lastClose) 326 401 (*tty->device.lastClose)(tty->major, tty->minor, arg); … … 335 410 rtems_semaphore_delete (tty->isem); 336 411 rtems_semaphore_delete (tty->osem); 337 rtems_semaphore_delete (tty->rawOutBufSemaphore); 338 if (!tty->device.pollRead) 339 rtems_semaphore_delete (tty->rawInBufSemaphore); 412 rtems_semaphore_delete (tty->rawOutBuf.Semaphore); 413 if ((tty->device.pollRead == NULL) || 414 (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN)) 415 rtems_semaphore_delete (tty->rawInBuf.Semaphore); 340 416 free (tty); 341 417 } … … 367 443 /* if chars available, call write function... */ 368 444 (*tty->device.write)(tty->minor, 369 (char *)&tty->rawOutBuf[tty->rawOutBufTail],1);445 (char *)&tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail],1); 370 446 } 371 447 /* reenable interrupts */ … … 428 504 switch (args->command) { 429 505 default: 430 sc = RTEMS_INVALID_NUMBER; 506 if (linesw[tty->t_line].l_ioctl != NULL) { 507 sc = linesw[tty->t_line].l_ioctl(tty,args); 508 } 509 else { 510 sc = RTEMS_INVALID_NUMBER; 511 } 431 512 break; 432 513 … … 477 558 break; 478 559 560 /* 561 * FIXME: add various ioctl code handlers 562 */ 563 564 #if 1 /* FIXME */ 565 case TIOCSETD: 566 /* 567 * close old line discipline 568 */ 569 if (linesw[tty->t_line].l_close != NULL) { 570 sc = linesw[tty->t_line].l_close(tty); 571 } 572 tty->t_line=*(int*)(args->buffer); 573 tty->t_sc = NULL; /* ensure that no more valid data */ 574 /* 575 * open new line discipline 576 */ 577 if (linesw[tty->t_line].l_open != NULL) { 578 sc = linesw[tty->t_line].l_open(tty); 579 } 580 break; 581 case TIOCGETD: 582 *(int*)(args->buffer)=tty->t_line; 583 break; 584 #endif 479 585 case FIONREAD: 480 586 /* Half guess that this is the right operation */ … … 490 596 * Send characters to device-specific code 491 597 */ 492 staticvoid493 osend(const char *buf, int len, struct rtems_termios_tty *tty)598 void 599 rtems_termios_puts (const char *buf, int len, struct rtems_termios_tty *tty) 494 600 { 495 601 unsigned int newHead; … … 497 603 rtems_status_code sc; 498 604 499 if ( !tty->device.outputUsesInterrupts) {605 if (tty->device.outputUsesInterrupts == TERMIOS_POLLED) { 500 606 (*tty->device.write)(tty->minor, buf, len); 501 607 return; 502 608 } 503 newHead = tty->rawOutBuf Head;609 newHead = tty->rawOutBuf.Head; 504 610 while (len) { 505 611 /* … … 515 621 * with interrupts enabled. 516 622 */ 517 newHead = (newHead + 1) % RAW_OUTPUT_BUFFER_SIZE;623 newHead = (newHead + 1) % tty->rawOutBuf.Size; 518 624 rtems_interrupt_disable (level); 519 while (newHead == tty->rawOutBuf Tail) {625 while (newHead == tty->rawOutBuf.Tail) { 520 626 tty->rawOutBufState = rob_wait; 521 627 rtems_interrupt_enable (level); 522 sc = rtems_semaphore_obtain (tty->rawOutBuf Semaphore,628 sc = rtems_semaphore_obtain (tty->rawOutBuf.Semaphore, 523 629 RTEMS_WAIT, 524 630 RTEMS_NO_TIMEOUT); … … 527 633 rtems_interrupt_disable (level); 528 634 } 529 tty->rawOutBuf [tty->rawOutBufHead] = *buf++;530 tty->rawOutBuf Head = newHead;635 tty->rawOutBuf.theBuf[tty->rawOutBuf.Head] = *buf++; 636 tty->rawOutBuf.Head = newHead; 531 637 if (tty->rawOutBufState == rob_idle) { 532 638 /* check, whether XOFF has been received */ 533 639 if (!(tty->flow_ctrl & FL_ORCVXOF)) { 534 640 (*tty->device.write)(tty->minor, 535 (char *)&tty->rawOutBuf[tty->rawOutBufTail],1);641 (char *)&tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail],1); 536 642 } 537 643 else { … … 560 666 tty->column = 0; 561 667 if (tty->termios.c_oflag & ONLCR) { 562 osend("\r", 1, tty);668 rtems_termios_puts ("\r", 1, tty); 563 669 tty->column = 0; 564 670 } … … 581 687 if ((tty->termios.c_oflag & TABDLY) == XTABS) { 582 688 tty->column += i; 583 osend( " ", i, tty);689 rtems_termios_puts ( " ", i, tty); 584 690 return; 585 691 } … … 600 706 } 601 707 } 602 osend(&c, 1, tty);708 rtems_termios_puts (&c, 1, tty); 603 709 } 604 710 … … 613 719 if (sc != RTEMS_SUCCESSFUL) 614 720 return sc; 721 if (linesw[tty->t_line].l_write != NULL) { 722 sc = linesw[tty->t_line].l_write(tty,args); 723 rtems_semaphore_release (tty->osem); 724 return sc; 725 } 615 726 if (tty->termios.c_oflag & OPOST) { 616 727 unsigned32 count = args->count; … … 621 732 } 622 733 else { 623 osend(args->buffer, args->count, tty);734 rtems_termios_puts (args->buffer, args->count, tty); 624 735 args->bytes_moved = args->count; 625 736 } … … 639 750 echobuf[0] = '^'; 640 751 echobuf[1] = c ^ 0x40; 641 osend(echobuf, 2, tty);752 rtems_termios_puts (echobuf, 2, tty); 642 753 tty->column += 2; 643 754 } … … 702 813 */ 703 814 while (tty->column > col) { 704 osend("\b", 1, tty);815 rtems_termios_puts ("\b", 1, tty); 705 816 tty->column--; 706 817 } … … 708 819 else { 709 820 if (iscntrl (c) && (tty->termios.c_lflag & ECHOCTL)) { 710 osend("\b \b", 3, tty);821 rtems_termios_puts ("\b \b", 3, tty); 711 822 if (tty->column) 712 823 tty->column--; 713 824 } 714 825 if (!iscntrl (c) || (tty->termios.c_lflag & ECHOCTL)) { 715 osend("\b \b", 3, tty);826 rtems_termios_puts ("\b \b", 3, tty); 716 827 if (tty->column) 717 828 tty->column--; … … 873 984 * Process characters read from raw queue 874 985 */ 875 while (tty->rawInBuf Head != tty->rawInBufTail) {986 while (tty->rawInBuf.Head != tty->rawInBuf.Tail) { 876 987 unsigned char c; 877 988 unsigned int newHead; 878 989 879 newHead = (tty->rawInBuf Head + 1) % RAW_INPUT_BUFFER_SIZE;880 c = tty->rawInBuf [newHead];881 tty->rawInBuf Head = newHead;882 if(((tty->rawInBuf Tail-newHead+RAW_INPUT_BUFFER_SIZE)883 % RAW_INPUT_BUFFER_SIZE)990 newHead = (tty->rawInBuf.Head + 1) % tty->rawInBuf.Size; 991 c = tty->rawInBuf.theBuf[newHead]; 992 tty->rawInBuf.Head = newHead; 993 if(((tty->rawInBuf.Tail-newHead+tty->rawInBuf.Size) 994 % tty->rawInBuf.Size) 884 995 < tty->lowwater) { 885 996 tty->flow_ctrl &= ~FL_IREQXOF; … … 919 1030 * Wait for characters 920 1031 */ 921 sc = rtems_semaphore_obtain (tty->rawInBuf Semaphore,1032 sc = rtems_semaphore_obtain (tty->rawInBuf.Semaphore, 922 1033 tty->rawInBufSemaphoreOptions, 923 1034 timeout); … … 940 1051 if (sc != RTEMS_SUCCESSFUL) 941 1052 return sc; 1053 if (linesw[tty->t_line].l_read != NULL) { 1054 sc = linesw[tty->t_line].l_read(tty,args); 1055 rtems_semaphore_release (tty->isem); 1056 return sc; 1057 } 942 1058 if (tty->cindex == tty->ccount) { 943 1059 tty->cindex = tty->ccount = 0; 944 1060 tty->read_start_column = tty->column; 945 if (tty->device.pollRead) 1061 if (tty->device.pollRead != NULL 1062 && tty->device.outputUsesInterrupts == TERMIOS_POLLED) 946 1063 sc = fillBufferPoll (tty); 947 1064 else … … 957 1074 rtems_semaphore_release (tty->isem); 958 1075 return sc; 1076 } 1077 1078 /* 1079 * signal receive interrupt to rx daemon 1080 * NOTE: This routine runs in the context of the 1081 * device receive interrupt handler. 1082 */ 1083 void rtems_termios_rxirq_occured(struct rtems_termios_tty *tty) 1084 { 1085 /* 1086 * send event to rx daemon task 1087 */ 1088 rtems_event_send(tty->rxTaskId,TERMIOS_RX_PROC_EVENT); 959 1089 } 960 1090 … … 974 1104 boolean flow_rcv = FALSE; /* TRUE, if flow control char received */ 975 1105 rtems_interrupt_level level; 1106 1107 if (linesw[tty->t_line].l_rint != NULL) { 1108 while (len--) { 1109 c = *buf++; 1110 linesw[tty->t_line].l_rint(c,tty); 1111 } 1112 return 0; 1113 } 976 1114 977 1115 while (len--) { … … 1011 1149 /* if chars available, call write function... */ 1012 1150 (*tty->device.write)(tty->minor, 1013 (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1);1151 (char *)&tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail], 1); 1014 1152 } 1015 1153 /* reenable interrupts */ … … 1018 1156 } 1019 1157 else { 1020 newTail = (tty->rawInBuf Tail + 1) % RAW_INPUT_BUFFER_SIZE;1158 newTail = (tty->rawInBuf.Tail + 1) % tty->rawInBuf.Size; 1021 1159 /* if chars_in_buffer > highwater */ 1022 1160 rtems_interrupt_disable(level); 1023 if ((((newTail - tty->rawInBuf Head + RAW_INPUT_BUFFER_SIZE)1024 % RAW_INPUT_BUFFER_SIZE)1161 if ((((newTail - tty->rawInBuf.Head + tty->rawInBuf.Size) 1162 % tty->rawInBuf.Size) 1025 1163 > tty->highwater) && 1026 1164 !(tty->flow_ctrl & FL_IREQXOF)) { … … 1051 1189 rtems_interrupt_enable(level); 1052 1190 1053 if (newTail == tty->rawInBuf Head) {1191 if (newTail == tty->rawInBuf.Head) { 1054 1192 dropped++; 1055 1193 } 1056 1194 else { 1057 tty->rawInBuf [newTail] = c;1058 tty->rawInBuf Tail = newTail;1195 tty->rawInBuf.theBuf[newTail] = c; 1196 tty->rawInBuf.Tail = newTail; 1059 1197 } 1060 1198 } 1061 1199 } 1062 1200 tty->rawInBufDropped += dropped; 1063 rtems_semaphore_release (tty->rawInBuf Semaphore);1201 rtems_semaphore_release (tty->rawInBuf.Semaphore); 1064 1202 return dropped; 1203 } 1204 1205 /* 1206 * in task-driven mode, this function is called in Tx task context 1207 * in interrupt-driven mode, this function is called in TxIRQ context 1208 */ 1209 int 1210 rtems_termios_refill_transmitter (struct rtems_termios_tty *tty) 1211 { 1212 unsigned int newTail; 1213 int nToSend; 1214 rtems_interrupt_level level; 1215 int len; 1216 1217 /* check for XOF/XON to send */ 1218 if ((tty->flow_ctrl & (FL_MDXOF | FL_IREQXOF | FL_ISNTXOF)) 1219 == (FL_MDXOF | FL_IREQXOF)) { 1220 /* XOFF should be sent now... */ 1221 (*tty->device.write)(tty->minor, 1222 &(tty->termios.c_cc[VSTOP]), 1); 1223 1224 rtems_interrupt_disable(level); 1225 tty->t_dqlen--; 1226 tty->flow_ctrl |= FL_ISNTXOF; 1227 rtems_interrupt_enable(level); 1228 1229 nToSend = 1; 1230 } 1231 else if ((tty->flow_ctrl & (FL_IREQXOF | FL_ISNTXOF)) 1232 == FL_ISNTXOF) { 1233 /* NOTE: send XON even, if no longer in XON/XOFF mode... */ 1234 /* XON should be sent now... */ 1235 /* 1236 * FIXME: this .write call will generate another 1237 * dequeue callback. This will advance the "Tail" in the data 1238 * buffer, although the corresponding data is not yet out! 1239 * Therefore the dequeue "length" should be reduced by 1 1240 */ 1241 (*tty->device.write)(tty->minor, 1242 &(tty->termios.c_cc[VSTART]), 1); 1243 1244 rtems_interrupt_disable(level); 1245 tty->t_dqlen--; 1246 tty->flow_ctrl &= ~FL_ISNTXOF; 1247 rtems_interrupt_enable(level); 1248 1249 nToSend = 1; 1250 } 1251 else { 1252 if ( tty->rawOutBuf.Head == tty->rawOutBuf.Tail ) { 1253 /* 1254 * buffer was empty 1255 */ 1256 if (tty->rawOutBufState == rob_wait) { 1257 /* 1258 * this should never happen... 1259 */ 1260 rtems_semaphore_release (tty->rawOutBuf.Semaphore); 1261 } 1262 return 0; 1263 } 1264 1265 rtems_interrupt_disable(level); 1266 len = tty->t_dqlen; 1267 tty->t_dqlen = 0; 1268 rtems_interrupt_enable(level); 1269 1270 newTail = (tty->rawOutBuf.Tail + len) % tty->rawOutBuf.Size; 1271 tty->rawOutBuf.Tail = newTail; 1272 if (tty->rawOutBufState == rob_wait) { 1273 /* 1274 * wake up any pending writer task 1275 */ 1276 rtems_semaphore_release (tty->rawOutBuf.Semaphore); 1277 } 1278 if (newTail == tty->rawOutBuf.Head) { 1279 /* 1280 * Buffer has become empty 1281 */ 1282 tty->rawOutBufState = rob_idle; 1283 nToSend = 0; 1284 } 1285 /* check, whether output should stop due to received XOFF */ 1286 else if ((tty->flow_ctrl & (FL_MDXON | FL_ORCVXOF)) 1287 == (FL_MDXON | FL_ORCVXOF)) { 1288 /* Buffer not empty, but output stops due to XOFF */ 1289 /* set flag, that output has been stopped */ 1290 rtems_interrupt_disable(level); 1291 tty->flow_ctrl |= FL_OSTOP; 1292 tty->rawOutBufState = rob_busy; /*apm*/ 1293 rtems_interrupt_enable(level); 1294 nToSend = 0; 1295 } 1296 else { 1297 /* 1298 * Buffer not empty, start tranmitter 1299 */ 1300 if (newTail > tty->rawOutBuf.Head) 1301 nToSend = tty->rawOutBuf.Size - newTail; 1302 else 1303 nToSend = tty->rawOutBuf.Head - newTail; 1304 /* when flow control XON or XOF, don't send blocks of data */ 1305 /* to allow fast reaction on incoming flow ctrl and low latency*/ 1306 /* for outgoing flow control */ 1307 if (tty->flow_ctrl & (FL_MDXON | FL_MDXOF)) { 1308 nToSend = 1; 1309 } 1310 tty->rawOutBufState = rob_busy; /*apm*/ 1311 (*tty->device.write)(tty->minor, 1312 (char *)&tty->rawOutBuf.theBuf[newTail], 1313 nToSend); 1314 } 1315 tty->rawOutBuf.Tail = newTail; /*apm*/ 1316 } 1317 return nToSend; 1065 1318 } 1066 1319 … … 1078 1331 { 1079 1332 struct rtems_termios_tty *tty = ttyp; 1080 unsigned int newTail; 1081 int nToSend; 1082 1083 /* check for XOF/XON to send */ 1084 if ((tty->flow_ctrl & (FL_MDXOF | FL_IREQXOF | FL_ISNTXOF)) 1085 == (FL_MDXOF | FL_IREQXOF)) { 1086 /* XOFF should be sent now... */ 1087 (*tty->device.write)(tty->minor, 1088 &(tty->termios.c_cc[VSTOP]), 1); 1089 tty->flow_ctrl |= FL_ISNTXOF; 1090 nToSend = 1; 1091 } 1092 else if ((tty->flow_ctrl & (FL_IREQXOF | FL_ISNTXOF)) 1093 == FL_ISNTXOF) { 1094 /* NOTE: send XON even, if no longer in XON/XOFF mode... */ 1095 /* XON should be sent now... */ 1096 (*tty->device.write)(tty->minor, 1097 &(tty->termios.c_cc[VSTART]), 1); 1098 tty->flow_ctrl &= ~FL_ISNTXOF; 1099 nToSend = 1; 1333 rtems_status_code sc; 1334 1335 /* 1336 * sum up character count already sent 1337 */ 1338 tty->t_dqlen += len; 1339 1340 if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) { 1341 /* 1342 * send wake up to transmitter task 1343 */ 1344 sc = rtems_event_send(tty->txTaskId, 1345 TERMIOS_TX_START_EVENT); 1346 if (sc != RTEMS_SUCCESSFUL) 1347 rtems_fatal_error_occurred (sc); 1348 return 0; /* nothing to output in IRQ... */ 1100 1349 } 1101 1350 else { 1102 if (tty->rawOutBufState == rob_wait) 1103 rtems_semaphore_release (tty->rawOutBufSemaphore); 1104 if ( tty->rawOutBufHead == tty->rawOutBufTail ) { 1105 tty->rawOutBufState = rob_idle; 1106 return 0; 1107 } 1108 newTail = (tty->rawOutBufTail + len) % RAW_OUTPUT_BUFFER_SIZE; 1109 if (newTail == tty->rawOutBufHead) { 1110 /* 1111 * Buffer empty 1112 */ 1113 tty->rawOutBufState = rob_idle; 1114 nToSend = 0; 1115 } 1116 /* check, whether output should stop due to received XOFF */ 1117 else if ((tty->flow_ctrl & (FL_MDXON | FL_ORCVXOF)) 1118 == (FL_MDXON | FL_ORCVXOF)) { 1119 /* Buffer not empty, but output stops due to XOFF */ 1120 /* set flag, that output has been stopped */ 1121 tty->flow_ctrl |= FL_OSTOP; 1122 tty->rawOutBufState = rob_busy; 1123 nToSend = 0; 1124 } 1125 else { 1126 /* 1127 * Buffer not empty, start tranmitter 1128 */ 1129 if (newTail > tty->rawOutBufHead) 1130 nToSend = RAW_OUTPUT_BUFFER_SIZE - newTail; 1131 else 1132 nToSend = tty->rawOutBufHead - newTail; 1133 /* when flow control XON or XOF, don't send blocks of data */ 1134 /* to allow fast reaction on incoming flow ctrl and low latency*/ 1135 /* for outgoing flow control */ 1136 if (tty->flow_ctrl & (FL_MDXON | FL_MDXOF)) 1137 nToSend = 1; 1138 tty->rawOutBufState = rob_busy; 1139 (*tty->device.write)(tty->minor, (char *)&tty->rawOutBuf[newTail], nToSend); 1140 } 1141 tty->rawOutBufTail = newTail; 1142 } 1143 return nToSend; 1144 } 1351 return rtems_termios_refill_transmitter(tty); 1352 } 1353 } 1354 1355 /* 1356 * this task actually processes any transmit events 1357 */ 1358 static rtems_task rtems_termios_txdaemon(rtems_task_argument argument) 1359 { 1360 struct rtems_termios_tty *tty = (struct rtems_termios_tty *)argument; 1361 rtems_event_set the_event; 1362 1363 while (1) { 1364 /* 1365 * wait for rtems event 1366 */ 1367 rtems_event_receive((TERMIOS_TX_START_EVENT | 1368 TERMIOS_TX_TERMINATE_EVENT), 1369 RTEMS_EVENT_ANY | RTEMS_WAIT, 1370 RTEMS_NO_TIMEOUT, 1371 &the_event); 1372 if ((the_event & TERMIOS_TX_TERMINATE_EVENT) != 0) { 1373 tty->txTaskId = 0; 1374 rtems_task_delete(RTEMS_SELF); 1375 } 1376 else { 1377 /* 1378 * call any line discipline start function 1379 */ 1380 if (linesw[tty->t_line].l_start != NULL) { 1381 linesw[tty->t_line].l_start(tty); 1382 } 1383 /* 1384 * try to push further characters to device 1385 */ 1386 rtems_termios_refill_transmitter(tty); 1387 } 1388 } 1389 } 1390 1391 /* 1392 * this task actually processes any receive events 1393 */ 1394 static rtems_task rtems_termios_rxdaemon(rtems_task_argument argument) 1395 { 1396 struct rtems_termios_tty *tty = (struct rtems_termios_tty *)argument; 1397 rtems_event_set the_event; 1398 int c; 1399 char c_buf; 1400 while (1) { 1401 /* 1402 * wait for rtems event 1403 */ 1404 rtems_event_receive((TERMIOS_RX_PROC_EVENT | 1405 TERMIOS_RX_TERMINATE_EVENT), 1406 RTEMS_EVENT_ANY | RTEMS_WAIT, 1407 RTEMS_NO_TIMEOUT, 1408 &the_event); 1409 if ((the_event & TERMIOS_RX_TERMINATE_EVENT) != 0) { 1410 tty->rxTaskId = 0; 1411 rtems_task_delete(RTEMS_SELF); 1412 } 1413 else { 1414 /* 1415 * do something 1416 */ 1417 c = tty->device.pollRead(tty->minor); 1418 if (c != EOF) { 1419 /* 1420 * pollRead did call enqueue on its own 1421 */ 1422 c_buf = c; 1423 rtems_termios_enqueue_raw_characters ( 1424 tty,&c_buf,1); 1425 } 1426 } 1427 } 1428 }
Note: See TracChangeset
for help on using the changeset viewer.