[9] | 1 | /* pty.c - pseudo terminal driver Author: Kees J. Bot
|
---|
| 2 | * 30 Dec 1995
|
---|
| 3 | * PTYs can be seen as a bidirectional pipe with TTY
|
---|
| 4 | * input and output processing. For example a simple rlogin session:
|
---|
| 5 | *
|
---|
| 6 | * keyboard -> rlogin -> in.rld -> /dev/ptypX -> /dev/ttypX -> shell
|
---|
| 7 | * shell -> /dev/ttypX -> /dev/ptypX -> in.rld -> rlogin -> screen
|
---|
| 8 | *
|
---|
| 9 | * This file takes care of copying data between the tty/pty device pairs and
|
---|
| 10 | * the open/read/write/close calls on the pty devices. The TTY task takes
|
---|
| 11 | * care of the input and output processing (interrupt, backspace, raw I/O,
|
---|
| 12 | * etc.) using the pty_read() and pty_write() functions as the "keyboard" and
|
---|
| 13 | * "screen" functions of the ttypX devices.
|
---|
| 14 | * Be careful when reading this code, the terms "reading" and "writing" are
|
---|
| 15 | * used both for the tty and the pty end of the pseudo tty. Writes to one
|
---|
| 16 | * end are to be read at the other end and vice-versa.
|
---|
| 17 | */
|
---|
| 18 |
|
---|
| 19 | #include "../drivers.h"
|
---|
| 20 | #include <assert.h>
|
---|
| 21 | #include <termios.h>
|
---|
| 22 | #include <signal.h>
|
---|
| 23 | #include <minix/com.h>
|
---|
| 24 | #include <minix/callnr.h>
|
---|
| 25 | #include <sys/select.h>
|
---|
| 26 | #include "tty.h"
|
---|
| 27 |
|
---|
| 28 | #if NR_PTYS > 0
|
---|
| 29 |
|
---|
| 30 | /* PTY bookkeeping structure, one per pty/tty pair. */
|
---|
| 31 | typedef struct pty {
|
---|
| 32 | tty_t *tty; /* associated TTY structure */
|
---|
| 33 | char state; /* flags: busy, closed, ... */
|
---|
| 34 |
|
---|
| 35 | /* Read call on /dev/ptypX. */
|
---|
| 36 | char rdsendreply; /* send a reply (instead of notify) */
|
---|
| 37 | int rdcaller; /* process making the call (usually FS) */
|
---|
| 38 | int rdproc; /* process that wants to read from the pty */
|
---|
| 39 | vir_bytes rdvir; /* virtual address in readers address space */
|
---|
| 40 | int rdleft; /* # bytes yet to be read */
|
---|
| 41 | int rdcum; /* # bytes written so far */
|
---|
| 42 |
|
---|
| 43 | /* Write call to /dev/ptypX. */
|
---|
| 44 | char wrsendreply; /* send a reply (instead of notify) */
|
---|
| 45 | int wrcaller; /* process making the call (usually FS) */
|
---|
| 46 | int wrproc; /* process that wants to write to the pty */
|
---|
| 47 | vir_bytes wrvir; /* virtual address in writers address space */
|
---|
| 48 | int wrleft; /* # bytes yet to be written */
|
---|
| 49 | int wrcum; /* # bytes written so far */
|
---|
| 50 |
|
---|
| 51 | /* Output buffer. */
|
---|
| 52 | int ocount; /* # characters in the buffer */
|
---|
| 53 | char *ohead, *otail; /* head and tail of the circular buffer */
|
---|
| 54 | char obuf[128]; /* buffer for bytes going to the pty reader */
|
---|
| 55 |
|
---|
| 56 | /* select() data. */
|
---|
| 57 | int select_ops, /* Which operations do we want to know about? */
|
---|
| 58 | select_proc, /* Who wants to know about it? */
|
---|
| 59 | select_ready_ops; /* For callback. */
|
---|
| 60 | } pty_t;
|
---|
| 61 |
|
---|
| 62 | #define PTY_ACTIVE 0x01 /* pty is open/active */
|
---|
| 63 | #define TTY_CLOSED 0x02 /* tty side has closed down */
|
---|
| 64 | #define PTY_CLOSED 0x04 /* pty side has closed down */
|
---|
| 65 |
|
---|
| 66 | PRIVATE pty_t pty_table[NR_PTYS]; /* PTY bookkeeping */
|
---|
| 67 |
|
---|
| 68 | FORWARD _PROTOTYPE( int pty_write, (tty_t *tp, int try) );
|
---|
| 69 | FORWARD _PROTOTYPE( void pty_echo, (tty_t *tp, int c) );
|
---|
| 70 | FORWARD _PROTOTYPE( void pty_start, (pty_t *pp) );
|
---|
| 71 | FORWARD _PROTOTYPE( void pty_finish, (pty_t *pp) );
|
---|
| 72 | FORWARD _PROTOTYPE( int pty_read, (tty_t *tp, int try) );
|
---|
| 73 | FORWARD _PROTOTYPE( int pty_close, (tty_t *tp, int try) );
|
---|
| 74 | FORWARD _PROTOTYPE( int pty_icancel, (tty_t *tp, int try) );
|
---|
| 75 | FORWARD _PROTOTYPE( int pty_ocancel, (tty_t *tp, int try) );
|
---|
| 76 | FORWARD _PROTOTYPE( int pty_select, (tty_t *tp, message *m) );
|
---|
| 77 |
|
---|
| 78 | /*===========================================================================*
|
---|
| 79 | * do_pty *
|
---|
| 80 | *===========================================================================*/
|
---|
| 81 | PUBLIC void do_pty(tp, m_ptr)
|
---|
| 82 | tty_t *tp;
|
---|
| 83 | message *m_ptr;
|
---|
| 84 | {
|
---|
| 85 | /* Perform an open/close/read/write call on a /dev/ptypX device. */
|
---|
| 86 | pty_t *pp = tp->tty_priv;
|
---|
| 87 | int r;
|
---|
| 88 | phys_bytes p;
|
---|
| 89 |
|
---|
| 90 | switch (m_ptr->m_type) {
|
---|
| 91 | case DEV_READ:
|
---|
| 92 | /* Check, store information on the reader, do I/O. */
|
---|
| 93 | if (pp->state & TTY_CLOSED) {
|
---|
| 94 | r = 0;
|
---|
| 95 | break;
|
---|
| 96 | }
|
---|
| 97 | if (pp->rdleft != 0 || pp->rdcum != 0) {
|
---|
| 98 | r = EIO;
|
---|
| 99 | break;
|
---|
| 100 | }
|
---|
| 101 | if (m_ptr->COUNT <= 0) {
|
---|
| 102 | r = EINVAL;
|
---|
| 103 | break;
|
---|
| 104 | }
|
---|
| 105 | #if DEAD_CODE
|
---|
| 106 | if (numap_local(m_ptr->IO_ENDPT, (vir_bytes) m_ptr->ADDRESS,
|
---|
| 107 | m_ptr->COUNT) == 0) {
|
---|
| 108 | #else
|
---|
| 109 | if ((r = sys_umap(m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS,
|
---|
| 110 | m_ptr->COUNT, &p)) != OK) {
|
---|
| 111 | #endif
|
---|
| 112 | break;
|
---|
| 113 | }
|
---|
| 114 | pp->rdsendreply = TRUE;
|
---|
| 115 | pp->rdcaller = m_ptr->m_source;
|
---|
| 116 | pp->rdproc = m_ptr->IO_ENDPT;
|
---|
| 117 | pp->rdvir = (vir_bytes) m_ptr->ADDRESS;
|
---|
| 118 | pp->rdleft = m_ptr->COUNT;
|
---|
| 119 | pty_start(pp);
|
---|
| 120 | handle_events(tp);
|
---|
| 121 | if (pp->rdleft == 0) return; /* already done */
|
---|
| 122 |
|
---|
| 123 | if (m_ptr->TTY_FLAGS & O_NONBLOCK) {
|
---|
| 124 | r = EAGAIN; /* don't suspend */
|
---|
| 125 | pp->rdleft = pp->rdcum = 0;
|
---|
| 126 | } else {
|
---|
| 127 | r = SUSPEND; /* do suspend */
|
---|
| 128 | pp->rdsendreply = FALSE;
|
---|
| 129 | }
|
---|
| 130 | break;
|
---|
| 131 |
|
---|
| 132 | case DEV_WRITE:
|
---|
| 133 | /* Check, store information on the writer, do I/O. */
|
---|
| 134 | if (pp->state & TTY_CLOSED) {
|
---|
| 135 | r = EIO;
|
---|
| 136 | break;
|
---|
| 137 | }
|
---|
| 138 | if (pp->wrleft != 0 || pp->wrcum != 0) {
|
---|
| 139 | r = EIO;
|
---|
| 140 | break;
|
---|
| 141 | }
|
---|
| 142 | if (m_ptr->COUNT <= 0) {
|
---|
| 143 | r = EINVAL;
|
---|
| 144 | break;
|
---|
| 145 | }
|
---|
| 146 | #if DEAD_CODE
|
---|
| 147 | if (numap_local(m_ptr->IO_ENDPT, (vir_bytes) m_ptr->ADDRESS,
|
---|
| 148 | m_ptr->COUNT) == 0) {
|
---|
| 149 | r = EFAULT;
|
---|
| 150 | #else
|
---|
| 151 | if ((r = sys_umap(m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS,
|
---|
| 152 | m_ptr->COUNT, &p)) != OK) {
|
---|
| 153 | #endif
|
---|
| 154 | break;
|
---|
| 155 | }
|
---|
| 156 | pp->wrsendreply = TRUE;
|
---|
| 157 | pp->wrcaller = m_ptr->m_source;
|
---|
| 158 | pp->wrproc = m_ptr->IO_ENDPT;
|
---|
| 159 | pp->wrvir = (vir_bytes) m_ptr->ADDRESS;
|
---|
| 160 | pp->wrleft = m_ptr->COUNT;
|
---|
| 161 | handle_events(tp);
|
---|
| 162 | if (pp->wrleft == 0) return; /* already done */
|
---|
| 163 |
|
---|
| 164 | if (m_ptr->TTY_FLAGS & O_NONBLOCK) { /* don't suspend */
|
---|
| 165 | r = pp->wrcum > 0 ? pp->wrcum : EAGAIN;
|
---|
| 166 | pp->wrleft = pp->wrcum = 0;
|
---|
| 167 | } else {
|
---|
| 168 | pp->wrsendreply = FALSE; /* do suspend */
|
---|
| 169 | r = SUSPEND;
|
---|
| 170 | }
|
---|
| 171 | break;
|
---|
| 172 |
|
---|
| 173 | case DEV_OPEN:
|
---|
| 174 | r = pp->state != 0 ? EIO : OK;
|
---|
| 175 | pp->state |= PTY_ACTIVE;
|
---|
| 176 | pp->rdcum = 0;
|
---|
| 177 | pp->wrcum = 0;
|
---|
| 178 | break;
|
---|
| 179 |
|
---|
| 180 | case DEV_CLOSE:
|
---|
| 181 | r = OK;
|
---|
| 182 | if (pp->state & TTY_CLOSED) {
|
---|
| 183 | pp->state = 0;
|
---|
| 184 | } else {
|
---|
| 185 | pp->state |= PTY_CLOSED;
|
---|
| 186 | sigchar(tp, SIGHUP);
|
---|
| 187 | }
|
---|
| 188 | break;
|
---|
| 189 |
|
---|
| 190 | case DEV_SELECT:
|
---|
| 191 | r = pty_select(tp, m_ptr);
|
---|
| 192 | break;
|
---|
| 193 |
|
---|
| 194 | case CANCEL:
|
---|
| 195 | if (m_ptr->IO_ENDPT == pp->rdproc) {
|
---|
| 196 | /* Cancel a read from a PTY. */
|
---|
| 197 | pp->rdleft = pp->rdcum = 0;
|
---|
| 198 | }
|
---|
| 199 | if (m_ptr->IO_ENDPT == pp->wrproc) {
|
---|
| 200 | /* Cancel a write to a PTY. */
|
---|
| 201 | pp->wrleft = pp->wrcum = 0;
|
---|
| 202 | }
|
---|
| 203 | r = EINTR;
|
---|
| 204 | break;
|
---|
| 205 |
|
---|
| 206 | default:
|
---|
| 207 | r = EINVAL;
|
---|
| 208 | }
|
---|
| 209 | tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, r);
|
---|
| 210 | }
|
---|
| 211 |
|
---|
| 212 | /*===========================================================================*
|
---|
| 213 | * pty_write *
|
---|
| 214 | *===========================================================================*/
|
---|
| 215 | PRIVATE int pty_write(tp, try)
|
---|
| 216 | tty_t *tp;
|
---|
| 217 | int try;
|
---|
| 218 | {
|
---|
| 219 | /* (*dev_write)() routine for PTYs. Transfer bytes from the writer on
|
---|
| 220 | * /dev/ttypX to the output buffer.
|
---|
| 221 | */
|
---|
| 222 | pty_t *pp = tp->tty_priv;
|
---|
| 223 | int count, ocount, s;
|
---|
| 224 | phys_bytes user_phys;
|
---|
| 225 |
|
---|
| 226 | /* PTY closed down? */
|
---|
| 227 | if (pp->state & PTY_CLOSED) {
|
---|
| 228 | if (try) return 1;
|
---|
| 229 | if (tp->tty_outleft > 0) {
|
---|
| 230 | tty_reply(tp->tty_outrepcode, tp->tty_outcaller,
|
---|
| 231 | tp->tty_outproc, EIO);
|
---|
| 232 | tp->tty_outleft = tp->tty_outcum = 0;
|
---|
| 233 | }
|
---|
| 234 | return;
|
---|
| 235 | }
|
---|
| 236 |
|
---|
| 237 | /* While there is something to do. */
|
---|
| 238 | for (;;) {
|
---|
| 239 | ocount = buflen(pp->obuf) - pp->ocount;
|
---|
| 240 | if (try) return (ocount > 0);
|
---|
| 241 | count = bufend(pp->obuf) - pp->ohead;
|
---|
| 242 | if (count > ocount) count = ocount;
|
---|
| 243 | if (count > tp->tty_outleft) count = tp->tty_outleft;
|
---|
| 244 | if (count == 0 || tp->tty_inhibited)
|
---|
| 245 | break;
|
---|
| 246 |
|
---|
| 247 | /* Copy from user space to the PTY output buffer. */
|
---|
| 248 | if ((s = sys_vircopy(tp->tty_outproc, D, (vir_bytes) tp->tty_out_vir,
|
---|
| 249 | SELF, D, (vir_bytes) pp->ohead, (phys_bytes) count)) != OK) {
|
---|
| 250 | printf("pty tty%d: copy failed (error %d)\n", s);
|
---|
| 251 | break;
|
---|
| 252 | }
|
---|
| 253 |
|
---|
| 254 | /* Perform output processing on the output buffer. */
|
---|
| 255 | out_process(tp, pp->obuf, pp->ohead, bufend(pp->obuf), &count, &ocount);
|
---|
| 256 | if (count == 0) break;
|
---|
| 257 |
|
---|
| 258 | /* Assume echoing messed up by output. */
|
---|
| 259 | tp->tty_reprint = TRUE;
|
---|
| 260 |
|
---|
| 261 | /* Bookkeeping. */
|
---|
| 262 | pp->ocount += ocount;
|
---|
| 263 | if ((pp->ohead += ocount) >= bufend(pp->obuf))
|
---|
| 264 | pp->ohead -= buflen(pp->obuf);
|
---|
| 265 | pty_start(pp);
|
---|
| 266 | tp->tty_out_vir += count;
|
---|
| 267 | tp->tty_outcum += count;
|
---|
| 268 | if ((tp->tty_outleft -= count) == 0) {
|
---|
| 269 | /* Output is finished, reply to the writer. */
|
---|
| 270 | tty_reply(tp->tty_outrepcode, tp->tty_outcaller,
|
---|
| 271 | tp->tty_outproc, tp->tty_outcum);
|
---|
| 272 | tp->tty_outcum = 0;
|
---|
| 273 | }
|
---|
| 274 | }
|
---|
| 275 | pty_finish(pp);
|
---|
| 276 | return 1;
|
---|
| 277 | }
|
---|
| 278 |
|
---|
| 279 | /*===========================================================================*
|
---|
| 280 | * pty_echo *
|
---|
| 281 | *===========================================================================*/
|
---|
| 282 | PRIVATE void pty_echo(tp, c)
|
---|
| 283 | tty_t *tp;
|
---|
| 284 | int c;
|
---|
| 285 | {
|
---|
| 286 | /* Echo one character. (Like pty_write, but only one character, optionally.) */
|
---|
| 287 |
|
---|
| 288 | pty_t *pp = tp->tty_priv;
|
---|
| 289 | int count, ocount;
|
---|
| 290 |
|
---|
| 291 | ocount = buflen(pp->obuf) - pp->ocount;
|
---|
| 292 | if (ocount == 0) return; /* output buffer full */
|
---|
| 293 | count = 1;
|
---|
| 294 | *pp->ohead = c; /* add one character */
|
---|
| 295 |
|
---|
| 296 | out_process(tp, pp->obuf, pp->ohead, bufend(pp->obuf), &count, &ocount);
|
---|
| 297 | if (count == 0) return;
|
---|
| 298 |
|
---|
| 299 | pp->ocount += ocount;
|
---|
| 300 | if ((pp->ohead += ocount) >= bufend(pp->obuf)) pp->ohead -= buflen(pp->obuf);
|
---|
| 301 | pty_start(pp);
|
---|
| 302 | }
|
---|
| 303 |
|
---|
| 304 | /*===========================================================================*
|
---|
| 305 | * pty_start *
|
---|
| 306 | *===========================================================================*/
|
---|
| 307 | PRIVATE void pty_start(pp)
|
---|
| 308 | pty_t *pp;
|
---|
| 309 | {
|
---|
| 310 | /* Transfer bytes written to the output buffer to the PTY reader. */
|
---|
| 311 | int count;
|
---|
| 312 |
|
---|
| 313 | /* While there are things to do. */
|
---|
| 314 | for (;;) {
|
---|
| 315 | int s;
|
---|
| 316 | count = bufend(pp->obuf) - pp->otail;
|
---|
| 317 | if (count > pp->ocount) count = pp->ocount;
|
---|
| 318 | if (count > pp->rdleft) count = pp->rdleft;
|
---|
| 319 | if (count == 0) break;
|
---|
| 320 |
|
---|
| 321 | /* Copy from the output buffer to the readers address space. */
|
---|
| 322 | if ((s = sys_vircopy(SELF, D, (vir_bytes)pp->otail,
|
---|
| 323 | (vir_bytes) pp->rdproc, D, (vir_bytes) pp->rdvir, (phys_bytes) count)) != OK) {
|
---|
| 324 | printf("pty tty%d: copy failed (error %d)\n", s);
|
---|
| 325 | break;
|
---|
| 326 | }
|
---|
| 327 |
|
---|
| 328 | /* Bookkeeping. */
|
---|
| 329 | pp->ocount -= count;
|
---|
| 330 | if ((pp->otail += count) == bufend(pp->obuf)) pp->otail = pp->obuf;
|
---|
| 331 | pp->rdvir += count;
|
---|
| 332 | pp->rdcum += count;
|
---|
| 333 | pp->rdleft -= count;
|
---|
| 334 | }
|
---|
| 335 | }
|
---|
| 336 |
|
---|
| 337 | /*===========================================================================*
|
---|
| 338 | * pty_finish *
|
---|
| 339 | *===========================================================================*/
|
---|
| 340 | PRIVATE void pty_finish(pp)
|
---|
| 341 | pty_t *pp;
|
---|
| 342 | {
|
---|
| 343 | /* Finish the read request of a PTY reader if there is at least one byte
|
---|
| 344 | * transferred.
|
---|
| 345 | */
|
---|
| 346 | if (pp->rdcum > 0) {
|
---|
| 347 | if (pp->rdsendreply) {
|
---|
| 348 | tty_reply(TASK_REPLY, pp->rdcaller, pp->rdproc, pp->rdcum);
|
---|
| 349 | pp->rdleft = pp->rdcum = 0;
|
---|
| 350 | }
|
---|
| 351 | else
|
---|
| 352 | notify(pp->rdcaller);
|
---|
| 353 | }
|
---|
| 354 |
|
---|
| 355 | }
|
---|
| 356 |
|
---|
| 357 | /*===========================================================================*
|
---|
| 358 | * pty_read *
|
---|
| 359 | *===========================================================================*/
|
---|
| 360 | PRIVATE int pty_read(tp, try)
|
---|
| 361 | tty_t *tp;
|
---|
| 362 | int try;
|
---|
| 363 | {
|
---|
| 364 | /* Offer bytes from the PTY writer for input on the TTY. (Do it one byte at
|
---|
| 365 | * a time, 99% of the writes will be for one byte, so no sense in being smart.)
|
---|
| 366 | */
|
---|
| 367 | pty_t *pp = tp->tty_priv;
|
---|
| 368 | char c;
|
---|
| 369 |
|
---|
| 370 | if (pp->state & PTY_CLOSED) {
|
---|
| 371 | if (try) return 1;
|
---|
| 372 | if (tp->tty_inleft > 0) {
|
---|
| 373 | tty_reply(tp->tty_inrepcode, tp->tty_incaller, tp->tty_inproc,
|
---|
| 374 | tp->tty_incum);
|
---|
| 375 | tp->tty_inleft = tp->tty_incum = 0;
|
---|
| 376 | }
|
---|
| 377 | return 1;
|
---|
| 378 | }
|
---|
| 379 |
|
---|
| 380 | if (try) {
|
---|
| 381 | if (pp->wrleft > 0)
|
---|
| 382 | return 1;
|
---|
| 383 | return 0;
|
---|
| 384 | }
|
---|
| 385 |
|
---|
| 386 | while (pp->wrleft > 0) {
|
---|
| 387 | int s;
|
---|
| 388 |
|
---|
| 389 | /* Transfer one character to 'c'. */
|
---|
| 390 | if ((s = sys_vircopy(pp->wrproc, D, (vir_bytes) pp->wrvir,
|
---|
| 391 | SELF, D, (vir_bytes) &c, (phys_bytes) 1)) != OK) {
|
---|
| 392 | printf("pty: copy failed (error %d)\n", s);
|
---|
| 393 | break;
|
---|
| 394 | }
|
---|
| 395 |
|
---|
| 396 | /* Input processing. */
|
---|
| 397 | if (in_process(tp, &c, 1) == 0) break;
|
---|
| 398 |
|
---|
| 399 | /* PTY writer bookkeeping. */
|
---|
| 400 | pp->wrvir++;
|
---|
| 401 | pp->wrcum++;
|
---|
| 402 | if (--pp->wrleft == 0) {
|
---|
| 403 | if (pp->wrsendreply) {
|
---|
| 404 | tty_reply(TASK_REPLY, pp->wrcaller, pp->wrproc,
|
---|
| 405 | pp->wrcum);
|
---|
| 406 | pp->wrcum = 0;
|
---|
| 407 | }
|
---|
| 408 | else
|
---|
| 409 | notify(pp->wrcaller);
|
---|
| 410 | }
|
---|
| 411 | }
|
---|
| 412 | }
|
---|
| 413 |
|
---|
| 414 | /*===========================================================================*
|
---|
| 415 | * pty_close *
|
---|
| 416 | *===========================================================================*/
|
---|
| 417 | PRIVATE int pty_close(tp, try)
|
---|
| 418 | tty_t *tp;
|
---|
| 419 | int try;
|
---|
| 420 | {
|
---|
| 421 | /* The tty side has closed, so shut down the pty side. */
|
---|
| 422 | pty_t *pp = tp->tty_priv;
|
---|
| 423 |
|
---|
| 424 | if (!(pp->state & PTY_ACTIVE)) return;
|
---|
| 425 |
|
---|
| 426 | if (pp->rdleft > 0) {
|
---|
| 427 | assert(!pp->rdsendreply);
|
---|
| 428 | notify(pp->rdcaller);
|
---|
| 429 | }
|
---|
| 430 |
|
---|
| 431 | if (pp->wrleft > 0) {
|
---|
| 432 | assert(!pp->wrsendreply);
|
---|
| 433 | notify(pp->wrcaller);
|
---|
| 434 | }
|
---|
| 435 |
|
---|
| 436 | if (pp->state & PTY_CLOSED) pp->state = 0; else pp->state |= TTY_CLOSED;
|
---|
| 437 | }
|
---|
| 438 |
|
---|
| 439 | /*===========================================================================*
|
---|
| 440 | * pty_icancel *
|
---|
| 441 | *===========================================================================*/
|
---|
| 442 | PRIVATE int pty_icancel(tp, try)
|
---|
| 443 | tty_t *tp;
|
---|
| 444 | int try;
|
---|
| 445 | {
|
---|
| 446 | /* Discard waiting input. */
|
---|
| 447 | pty_t *pp = tp->tty_priv;
|
---|
| 448 |
|
---|
| 449 | if (pp->wrleft > 0) {
|
---|
| 450 | assert(!pp->wrsendreply);
|
---|
| 451 | pp->wrcum += pp->wrleft;
|
---|
| 452 | pp->wrleft= 0;
|
---|
| 453 | notify(pp->wrcaller);
|
---|
| 454 | }
|
---|
| 455 | }
|
---|
| 456 |
|
---|
| 457 | /*===========================================================================*
|
---|
| 458 | * pty_ocancel *
|
---|
| 459 | *===========================================================================*/
|
---|
| 460 | PRIVATE int pty_ocancel(tp, try)
|
---|
| 461 | tty_t *tp;
|
---|
| 462 | int try;
|
---|
| 463 | {
|
---|
| 464 | /* Drain the output buffer. */
|
---|
| 465 | pty_t *pp = tp->tty_priv;
|
---|
| 466 |
|
---|
| 467 | pp->ocount = 0;
|
---|
| 468 | pp->otail = pp->ohead;
|
---|
| 469 | }
|
---|
| 470 |
|
---|
| 471 | /*===========================================================================*
|
---|
| 472 | * pty_init *
|
---|
| 473 | *===========================================================================*/
|
---|
| 474 | PUBLIC void pty_init(tp)
|
---|
| 475 | tty_t *tp;
|
---|
| 476 | {
|
---|
| 477 | pty_t *pp;
|
---|
| 478 | int line;
|
---|
| 479 |
|
---|
| 480 | /* Associate PTY and TTY structures. */
|
---|
| 481 | line = tp - &tty_table[NR_CONS + NR_RS_LINES];
|
---|
| 482 | pp = tp->tty_priv = &pty_table[line];
|
---|
| 483 | pp->tty = tp;
|
---|
| 484 | pp->select_ops = 0;
|
---|
| 485 |
|
---|
| 486 | /* Set up output queue. */
|
---|
| 487 | pp->ohead = pp->otail = pp->obuf;
|
---|
| 488 |
|
---|
| 489 | /* Fill in TTY function hooks. */
|
---|
| 490 | tp->tty_devread = pty_read;
|
---|
| 491 | tp->tty_devwrite = pty_write;
|
---|
| 492 | tp->tty_echo = pty_echo;
|
---|
| 493 | tp->tty_icancel = pty_icancel;
|
---|
| 494 | tp->tty_ocancel = pty_ocancel;
|
---|
| 495 | tp->tty_close = pty_close;
|
---|
| 496 | tp->tty_select_ops = 0;
|
---|
| 497 | }
|
---|
| 498 |
|
---|
| 499 | /*===========================================================================*
|
---|
| 500 | * pty_status *
|
---|
| 501 | *===========================================================================*/
|
---|
| 502 | PUBLIC int pty_status(message *m_ptr)
|
---|
| 503 | {
|
---|
| 504 | int i, event_found;
|
---|
| 505 | pty_t *pp;
|
---|
| 506 |
|
---|
| 507 | event_found = 0;
|
---|
| 508 | for (i= 0, pp = pty_table; i<NR_PTYS; i++, pp++) {
|
---|
| 509 | if ((((pp->state & TTY_CLOSED) && pp->rdleft > 0) ||
|
---|
| 510 | pp->rdcum > 0) &&
|
---|
| 511 | pp->rdcaller == m_ptr->m_source)
|
---|
| 512 | {
|
---|
| 513 | m_ptr->m_type = DEV_REVIVE;
|
---|
| 514 | m_ptr->REP_ENDPT = pp->rdproc;
|
---|
| 515 | m_ptr->REP_STATUS = pp->rdcum;
|
---|
| 516 |
|
---|
| 517 | pp->rdleft = pp->rdcum = 0;
|
---|
| 518 | event_found = 1;
|
---|
| 519 | break;
|
---|
| 520 | }
|
---|
| 521 |
|
---|
| 522 | if ((((pp->state & TTY_CLOSED) && pp->wrleft > 0) ||
|
---|
| 523 | pp->wrcum > 0) &&
|
---|
| 524 | pp->wrcaller == m_ptr->m_source)
|
---|
| 525 | {
|
---|
| 526 | m_ptr->m_type = DEV_REVIVE;
|
---|
| 527 | m_ptr->REP_ENDPT = pp->wrproc;
|
---|
| 528 | if (pp->wrcum == 0)
|
---|
| 529 | m_ptr->REP_STATUS = EIO;
|
---|
| 530 | else
|
---|
| 531 | m_ptr->REP_STATUS = pp->wrcum;
|
---|
| 532 |
|
---|
| 533 | pp->wrleft = pp->wrcum = 0;
|
---|
| 534 | event_found = 1;
|
---|
| 535 | break;
|
---|
| 536 | }
|
---|
| 537 |
|
---|
| 538 | if (pp->select_ready_ops && pp->select_proc == m_ptr->m_source) {
|
---|
| 539 | m_ptr->m_type = DEV_IO_READY;
|
---|
| 540 | m_ptr->DEV_MINOR = PTYPX_MINOR + i;
|
---|
| 541 | m_ptr->DEV_SEL_OPS = pp->select_ready_ops;
|
---|
| 542 | pp->select_ready_ops = 0;
|
---|
| 543 | event_found = 1;
|
---|
| 544 | break;
|
---|
| 545 | }
|
---|
| 546 | }
|
---|
| 547 | return event_found;
|
---|
| 548 | }
|
---|
| 549 |
|
---|
| 550 | /*===========================================================================*
|
---|
| 551 | * select_try_pty *
|
---|
| 552 | *===========================================================================*/
|
---|
| 553 | PRIVATE int select_try_pty(tty_t *tp, int ops)
|
---|
| 554 | {
|
---|
| 555 | pty_t *pp = tp->tty_priv;
|
---|
| 556 | int r = 0;
|
---|
| 557 |
|
---|
| 558 | if (ops & SEL_WR) {
|
---|
| 559 | /* Write won't block on error. */
|
---|
| 560 | if (pp->state & TTY_CLOSED) r |= SEL_WR;
|
---|
| 561 | else if (pp->wrleft != 0 || pp->wrcum != 0) r |= SEL_WR;
|
---|
| 562 | else r |= SEL_WR;
|
---|
| 563 | }
|
---|
| 564 |
|
---|
| 565 | if (ops & SEL_RD) {
|
---|
| 566 | /* Read won't block on error. */
|
---|
| 567 | if (pp->state & TTY_CLOSED) r |= SEL_RD;
|
---|
| 568 | else if (pp->rdleft != 0 || pp->rdcum != 0) r |= SEL_RD;
|
---|
| 569 | else if (pp->ocount > 0) r |= SEL_RD; /* Actual data. */
|
---|
| 570 | }
|
---|
| 571 |
|
---|
| 572 | return r;
|
---|
| 573 | }
|
---|
| 574 |
|
---|
| 575 | /*===========================================================================*
|
---|
| 576 | * select_retry_pty *
|
---|
| 577 | *===========================================================================*/
|
---|
| 578 | PUBLIC void select_retry_pty(tty_t *tp)
|
---|
| 579 | {
|
---|
| 580 | pty_t *pp = tp->tty_priv;
|
---|
| 581 | int r;
|
---|
| 582 |
|
---|
| 583 | /* See if the pty side of a pty is ready to return a select. */
|
---|
| 584 | if (pp->select_ops && (r=select_try_pty(tp, pp->select_ops))) {
|
---|
| 585 | pp->select_ops &= ~r;
|
---|
| 586 | pp->select_ready_ops |= r;
|
---|
| 587 | notify(pp->select_proc);
|
---|
| 588 | }
|
---|
| 589 | }
|
---|
| 590 |
|
---|
| 591 | /*===========================================================================*
|
---|
| 592 | * pty_select *
|
---|
| 593 | *===========================================================================*/
|
---|
| 594 | PRIVATE int pty_select(tty_t *tp, message *m)
|
---|
| 595 | {
|
---|
| 596 | pty_t *pp = tp->tty_priv;
|
---|
| 597 | int ops, ready_ops = 0, watch;
|
---|
| 598 |
|
---|
| 599 | ops = m->IO_ENDPT & (SEL_RD|SEL_WR|SEL_ERR);
|
---|
| 600 | watch = (m->IO_ENDPT & SEL_NOTIFY) ? 1 : 0;
|
---|
| 601 |
|
---|
| 602 | ready_ops = select_try_pty(tp, ops);
|
---|
| 603 |
|
---|
| 604 | if (!ready_ops && ops && watch) {
|
---|
| 605 | pp->select_ops |= ops;
|
---|
| 606 | pp->select_proc = m->m_source;
|
---|
| 607 | }
|
---|
| 608 |
|
---|
| 609 | return ready_ops;
|
---|
| 610 | }
|
---|
| 611 |
|
---|
| 612 | #endif /* NR_PTYS > 0 */
|
---|