#include <signal.h>
#include <minix/com.h>
#include <minix/callnr.h>
+#include <sys/select.h>
#include "tty.h"
#if NR_PTYS > 0
int ocount; /* # characters in the buffer */
char *ohead, *otail; /* head and tail of the circular buffer */
char obuf[128]; /* buffer for bytes going to the pty reader */
+
+ /* select() data. */
+ int select_ops, /* Which operations do we want to know about? */
+ select_proc, /* Who wants to know about it? */
+ select_ready_ops; /* For callback. */
} pty_t;
#define PTY_ACTIVE 0x01 /* pty is open/active */
FORWARD _PROTOTYPE( void pty_echo, (tty_t *tp, int c) );
FORWARD _PROTOTYPE( void pty_start, (pty_t *pp) );
FORWARD _PROTOTYPE( void pty_finish, (pty_t *pp) );
-FORWARD _PROTOTYPE( int pty_read, (tty_t *tp, int try) );
-FORWARD _PROTOTYPE( int pty_close, (tty_t *tp, int try) );
-FORWARD _PROTOTYPE( int pty_icancel, (tty_t *tp, int try) );
-FORWARD _PROTOTYPE( int pty_ocancel, (tty_t *tp, int try) );
+FORWARD _PROTOTYPE( int pty_read, (tty_t *tp, int try) );
+FORWARD _PROTOTYPE( int pty_close, (tty_t *tp, int try) );
+FORWARD _PROTOTYPE( int pty_icancel, (tty_t *tp, int try) );
+FORWARD _PROTOTYPE( int pty_ocancel, (tty_t *tp, int try) );
+FORWARD _PROTOTYPE( int pty_select, (tty_t *tp, message *m) );
/*==========================================================================*
}
break;
+ case DEV_SELECT:
+ r = pty_select(tp, m_ptr);
+ break;
+
case CANCEL:
if (m_ptr->PROC_NR == pp->rdproc) {
/* Cancel a read from a PTY. */
int count, ocount, s;
phys_bytes user_phys;
+
/* PTY closed down? */
if (pp->state & PTY_CLOSED) {
if(try) return 1;
/* While there is something to do. */
for (;;) {
ocount = buflen(pp->obuf) - pp->ocount;
+ if(try) return (ocount > 0);
count = bufend(pp->obuf) - pp->ohead;
if (count > ocount) count = ocount;
if (count > tp->tty_outleft) count = tp->tty_outleft;
- if (count == 0 || tp->tty_inhibited) {
- if(try) return 0;
+ if (count == 0 || tp->tty_inhibited)
break;
- }
- if(try) return 1;
/* Copy from user space to the PTY output buffer. */
if((s = sys_vircopy(tp->tty_outproc, D, (vir_bytes) tp->tty_out_vir,
/* Finish the read request of a PTY reader if there is at least one byte
* transferred.
*/
-
if (pp->rdcum > 0) {
if (pp->rdsendreply) {
tty_reply(TASK_REPLY, pp->rdcaller, pp->rdproc, pp->rdcum);
else
notify(pp->rdcaller);
}
+
}
pty_t *pp = tp->tty_priv;
char c;
+
if (pp->state & PTY_CLOSED) {
if(try) return 1;
if (tp->tty_inleft > 0) {
line = tp - &tty_table[NR_CONS + NR_RS_LINES];
pp = tp->tty_priv = &pty_table[line];
pp->tty = tp;
+ pp->select_ops = 0;
/* Set up output queue. */
pp->ohead = pp->otail = pp->obuf;
tp->tty_icancel = pty_icancel;
tp->tty_ocancel = pty_ocancel;
tp->tty_close = pty_close;
+ tp->tty_select_ops = 0;
}
event_found = 0;
for (i= 0, pp = pty_table; i<NR_PTYS; i++, pp++) {
- if (((pp->state & TTY_CLOSED && pp->rdleft > 0) ||
+ if ((((pp->state & TTY_CLOSED) && pp->rdleft > 0) ||
pp->rdcum > 0) &&
pp->rdcaller == m_ptr->m_source)
{
break;
}
- if (((pp->state & TTY_CLOSED && pp->wrleft > 0) ||
+ if ((((pp->state & TTY_CLOSED) && pp->wrleft > 0) ||
pp->wrcum > 0) &&
pp->wrcaller == m_ptr->m_source)
{
event_found = 1;
break;
}
+
+ if(pp->select_ready_ops && pp->select_proc == m_ptr->m_source) {
+ m_ptr->m_type = DEV_IO_READY;
+ m_ptr->DEV_MINOR = PTYPX_MINOR + i;
+ m_ptr->DEV_SEL_OPS = pp->select_ready_ops;
+ pp->select_ready_ops = 0;
+ event_found = 1;
+ break;
+ }
}
return event_found;
}
+/*==========================================================================*
+ * select_try_pty *
+ *==========================================================================*/
+PRIVATE int select_try_pty(tty_t *tp, int ops)
+{
+ pty_t *pp = tp->tty_priv;
+ int r = 0;
+
+ if(ops & SEL_WR) {
+ /* Write won't block on error. */
+ if (pp->state & TTY_CLOSED) r |= SEL_WR;
+ else if (pp->wrleft != 0 || pp->wrcum != 0) r |= SEL_WR;
+ else r |= SEL_WR;
+ }
+
+ if(ops & SEL_RD) {
+ /* Read won't block on error. */
+ if (pp->state & TTY_CLOSED) r |= SEL_RD;
+ else if(pp->rdleft != 0 || pp->rdcum != 0) r |= SEL_RD;
+ else if(pp->ocount > 0) r |= SEL_RD; /* Actual data. */
+ }
+
+ return r;
+}
+
+/*==========================================================================*
+ * select_retry_pty *
+ *==========================================================================*/
+PUBLIC void select_retry_pty(tty_t *tp)
+{
+ pty_t *pp = tp->tty_priv;
+ int r;
+
+ /* See if the pty side of a pty is ready to return a select. */
+ if(pp->select_ops && (r=select_try_pty(tp, pp->select_ops))) {
+ pp->select_ops &= ~r;
+ pp->select_ready_ops |= r;
+ notify(pp->select_proc);
+ }
+}
+
+/*==========================================================================*
+ * pty_select *
+ *==========================================================================*/
+PRIVATE int pty_select(tty_t *tp, message *m)
+{
+ pty_t *pp = tp->tty_priv;
+ int ops, ready_ops = 0, watch;
+
+ ops = m->PROC_NR & (SEL_RD|SEL_WR|SEL_ERR);
+ watch = (m->PROC_NR & SEL_NOTIFY) ? 1 : 0;
+
+ ready_ops = select_try_pty(tp, ops);
+
+ if(!ready_ops && ops && watch) {
+ pp->select_ops |= ops;
+ pp->select_proc = m->m_source;
+ }
+
+ return ready_ops;
+}
+
#endif /* NR_PTYS > 0 */
/* Address of a tty structure. */
#define tty_addr(line) (&tty_table[line])
-/* First minor numbers for the various classes of TTY devices. */
-#define CONS_MINOR 0
-#define LOG_MINOR 15
-#define RS232_MINOR 16
-#define TTYPX_MINOR 128
-#define PTYPX_MINOR 192
-
/* Macros for magic tty types. */
#define isconsole(tp) ((tp) < tty_addr(NR_CONS))
+#define ispty(tp) ((tp) >= tty_addr(NR_CONS+NR_RS_LINES))
/* Macros for magic tty structure pointers. */
#define FIRST_TTY tty_addr(0)
panic("TTY","Couldn't obtain kernel environment.", s);
}
-printf("\n");
while (TRUE) {
/* Check for and handle any events on any of the ttys. */
/* Try to write. */
handle_events(tp);
- if (tp->tty_outleft == 0) {
- if(tp->tty_select_ops)
- select_retry(tp);
- return; /* already done */
- }
+ if (tp->tty_outleft == 0)
+ return; /* already done */
/* None or not all the bytes could be written, so either suspend the
* caller or break off the write if nonblocking.
}
}
tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r);
- if(tp->tty_select_ops)
- select_retry(tp);
}
* (and it can be seen as an exceptional condition.)
*/
if (tp->tty_termios.c_ospeed == B0) {
- printf("tty: hangup always ok\n");
ready_ops |= ops;
}
if (tp->tty_inleft > 0) {
ready_ops |= SEL_RD; /* EIO - no blocking */
} else if(tp->tty_incount > 0) {
- /* is a regular read possible? tty_incount
- * says there is data. but a read will only succeed
+ /* Is a regular read possible? tty_incount
+ * says there is data. But a read will only succeed
* in canonical mode if a newline has been seen.
*/
if(!(tp->tty_termios.c_lflag & ICANON) ||
}
}
- if(ops & SEL_WR) {
- if (tp->tty_outleft > 0) {
- ready_ops |= SEL_WR; /* EIO - no blocking */
- }
- if((*tp->tty_devwrite)(tp, 1)) {
- ready_ops |= SEL_WR; /* real write possible */
- }
+ if(ops & SEL_WR) {
+ if (tp->tty_outleft > 0) ready_ops |= SEL_WR;
+ else if((*tp->tty_devwrite)(tp, 1)) ready_ops |= SEL_WR;
}
return ready_ops;
PUBLIC int select_retry(struct tty *tp)
{
-#if DEAD_CODE
- int ops;
- if((ops = select_try(tp, tp->tty_select_ops))) {
- message m;
- m.NOTIFY_TYPE = DEV_SELECTED;
- m.NOTIFY_ARG = tp->tty_index;
- m.NOTIFY_FLAGS = ops;
- notify(tp->tty_select_proc, &m);
- tp->tty_select_ops &= ~ops;
- }
-#else
if (select_try(tp, tp->tty_select_ops))
notify(tp->tty_select_proc);
-#endif
-
return OK;
}
tp->tty_inleft = tp->tty_incum = 0;
#endif
}
+ if(tp->tty_select_ops)
+ select_retry(tp);
+ if(ispty(tp))
+ select_retry_pty(tp);
}
tty_devnop;
if (tp < tty_addr(NR_CONS)) {
scr_init(tp);
+ tp->tty_minor = CONS_MINOR + s;
} else
if (tp < tty_addr(NR_CONS+NR_RS_LINES)) {
rs_init(tp);
+ tp->tty_minor = RS232_MINOR + s-NR_CONS;
} else {
pty_init(tp);
+ tp->tty_minor = s + TTYPX_MINOR + s-(NR_CONS+RS232_MINOR);
}
}
register message *m_ptr; /* pointer to message sent to the task */
{
int ops, ready_ops = 0, watch;
- printf("doing select..\n");
ops = m_ptr->PROC_NR & (SEL_RD|SEL_WR|SEL_ERR);
watch = (m_ptr->PROC_NR & SEL_NOTIFY) ? 1 : 0;
ready_ops = select_try(tp, ops);
if(!ready_ops && ops && watch) {
- printf("doing select.. ops %d\n", ops);
tp->tty_select_ops |= ops;
tp->tty_select_proc = m_ptr->m_source;
- } else printf("not doing select.. ready_ops %d ops %d watch %d\n",
- ready_ops, ops, watch);
+ }
tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, ready_ops);