. Safe I/O, ioctl() and DIAGNOSTICS variants conversion - safe copies,

include grant id in DEV_REVIVE messages.
. Removal of TTY_FLAGS field (and so O_NONBLOCK support).
. Fixed CANCEL behaviour and return code on blocking I/O,
  previously handled by O_NONBLOCK
. Totally removed REVIVE replies, previously still possible on
  blocking ioctls (REVIVE directly called) and ptys (missing TTY_REVIVE
  check), removes deadlock bug with FS
. Removed obsolete *COMPAT options and associated code
This commit is contained in:
Ben Gras 2006-06-20 09:02:54 +00:00
parent 9fa06d5e3f
commit 1c8b206a5d
7 changed files with 443 additions and 595 deletions

View File

@ -14,7 +14,7 @@ MAKE = exec make
CC = exec cc
CFLAGS = -I$i
LDFLAGS = -i
LIBS = -lsys -lsysutil -ltimers
LIBS = -lsysutil -lsys -ltimers
OBJ = tty.o console.o vidcopy.o keyboard.o pty.o rs232.o

View File

@ -167,13 +167,20 @@ int try;
*/
do {
if (count > sizeof(buf)) count = sizeof(buf);
if ((result = sys_vircopy(tp->tty_outproc, D, tp->tty_out_vir,
if(tp->tty_out_safe) {
if ((result = sys_safecopyfrom(tp->tty_outproc, tp->tty_out_vir_g,
tp->tty_out_vir_offset, (vir_bytes) buf, count, D)) != OK)
break;
tp->tty_out_vir_offset += count;
} else {
if ((result = sys_vircopy(tp->tty_outproc, D, tp->tty_out_vir_g,
SELF, D, (vir_bytes) buf, (vir_bytes) count)) != OK)
break;
tp->tty_out_vir_g += count;
}
tbuf = buf;
/* Update terminal data structure. */
tp->tty_out_vir += count;
tp->tty_outcum += count;
tp->tty_outleft -= count;
@ -777,7 +784,7 @@ PRIVATE void beep()
*===========================================================================*/
PUBLIC void do_video(message *m)
{
int i, n, r, ops, watch;
int i, n, r, ops, watch, safe = 0;
unsigned char c;
/* Execute the requested device driver function. */
@ -790,6 +797,9 @@ PUBLIC void do_video(message *m)
case DEV_CLOSE:
r= OK;
break;
case DEV_IOCTL_S:
safe=1;
/* Fallthrough. */
case DEV_IOCTL:
if (m->TTY_REQUEST == MIOCMAP || m->TTY_REQUEST == MIOCUNMAP)
{
@ -799,18 +809,30 @@ PUBLIC void do_video(message *m)
do_map= (m->REQUEST == MIOCMAP); /* else unmap */
/* Get request structure */
r= sys_vircopy(m->IO_ENDPT, D,
if(safe) {
r = sys_safecopyfrom(m->IO_ENDPT,
(vir_bytes)m->ADDRESS, 0, (vir_bytes) &mapreq,
sizeof(mapreq), D);
} else {
r= sys_vircopy(m->IO_ENDPT, D,
(vir_bytes)m->ADDRESS,
SELF, D, (vir_bytes)&mapreq, sizeof(mapreq));
}
if (r != OK)
{
tty_reply(TASK_REPLY, m->m_source, m->IO_ENDPT,
r);
return;
}
r= sys_vm_map(m->IO_ENDPT, do_map,
(phys_bytes)mapreq.base, mapreq.size,
mapreq.offset);
/* In safe ioctl mode, the POSITION field contains
* the endpt number of the original requestor.
* IO_ENDPT is always FS.
*/
r= sys_vm_map(safe ? m->POSITION : m->IO_ENDPT,
do_map, (phys_bytes)mapreq.base, mapreq.size,
mapreq.offset);
tty_reply(TASK_REPLY, m->m_source, m->IO_ENDPT, r);
return;
}
@ -1057,20 +1079,27 @@ message *m;
/*===========================================================================*
* do_diagnostics *
*===========================================================================*/
PUBLIC void do_diagnostics(m_ptr)
PUBLIC void do_diagnostics(m_ptr, safe)
message *m_ptr; /* pointer to request message */
int safe;
{
/* Print a string for a server. */
char c;
vir_bytes src;
int count;
int count, offset = 0;
int result = OK;
int proc_nr = m_ptr->DIAG_ENDPT;
if (proc_nr == SELF) proc_nr = m_ptr->m_source;
int proc_nr = m_ptr->m_source;
src = (vir_bytes) m_ptr->DIAG_PRINT_BUF;
src = (vir_bytes) m_ptr->DIAG_PRINT_BUF_G;
for (count = m_ptr->DIAG_BUF_COUNT; count > 0; count--) {
if (sys_vircopy(proc_nr, D, src++, SELF, D, (vir_bytes) &c, 1) != OK) {
int r;
if(safe) {
r = sys_safecopyfrom(proc_nr, src, offset, (vir_bytes) &c, 1, D);
} else {
r = sys_vircopy(proc_nr, D, src+offset, SELF, D, (vir_bytes) &c, 1);
}
offset++;
if(r != OK) {
result = EFAULT;
break;
}

View File

@ -110,7 +110,9 @@ PRIVATE struct kbd
int avail;
int req_size;
int req_proc;
vir_bytes req_addr;
int req_safe; /* nonzero: safe (req_addr_g is grant) */
vir_bytes req_addr_g; /* Virtual address or grant */
vir_bytes req_addr_offset;
int incaller;
int select_ops;
int select_proc;
@ -188,7 +190,7 @@ PRIVATE void handle_req(kbdp, m)
struct kbd *kbdp;
message *m;
{
int i, n, r, ops, watch;
int i, n, r, ops, watch, safecopy = 0;
unsigned char c;
/* Execute the requested device driver function. */
@ -209,6 +211,9 @@ message *m;
kbdp->avail= 0;
r= OK;
break;
case DEV_READ_S:
safecopy = 1;
/* Fallthrough. */
case DEV_READ:
if (kbdp->req_size)
{
@ -221,7 +226,9 @@ message *m;
/* Should record proc */
kbdp->req_size= m->COUNT;
kbdp->req_proc= m->IO_ENDPT;
kbdp->req_addr= (vir_bytes)m->ADDRESS;
kbdp->req_addr_g= (vir_bytes)m->ADDRESS;
kbdp->req_addr_offset= 0;
kbdp->req_safe= safecopy;
kbdp->incaller= m->m_source;
r= SUSPEND;
break;
@ -235,17 +242,27 @@ message *m;
n= KBD_BUFSZ-kbdp->offset;
if (n <= 0)
panic("TTY", "do_kbd(READ): bad n", n);
r= sys_vircopy(SELF, D, (vir_bytes)&kbdp->buf[kbdp->offset],
if(safecopy) {
r= sys_safecopyto(m->IO_ENDPT, (vir_bytes) m->ADDRESS, 0,
(vir_bytes) &kbdp->buf[kbdp->offset], n, D);
} else {
r= sys_vircopy(SELF, D, (vir_bytes)&kbdp->buf[kbdp->offset],
m->IO_ENDPT, D, (vir_bytes) m->ADDRESS, n);
}
if (r == OK)
{
kbdp->offset= (kbdp->offset+n) % KBD_BUFSZ;
kbdp->avail -= n;
r= n;
} else {
printf("copy in read kbd failed: %d\n", r);
}
break;
case DEV_WRITE_S:
safecopy = 1;
/* Fallthrough. */
case DEV_WRITE:
if (kbdp != &kbdaux)
{
@ -260,8 +277,14 @@ message *m;
*/
for (i= 0; i<m->COUNT; i++)
{
r= sys_vircopy(m->IO_ENDPT, D, (vir_bytes) m->ADDRESS+i,
if(safecopy) {
r= sys_safecopyfrom(m->IO_ENDPT, (vir_bytes)
m->ADDRESS, i, (vir_bytes)&c, 1, D);
} else {
r= sys_vircopy(m->IO_ENDPT, D,
(vir_bytes) m->ADDRESS+i,
SELF, D, (vir_bytes)&c, 1);
}
if (r != OK)
break;
kbc_cmd1(KBC_WRITE_AUX, c);
@ -290,14 +313,24 @@ message *m;
kbdp->select_proc= m->m_source;
}
break;
case DEV_IOCTL_S:
safecopy=1;
/* Fallthrough. */
case DEV_IOCTL:
if (kbdp == &kbd && m->TTY_REQUEST == KIOCSLEDS)
{
kio_leds_t leds;
unsigned char b;
r= sys_vircopy(m->IO_ENDPT, D, (vir_bytes) m->ADDRESS,
if(safecopy) {
r= sys_safecopyfrom(m->IO_ENDPT, (vir_bytes)
m->ADDRESS, 0, (vir_bytes)&leds,
sizeof(leds), D);
} else {
r= sys_vircopy(m->IO_ENDPT, D, (vir_bytes) m->ADDRESS,
SELF, D, (vir_bytes)&leds, sizeof(leds));
}
if (r != OK)
break;
b= 0;
@ -330,8 +363,14 @@ message *m;
kio_bell_t bell;
clock_t ticks;
r= sys_vircopy(m->IO_ENDPT, D, (vir_bytes) m->ADDRESS,
if(safecopy) {
r= sys_safecopyfrom(m->IO_ENDPT, (vir_bytes)
m->ADDRESS, 0, (vir_bytes)&bell,
sizeof(bell), D);
} else {
r= sys_vircopy(m->IO_ENDPT, D, (vir_bytes) m->ADDRESS,
SELF, D, (vir_bytes)&bell, sizeof(bell));
}
if (r != OK)
break;
@ -376,17 +415,23 @@ message *m;
if (n <= 0)
panic("TTY", "kbd_status: bad n", n);
kbdp->req_size= 0;
r= sys_vircopy(SELF, D, (vir_bytes)&kbdp->buf[kbdp->offset],
kbdp->req_proc, D, kbdp->req_addr, n);
if(kbdp->req_safe) {
r= sys_safecopyto(kbdp->req_proc, kbdp->req_addr_g, 0,
(vir_bytes)&kbdp->buf[kbdp->offset], n, D);
} else {
r= sys_vircopy(SELF, D, (vir_bytes)&kbdp->buf[kbdp->offset],
kbdp->req_proc, D, kbdp->req_addr_g, n);
}
if (r == OK)
{
kbdp->offset= (kbdp->offset+n) % KBD_BUFSZ;
kbdp->avail -= n;
r= n;
}
} else printf("copy in revive kbd failed: %d\n", r);
m->m_type = DEV_REVIVE;
m->REP_ENDPT= kbdp->req_proc;
m->REP_IO_GRANT= kbdp->req_addr_g;
m->REP_STATUS= r;
return 1;
}
@ -472,15 +517,18 @@ message *m_ptr;
/* raw scan codes or aux data */
if (kbdp->avail >= KBD_BUFSZ)
{
#if 0
printf("kbd_interrupt: %s buffer is full\n",
isaux ? "kbdaux" : "keyboard");
#endif
return; /* Buffer is full */
}
o= (kbdp->offset + kbdp->avail) % KBD_BUFSZ;
kbdp->buf[o]= scode;
kbdp->avail++;
if (kbdp->req_size)
if (kbdp->req_size) {
notify(kbdp->incaller);
}
if (kbdp->select_ops & SEL_RD)
notify(kbdp->select_proc);
return;
@ -583,14 +631,18 @@ PRIVATE void kbd_send()
if (kbdout.expect_ack)
return;
sys_inb(KB_STATUS, &sb);
if((r=sys_inb(KB_STATUS, &sb)) != OK) {
printf("kbd_send: 1 sys_inb() failed: %d\n", r);
}
if (sb & (KB_OUT_FULL|KB_IN_FULL))
{
printf("not sending 1: sb = 0x%x\n", sb);
return;
}
micro_delay(KBC_IN_DELAY);
sys_inb(KB_STATUS, &sb);
if((r=sys_inb(KB_STATUS, &sb)) != OK) {
printf("kbd_send: 2 sys_inb() failed: %d\n", r);
}
if (sb & (KB_OUT_FULL|KB_IN_FULL))
{
printf("not sending 2: sb = 0x%x\n", sb);
@ -601,7 +653,9 @@ PRIVATE void kbd_send()
#if 0
printf("sending byte 0x%x to keyboard\n", kbdout.buf[kbdout.offset]);
#endif
sys_outb(KEYBD, kbdout.buf[kbdout.offset]);
if((r=sys_outb(KEYBD, kbdout.buf[kbdout.offset])) != OK) {
printf("kbd_send: 3 sys_inb() failed: %d\n", r);
}
kbdout.offset++;
kbdout.avail--;
kbdout.expect_ack= 1;
@ -734,7 +788,8 @@ PRIVATE void kbc_cmd0(cmd)
int cmd;
{
kb_wait();
sys_outb(KB_COMMAND, cmd);
if(sys_outb(KB_COMMAND, cmd) != OK)
printf("kbc_cmd0: sys_outb failed\n");
}
/*===========================================================================*
@ -745,9 +800,11 @@ int cmd;
int data;
{
kb_wait();
sys_outb(KB_COMMAND, cmd);
if(sys_outb(KB_COMMAND, cmd) != OK)
printf("kbc_cmd1: 1 sys_outb failed\n");
kb_wait();
sys_outb(KEYBD, data);
if(sys_outb(KEYBD, data) != OK)
printf("kbc_cmd1: 2 sys_outb failed\n");
}
@ -775,11 +832,13 @@ PRIVATE int kbc_read()
do
#endif
{
sys_inb(KB_STATUS, &st);
if(sys_inb(KB_STATUS, &st) != OK)
printf("kbc_read: 1 sys_inb failed\n");
if (st & KB_OUT_FULL)
{
micro_delay(KBC_IN_DELAY);
sys_inb(KEYBD, &byte);
if(sys_inb(KEYBD, &byte) != OK)
printf("kbc_read: 2 sys_inb failed\n");
if (st & KB_AUX_BYTE)
{
#if DEBUG
@ -819,6 +878,8 @@ PRIVATE int kb_wait()
retries = MAX_KB_BUSY_RETRIES + 1; /* wait until not busy */
do {
s = sys_inb(KB_STATUS, &status);
if(s != OK)
printf("kb_wait: sys_inb failed: %d\n", s);
if (status & KB_OUT_FULL) {
if (scan_keyboard(&byte, &isaux))
{
@ -847,6 +908,8 @@ PRIVATE int kb_ack()
retries = MAX_KB_ACK_RETRIES + 1;
do {
s = sys_inb(KEYBD, &u8val);
if(s != OK)
printf("kb_ack: sys_inb failed: %d\n", s);
if (u8val == KB_ACK)
break; /* wait for ack */
} while(--retries != 0); /* continue unless timeout */
@ -925,14 +988,20 @@ PUBLIC void kb_init_once(void)
/*===========================================================================*
* kbd_loadmap *
*===========================================================================*/
PUBLIC int kbd_loadmap(m)
PUBLIC int kbd_loadmap(m, safe)
message *m;
int safe;
{
/* Load a new keymap. */
int result;
result = sys_vircopy(m->IO_ENDPT, D, (vir_bytes) m->ADDRESS,
if(safe) {
result = sys_safecopyfrom(m->IO_ENDPT, (vir_bytes) m->ADDRESS,
0, (vir_bytes) keymap, (vir_bytes) sizeof(keymap), D);
} else {
result = sys_vircopy(m->IO_ENDPT, D, (vir_bytes) m->ADDRESS,
SELF, D, (vir_bytes) keymap,
(vir_bytes) sizeof(keymap));
}
return(result);
}
@ -1137,30 +1206,35 @@ int *isauxp;
byte_in[0].port = KEYBD; /* get the scan code for the key struck */
byte_in[1].port = PORT_B; /* strobe the keyboard to ack the char */
sys_vinb(byte_in, 2); /* request actual input */
if(sys_vinb(byte_in, 2) != OK) /* request actual input */
printf("scan_keyboard: sys_vinb failed\n");
pv_set(byte_out[0], PORT_B, byte_in[1].value | KBIT); /* strobe bit high */
pv_set(byte_out[1], PORT_B, byte_in[1].value); /* then strobe low */
sys_voutb(byte_out, 2); /* request actual output */
if(sys_voutb(byte_out, 2) != OK) /* request actual output */
printf("scan_keyboard: sys_voutb failed\n");
return(byte_in[0].value); /* return scan code */
#else
unsigned long b, sb;
sys_inb(KB_STATUS, &sb);
if(sys_inb(KB_STATUS, &sb) != OK)
printf("scan_keyboard: sys_inb failed\n");
if (!(sb & KB_OUT_FULL))
{
if (kbdout.avail && !kbdout.expect_ack)
kbd_send();
return 0;
}
sys_inb(KEYBD, &b);
if(sys_inb(KEYBD, &b) != OK)
printf("scan_keyboard: 2 sys_inb failed\n");
#if 0
printf("got byte 0x%x from %s\n", b, (sb & KB_AUX_BYTE) ? "AUX" : "keyboard");
#endif
if (!(sb & KB_AUX_BYTE) && b == KB_ACK && kbdout.expect_ack)
{
#if 1
#if 0
printf("got ACK from keyboard\n");
#endif
kbdout.expect_ack= 0;

View File

@ -36,7 +36,9 @@ typedef struct pty {
char rdsendreply; /* send a reply (instead of notify) */
int rdcaller; /* process making the call (usually FS) */
int rdproc; /* process that wants to read from the pty */
vir_bytes rdvir; /* virtual address in readers address space */
vir_bytes rdvir_g; /* virtual address in readers address space */
vir_bytes rdvir_offset; /* offset in above grant */
int rdsafe; /* safe read mode? */
int rdleft; /* # bytes yet to be read */
int rdcum; /* # bytes written so far */
@ -44,14 +46,16 @@ typedef struct pty {
char wrsendreply; /* send a reply (instead of notify) */
int wrcaller; /* process making the call (usually FS) */
int wrproc; /* process that wants to write to the pty */
vir_bytes wrvir; /* virtual address in writers address space */
vir_bytes wrvir_g; /* virtual address in writers address space */
vir_bytes wrvir_offset; /* offset in above grant */
int wrsafe; /* safe write mode? */
int wrleft; /* # bytes yet to be written */
int wrcum; /* # bytes written so far */
/* Output buffer. */
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 */
char obuf[2048]; /* buffer for bytes going to the pty reader */
/* select() data. */
int select_ops, /* Which operations do we want to know about? */
@ -86,8 +90,12 @@ message *m_ptr;
pty_t *pp = tp->tty_priv;
int r;
phys_bytes p;
int safe = 0;
switch (m_ptr->m_type) {
case DEV_READ_S:
safe=1;
/* fallthrough */
case DEV_READ:
/* Check, store information on the reader, do I/O. */
if (pp->state & TTY_CLOSED) {
@ -114,21 +122,31 @@ message *m_ptr;
pp->rdsendreply = TRUE;
pp->rdcaller = m_ptr->m_source;
pp->rdproc = m_ptr->IO_ENDPT;
pp->rdvir = (vir_bytes) m_ptr->ADDRESS;
pp->rdvir_g = (vir_bytes) m_ptr->ADDRESS;
pp->rdvir_offset = 0;
pp->rdsafe = safe;
pp->rdleft = m_ptr->COUNT;
pty_start(pp);
handle_events(tp);
if (pp->rdleft == 0) return; /* already done */
if (pp->rdleft == 0) {
return; /* already done */
}
#if DEAD_CODE
if (m_ptr->TTY_FLAGS & O_NONBLOCK) {
r = EAGAIN; /* don't suspend */
pp->rdleft = pp->rdcum = 0;
} else {
} else
#endif
{
r = SUSPEND; /* do suspend */
pp->rdsendreply = FALSE;
}
break;
case DEV_WRITE_S:
safe=1;
/* fallthrough */
case DEV_WRITE:
/* Check, store information on the writer, do I/O. */
if (pp->state & TTY_CLOSED) {
@ -156,15 +174,22 @@ message *m_ptr;
pp->wrsendreply = TRUE;
pp->wrcaller = m_ptr->m_source;
pp->wrproc = m_ptr->IO_ENDPT;
pp->wrvir = (vir_bytes) m_ptr->ADDRESS;
pp->wrvir_g = (vir_bytes) m_ptr->ADDRESS;
pp->wrvir_offset = 0;
pp->wrsafe = safe;
pp->wrleft = m_ptr->COUNT;
handle_events(tp);
if (pp->wrleft == 0) return; /* already done */
if (pp->wrleft == 0) {
return; /* already done */
}
#if DEAD_CODE
if (m_ptr->TTY_FLAGS & O_NONBLOCK) { /* don't suspend */
r = pp->wrcum > 0 ? pp->wrcum : EAGAIN;
pp->wrleft = pp->wrcum = 0;
} else {
} else
#endif
{
pp->wrsendreply = FALSE; /* do suspend */
r = SUSPEND;
}
@ -192,15 +217,17 @@ message *m_ptr;
break;
case CANCEL:
r = EINTR;
if (m_ptr->IO_ENDPT == pp->rdproc) {
/* Cancel a read from a PTY. */
r = pp->rdcum > 0 ? pp->rdcum : EAGAIN;
pp->rdleft = pp->rdcum = 0;
}
if (m_ptr->IO_ENDPT == pp->wrproc) {
/* Cancel a write to a PTY. */
r = pp->wrcum > 0 ? pp->wrcum : EAGAIN;
pp->wrleft = pp->wrcum = 0;
}
r = EINTR;
break;
default:
@ -227,9 +254,14 @@ int try;
if (pp->state & PTY_CLOSED) {
if (try) return 1;
if (tp->tty_outleft > 0) {
tty_reply(tp->tty_outrepcode, tp->tty_outcaller,
if(tp->tty_outrepcode == TTY_REVIVE) {
notify(tp->tty_outcaller);
tp->tty_outrevived = 1;
} else {
tty_reply(tp->tty_outrepcode, tp->tty_outcaller,
tp->tty_outproc, EIO);
tp->tty_outleft = tp->tty_outcum = 0;
tp->tty_outleft = tp->tty_outcum = 0;
}
}
return;
}
@ -245,10 +277,16 @@ int try;
break;
/* Copy from user space to the PTY output buffer. */
if ((s = sys_vircopy(tp->tty_outproc, D, (vir_bytes) tp->tty_out_vir,
SELF, D, (vir_bytes) pp->ohead, (phys_bytes) count)) != OK) {
printf("pty tty%d: copy failed (error %d)\n", s);
if(tp->tty_out_safe) {
if ((s = sys_safecopyfrom(tp->tty_outproc, tp->tty_out_vir_g,
tp->tty_out_vir_offset, (vir_bytes) pp->ohead, count, D))!=OK) {
break;
}
} else {
if ((s = sys_vircopy(tp->tty_outproc, D, (vir_bytes) tp->tty_out_vir_g,
SELF, D, (vir_bytes) pp->ohead, (phys_bytes) count)) != OK) {
break;
}
}
/* Perform output processing on the output buffer. */
@ -263,13 +301,21 @@ int try;
if ((pp->ohead += ocount) >= bufend(pp->obuf))
pp->ohead -= buflen(pp->obuf);
pty_start(pp);
tp->tty_out_vir += count;
if(tp->tty_out_safe) tp->tty_out_vir_offset += count;
else tp->tty_out_vir_g += count;
tp->tty_outcum += count;
if ((tp->tty_outleft -= count) == 0) {
/* Output is finished, reply to the writer. */
tty_reply(tp->tty_outrepcode, tp->tty_outcaller,
if(tp->tty_outrepcode == TTY_REVIVE) {
notify(tp->tty_outcaller);
tp->tty_outrevived = 1;
} else {
tty_reply(tp->tty_outrepcode, tp->tty_outcaller,
tp->tty_outproc, tp->tty_outcum);
tp->tty_outcum = 0;
tp->tty_outcum = 0;
}
}
}
pty_finish(pp);
@ -319,16 +365,24 @@ pty_t *pp;
if (count == 0) break;
/* Copy from the output buffer to the readers address space. */
if ((s = sys_vircopy(SELF, D, (vir_bytes)pp->otail,
(vir_bytes) pp->rdproc, D, (vir_bytes) pp->rdvir, (phys_bytes) count)) != OK) {
printf("pty tty%d: copy failed (error %d)\n", s);
if (pp->rdsafe) {
if((s = sys_safecopyto(pp->rdproc, pp->rdvir_g,
pp->rdvir_offset, (vir_bytes) pp->otail, count, D)) != OK) {
break;
}
pp->rdvir_offset += count;
} else {
if ((s = sys_vircopy(SELF, D, (vir_bytes)pp->otail,
(vir_bytes) pp->rdproc, D, (vir_bytes) pp->rdvir_g, (phys_bytes) count)) != OK) {
printf("pty tty: copy failed (error %d)\n", s);
break;
}
pp->rdvir_g += count;
}
/* Bookkeeping. */
pp->ocount -= count;
if ((pp->otail += count) == bufend(pp->obuf)) pp->otail = pp->obuf;
pp->rdvir += count;
pp->rdcum += count;
pp->rdleft -= count;
}
@ -370,9 +424,14 @@ int try;
if (pp->state & PTY_CLOSED) {
if (try) return 1;
if (tp->tty_inleft > 0) {
tty_reply(tp->tty_inrepcode, tp->tty_incaller, tp->tty_inproc,
tp->tty_incum);
tp->tty_inleft = tp->tty_incum = 0;
if(tp->tty_inrepcode == TTY_REVIVE) {
notify(tp->tty_incaller);
tp->tty_inrevived = 1;
} else {
tty_reply(tp->tty_inrepcode, tp->tty_incaller,
tp->tty_inproc, tp->tty_incum);
tp->tty_inleft = tp->tty_incum = 0;
}
}
return 1;
}
@ -387,17 +446,26 @@ int try;
int s;
/* Transfer one character to 'c'. */
if ((s = sys_vircopy(pp->wrproc, D, (vir_bytes) pp->wrvir,
if(pp->wrsafe) {
if ((s = sys_safecopyfrom(pp->wrproc, pp->wrvir_g,
pp->wrvir_offset, (vir_bytes) &c, 1, D)) != OK) {
printf("pty: safecopy failed (error %d)\n", s);
break;
}
pp->wrvir_offset++;
} else {
if ((s = sys_vircopy(pp->wrproc, D, (vir_bytes) pp->wrvir_g,
SELF, D, (vir_bytes) &c, (phys_bytes) 1)) != OK) {
printf("pty: copy failed (error %d)\n", s);
break;
}
pp->wrvir_g++;
}
/* Input processing. */
if (in_process(tp, &c, 1) == 0) break;
/* PTY writer bookkeeping. */
pp->wrvir++;
pp->wrcum++;
if (--pp->wrleft == 0) {
if (pp->wrsendreply) {
@ -447,7 +515,6 @@ int try;
pty_t *pp = tp->tty_priv;
if (pp->wrleft > 0) {
assert(!pp->wrsendreply);
pp->wrcum += pp->wrleft;
pp->wrleft= 0;
notify(pp->wrcaller);
@ -512,6 +579,7 @@ PUBLIC int pty_status(message *m_ptr)
{
m_ptr->m_type = DEV_REVIVE;
m_ptr->REP_ENDPT = pp->rdproc;
m_ptr->REP_IO_GRANT = pp->rdvir_g;
m_ptr->REP_STATUS = pp->rdcum;
pp->rdleft = pp->rdcum = 0;
@ -525,6 +593,7 @@ PUBLIC int pty_status(message *m_ptr)
{
m_ptr->m_type = DEV_REVIVE;
m_ptr->REP_ENDPT = pp->wrproc;
m_ptr->REP_IO_GRANT = pp->wrvir_g;
if (pp->wrcum == 0)
m_ptr->REP_STATUS = EIO;
else

View File

@ -321,8 +321,13 @@ int try;
if (try) return 1;
/* Copy from user space to the RS232 output buffer. */
sys_vircopy(tp->tty_outproc, D, (vir_bytes) tp->tty_out_vir,
if(tp->tty_out_safe) {
sys_safecopyfrom(tp->tty_outproc, tp->tty_out_vir_g,
tp->tty_out_vir_offset, (vir_bytes) rs->ohead, count, D);
} else {
sys_vircopy(tp->tty_outproc, D, (vir_bytes) tp->tty_out_vir_g,
SELF, D, (vir_bytes) rs->ohead, (phys_bytes) count);
}
/* Perform output processing on the output buffer. */
out_process(tp, rs->obuf, rs->ohead, bufend(rs->obuf), &count, &ocount);
@ -338,7 +343,11 @@ int try;
unlock();
if ((rs->ohead += ocount) >= bufend(rs->obuf))
rs->ohead -= buflen(rs->obuf);
tp->tty_out_vir += count;
if(tp->tty_out_safe) {
tp->tty_out_vir_offset += count;
} else {
tp->tty_out_vir_g += count;
}
tp->tty_outcum += count;
if ((tp->tty_outleft -= count) == 0) {
/* Output is finished, reply to the writer. */

View File

@ -29,26 +29,26 @@
* DEV_STATUS: FS wants to know status for SELECT or REVIVE
* CANCEL: terminate a previous incomplete system call immediately
*
* m_type TTY_LINE IO_ENDPT COUNT TTY_SPEK TTY_FLAGS ADDRESS
* ---------------------------------------------------------------------------
* | HARD_INT | | | | | | |
* |-------------+---------+---------+---------+---------+---------+---------|
* | SYS_SIG | sig set | | | | | |
* |-------------+---------+---------+---------+---------+---------+---------|
* | DEV_READ |minor dev| proc nr | count | O_NONBLOCK| buf ptr |
* |-------------+---------+---------+---------+---------+---------+---------|
* | DEV_WRITE |minor dev| proc nr | count | | | buf ptr |
* |-------------+---------+---------+---------+---------+---------+---------|
* | DEV_IOCTL |minor dev| proc nr |func code|erase etc| flags | |
* |-------------+---------+---------+---------+---------+---------+---------|
* | DEV_OPEN |minor dev| proc nr | O_NOCTTY| | | |
* |-------------+---------+---------+---------+---------+---------+---------|
* | DEV_CLOSE |minor dev| proc nr | | | | |
* |-------------+---------+---------+---------+---------+---------+---------|
* | DEV_STATUS | | | | | | |
* |-------------+---------+---------+---------+---------+---------+---------|
* | CANCEL |minor dev| proc nr | | | | |
* ---------------------------------------------------------------------------
* m_type TTY_LINE IO_ENDPT COUNT TTY_SPEKS ADDRESS
* -----------------------------------------------------------------
* | HARD_INT | | | | | |
* |-------------+---------+---------+---------+---------+---------|
* | SYS_SIG | sig set | | | | |
* |-------------+---------+---------+---------+---------+---------|
* | DEV_READ |minor dev| proc nr | count | | buf ptr |
* |-------------+---------+---------+---------+---------+---------|
* | DEV_WRITE |minor dev| proc nr | count | | buf ptr |
* |-------------+---------+---------+---------+---------+---------|
* | DEV_IOCTL |minor dev| proc nr |func code|erase etc| |
* |-------------+---------+---------+---------+---------+---------|
* | DEV_OPEN |minor dev| proc nr | O_NOCTTY| | |
* |-------------+---------+---------+---------+---------+---------|
* | DEV_CLOSE |minor dev| proc nr | | | |
* |-------------+---------+---------+---------+---------+---------|
* | DEV_STATUS | | | | | |
* |-------------+---------+---------+---------+---------+---------|
* | CANCEL |minor dev| proc nr | | | |
* -----------------------------------------------------------------
*
* Changes:
* Jan 20, 2004 moved TTY driver to user-space (Jorrit N. Herder)
@ -58,9 +58,6 @@
#include "../drivers.h"
#include <termios.h>
#if ENABLE_SRCCOMPAT || ENABLE_BINCOMPAT
#include <sgtty.h>
#endif
#include <sys/ioc_tty.h>
#include <signal.h>
#include <minix/callnr.h>
@ -106,11 +103,11 @@ FORWARD _PROTOTYPE( void tty_timed_out, (timer_t *tp) );
FORWARD _PROTOTYPE( void expire_timers, (void) );
FORWARD _PROTOTYPE( void settimer, (tty_t *tty_ptr, int enable) );
FORWARD _PROTOTYPE( void do_cancel, (tty_t *tp, message *m_ptr) );
FORWARD _PROTOTYPE( void do_ioctl, (tty_t *tp, message *m_ptr) );
FORWARD _PROTOTYPE( void do_ioctl, (tty_t *tp, message *m_ptr, int s) );
FORWARD _PROTOTYPE( void do_open, (tty_t *tp, message *m_ptr) );
FORWARD _PROTOTYPE( void do_close, (tty_t *tp, message *m_ptr) );
FORWARD _PROTOTYPE( void do_read, (tty_t *tp, message *m_ptr) );
FORWARD _PROTOTYPE( void do_write, (tty_t *tp, message *m_ptr) );
FORWARD _PROTOTYPE( void do_read, (tty_t *tp, message *m_ptr, int s) );
FORWARD _PROTOTYPE( void do_write, (tty_t *tp, message *m_ptr, int s) );
FORWARD _PROTOTYPE( void do_select, (tty_t *tp, message *m_ptr) );
FORWARD _PROTOTYPE( void do_status, (message *m_ptr) );
FORWARD _PROTOTYPE( void in_transfer, (tty_t *tp) );
@ -122,17 +119,6 @@ FORWARD _PROTOTYPE( void dev_ioctl, (tty_t *tp) );
FORWARD _PROTOTYPE( void setattr, (tty_t *tp) );
FORWARD _PROTOTYPE( void tty_icancel, (tty_t *tp) );
FORWARD _PROTOTYPE( void tty_init, (void) );
#if ENABLE_SRCCOMPAT || ENABLE_BINCOMPAT
FORWARD _PROTOTYPE( int compat_getp, (tty_t *tp, struct sgttyb *sg) );
FORWARD _PROTOTYPE( int compat_getc, (tty_t *tp, struct tchars *sg) );
FORWARD _PROTOTYPE( int compat_setp, (tty_t *tp, struct sgttyb *sg) );
FORWARD _PROTOTYPE( int compat_setc, (tty_t *tp, struct tchars *sg) );
FORWARD _PROTOTYPE( int tspd2sgspd, (speed_t tspd) );
FORWARD _PROTOTYPE( speed_t sgspd2tspd, (int sgspd) );
#if ENABLE_BINCOMPAT
FORWARD _PROTOTYPE( void do_ioctl_compat, (tty_t *tp, message *m_ptr) );
#endif
#endif
/* Default attributes. */
PRIVATE struct termios termios_defaults = {
@ -165,17 +151,6 @@ PUBLIC void main(void)
register struct proc *rp;
register tty_t *tp;
#if DEBUG
kputc('H');
kputc('e');
kputc('l');
kputc('l');
kputc('o');
kputc(',');
kputc(' ');
printf("TTY\n");
#endif
/* Get kernel environment (protected_mode, pc_at and ega are needed). */
if (OK != (s=sys_getmachine(&machine))) {
panic("TTY","Couldn't obtain kernel environment.", s);
@ -229,13 +204,6 @@ PUBLIC void main(void)
}
case PROC_EVENT: {
cons_stop(); /* switch to primary console */
printf("TTY got PROC_EVENT, assuming SIGTERM\n");
#if DEAD_CODE
if (irq_hook_id != -1) {
sys_irqdisable(&irq_hook_id);
sys_irqrmpolicy(KEYBOARD_IRQ, &irq_hook_id);
}
#endif
continue;
}
case SYS_SIG: { /* system signal */
@ -244,7 +212,10 @@ PUBLIC void main(void)
continue;
}
case DIAGNOSTICS: /* a server wants to print some */
do_diagnostics(&tty_mess);
do_diagnostics(&tty_mess, 0);
continue;
case DIAGNOSTICS_S:
do_diagnostics(&tty_mess, 1);
continue;
case GET_KMESS:
do_get_kmess(&tty_mess);
@ -284,7 +255,8 @@ PUBLIC void main(void)
tp = tty_addr(line - TTYPX_MINOR + NR_CONS + NR_RS_LINES);
} else if ((line - PTYPX_MINOR) < NR_PTYS) {
tp = tty_addr(line - PTYPX_MINOR + NR_CONS + NR_RS_LINES);
if (tty_mess.m_type != DEV_IOCTL) {
if (tty_mess.m_type != DEV_IOCTL &&
tty_mess.m_type != DEV_IOCTL_S) {
do_pty(tp, &tty_mess);
continue;
}
@ -306,9 +278,12 @@ PUBLIC void main(void)
/* Execute the requested device driver function. */
switch (tty_mess.m_type) {
case DEV_READ: do_read(tp, &tty_mess); break;
case DEV_WRITE: do_write(tp, &tty_mess); break;
case DEV_IOCTL: do_ioctl(tp, &tty_mess); break;
case DEV_READ: do_read(tp, &tty_mess, 0); break;
case DEV_READ_S: do_read(tp, &tty_mess, 1); break;
case DEV_WRITE: do_write(tp, &tty_mess, 0); break;
case DEV_WRITE_S: do_write(tp, &tty_mess, 1); break;
case DEV_IOCTL: do_ioctl(tp, &tty_mess, 0); break;
case DEV_IOCTL_S: do_ioctl(tp, &tty_mess, 1); break;
case DEV_OPEN: do_open(tp, &tty_mess); break;
case DEV_CLOSE: do_close(tp, &tty_mess); break;
case DEV_SELECT: do_select(tp, &tty_mess); break;
@ -356,6 +331,7 @@ message *m_ptr;
/* Suspended request finished. Send a REVIVE. */
m_ptr->m_type = DEV_REVIVE;
m_ptr->REP_ENDPT = tp->tty_inproc;
m_ptr->REP_IO_GRANT = tp->tty_in_vir_g;
m_ptr->REP_STATUS = tp->tty_incum;
tp->tty_inleft = tp->tty_incum = 0;
@ -368,6 +344,7 @@ message *m_ptr;
/* Suspended request finished. Send a REVIVE. */
m_ptr->m_type = DEV_REVIVE;
m_ptr->REP_ENDPT = tp->tty_outproc;
m_ptr->REP_IO_GRANT = tp->tty_out_vir_g;
m_ptr->REP_STATUS = tp->tty_outcum;
tp->tty_outcum = 0;
@ -375,6 +352,16 @@ message *m_ptr;
event_found = 1;
break;
}
else if (tp->tty_iorevived && tp->tty_iocaller == m_ptr->m_source) {
/* Suspended request finished. Send a REVIVE. */
m_ptr->m_type = DEV_REVIVE;
m_ptr->REP_ENDPT = tp->tty_ioproc;
m_ptr->REP_IO_GRANT = tp->tty_iovir_g;
m_ptr->REP_STATUS = tp->tty_iostatus;
tp->tty_iorevived = 0; /* unmark revive event */
event_found = 1;
break;
}
}
#if NR_PTYS > 0
@ -398,36 +385,30 @@ message *m_ptr;
/*===========================================================================*
* do_read *
*===========================================================================*/
PRIVATE void do_read(tp, m_ptr)
PRIVATE void do_read(tp, m_ptr, safe)
register tty_t *tp; /* pointer to tty struct */
register message *m_ptr; /* pointer to message sent to the task */
int safe; /* use safecopies? */
{
/* A process wants to read from a terminal. */
int r, status;
phys_bytes phys_addr;
int more_verbose= (tp == tty_addr(NR_CONS));
/* Check if there is already a process hanging in a read, check if the
* parameters are correct, do I/O.
*/
if (tp->tty_inleft > 0) {
if (more_verbose) printf("do_read: EIO\n");
r = EIO;
} else
if (m_ptr->COUNT <= 0) {
if (more_verbose) printf("do_read: EINVAL\n");
r = EINVAL;
} else
if (sys_umap(m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS, m_ptr->COUNT,
&phys_addr) != OK) {
if (more_verbose) printf("do_read: EFAULT\n");
r = EFAULT;
} else {
/* Copy information from the message to the tty struct. */
tp->tty_inrepcode = TASK_REPLY;
tp->tty_incaller = m_ptr->m_source;
tp->tty_inproc = m_ptr->IO_ENDPT;
tp->tty_in_vir = (vir_bytes) m_ptr->ADDRESS;
tp->tty_in_vir_g = (vir_bytes) m_ptr->ADDRESS;
tp->tty_in_vir_offset = 0;
tp->tty_in_safe = safe;
tp->tty_inleft = m_ptr->COUNT;
if (!(tp->tty_termios.c_lflag & ICANON)
@ -459,18 +440,12 @@ register message *m_ptr; /* pointer to message sent to the task */
return; /* already done */
}
/* There were no bytes in the input queue available, so either suspend
* the caller or break off the read if nonblocking.
/* There were no bytes in the input queue available, so suspend
* the caller.
*/
if (m_ptr->TTY_FLAGS & O_NONBLOCK) {
r = EAGAIN; /* cancel the read */
tp->tty_inleft = tp->tty_incum = 0;
} else {
r = SUSPEND; /* suspend the caller */
tp->tty_inrepcode = REVIVE;
}
r = SUSPEND; /* suspend the caller */
tp->tty_inrepcode = TTY_REVIVE;
}
if (more_verbose) printf("do_read: replying %d\n", r);
tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, r);
if (tp->tty_select_ops)
select_retry(tp);
@ -479,13 +454,13 @@ register message *m_ptr; /* pointer to message sent to the task */
/*===========================================================================*
* do_write *
*===========================================================================*/
PRIVATE void do_write(tp, m_ptr)
PRIVATE void do_write(tp, m_ptr, safe)
register tty_t *tp;
register message *m_ptr; /* pointer to message sent to the task */
int safe;
{
/* A process wants to write on a terminal. */
int r;
phys_bytes phys_addr;
/* Check if there is already a process hanging in a write, check if the
* parameters are correct, do I/O.
@ -495,16 +470,14 @@ register message *m_ptr; /* pointer to message sent to the task */
} else
if (m_ptr->COUNT <= 0) {
r = EINVAL;
} else
if (sys_umap(m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS, m_ptr->COUNT,
&phys_addr) != OK) {
r = EFAULT;
} else {
/* Copy message parameters to the tty structure. */
tp->tty_outrepcode = TASK_REPLY;
tp->tty_outcaller = m_ptr->m_source;
tp->tty_outproc = m_ptr->IO_ENDPT;
tp->tty_out_vir = (vir_bytes) m_ptr->ADDRESS;
tp->tty_out_vir_g = (vir_bytes) m_ptr->ADDRESS;
tp->tty_out_vir_offset = 0;
tp->tty_out_safe = safe;
tp->tty_outleft = m_ptr->COUNT;
/* Try to write. */
@ -512,16 +485,11 @@ register message *m_ptr; /* pointer to message sent to the task */
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.
/* None or not all the bytes could be written, so suspend the
* caller.
*/
if (m_ptr->TTY_FLAGS & O_NONBLOCK) { /* cancel the write */
r = tp->tty_outcum > 0 ? tp->tty_outcum : EAGAIN;
tp->tty_outleft = tp->tty_outcum = 0;
} else {
r = SUSPEND; /* suspend the caller */
tp->tty_outrepcode = REVIVE;
}
r = SUSPEND; /* suspend the caller */
tp->tty_outrepcode = TTY_REVIVE;
}
tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, r);
}
@ -529,9 +497,10 @@ register message *m_ptr; /* pointer to message sent to the task */
/*===========================================================================*
* do_ioctl *
*===========================================================================*/
PRIVATE void do_ioctl(tp, m_ptr)
PRIVATE void do_ioctl(tp, m_ptr, safe)
register tty_t *tp;
message *m_ptr; /* pointer to message sent to task */
int safe;
{
/* Perform an IOCTL on this terminal. Posix termios calls are handled
* by the IOCTL system call
@ -540,10 +509,6 @@ message *m_ptr; /* pointer to message sent to task */
int r;
union {
int i;
#if ENABLE_SRCCOMPAT
struct sgttyb sg;
struct tchars tc;
#endif
} param;
size_t size;
@ -569,17 +534,6 @@ message *m_ptr; /* pointer to message sent to task */
size = sizeof(struct winsize);
break;
#if ENABLE_SRCCOMPAT
case TIOCGETP: /* BSD-style get terminal properties */
case TIOCSETP: /* BSD-style set terminal properties */
size = sizeof(struct sgttyb);
break;
case TIOCGETC: /* BSD-style get terminal special characters */
case TIOCSETC: /* BSD-style get terminal special characters */
size = sizeof(struct tchars);
break;
#endif
#if (MACHINE == IBM_PC)
case KIOCSMAP: /* load keymap (Minix extension) */
size = sizeof(keymap_t);
@ -598,9 +552,14 @@ message *m_ptr; /* pointer to message sent to task */
switch (m_ptr->TTY_REQUEST) {
case TCGETS:
/* Get the termios attributes. */
r = sys_vircopy(SELF, D, (vir_bytes) &tp->tty_termios,
if(safe) {
r = sys_safecopyto(m_ptr->IO_ENDPT, (vir_bytes) m_ptr->ADDRESS, 0,
(vir_bytes) &tp->tty_termios, (vir_bytes) size, D);
} else {
r = sys_vircopy(SELF, D, (vir_bytes) &tp->tty_termios,
m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS,
(vir_bytes) size);
}
break;
case TCSETSW:
@ -611,7 +570,8 @@ message *m_ptr; /* pointer to message sent to task */
tp->tty_iocaller = m_ptr->m_source;
tp->tty_ioproc = m_ptr->IO_ENDPT;
tp->tty_ioreq = m_ptr->REQUEST;
tp->tty_iovir = (vir_bytes) m_ptr->ADDRESS;
tp->tty_iovir_g = (vir_bytes) m_ptr->ADDRESS;
tp->tty_io_safe = safe;
r = SUSPEND;
break;
}
@ -620,15 +580,25 @@ message *m_ptr; /* pointer to message sent to task */
/*FALL THROUGH*/
case TCSETS:
/* Set the termios attributes. */
r = sys_vircopy( m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS,
SELF, D, (vir_bytes) &tp->tty_termios, (vir_bytes) size);
if(safe) {
r = sys_safecopyfrom(m_ptr->IO_ENDPT, (vir_bytes) m_ptr->ADDRESS, 0,
(vir_bytes) &tp->tty_termios, (vir_bytes) size, D);
} else {
r = sys_vircopy( m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS,
SELF, D, (vir_bytes) &tp->tty_termios, (vir_bytes) size);
}
if (r != OK) break;
setattr(tp);
break;
case TCFLSH:
r = sys_vircopy( m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS,
if(safe) {
r = sys_safecopyfrom(m_ptr->IO_ENDPT, (vir_bytes) m_ptr->ADDRESS, 0,
(vir_bytes) &param.i, (vir_bytes) size, D);
} else {
r = sys_vircopy(m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS,
SELF, D, (vir_bytes) &param.i, (vir_bytes) size);
}
if (r != OK) break;
switch (param.i) {
case TCIFLUSH: tty_icancel(tp); break;
@ -639,8 +609,13 @@ message *m_ptr; /* pointer to message sent to task */
break;
case TCFLOW:
r = sys_vircopy( m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS,
if(safe) {
r = sys_safecopyfrom(m_ptr->IO_ENDPT, (vir_bytes) m_ptr->ADDRESS, 0,
(vir_bytes) &param.i, (vir_bytes) size, D);
} else {
r = sys_vircopy( m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS,
SELF, D, (vir_bytes) &param.i, (vir_bytes) size);
}
if (r != OK) break;
switch (param.i) {
case TCOOFF:
@ -664,51 +639,31 @@ message *m_ptr; /* pointer to message sent to task */
break;
case TIOCGWINSZ:
r = sys_vircopy(SELF, D, (vir_bytes) &tp->tty_winsize,
if(safe) {
r = sys_safecopyto(m_ptr->IO_ENDPT, (vir_bytes) m_ptr->ADDRESS, 0,
(vir_bytes) &tp->tty_winsize, (vir_bytes) size, D);
} else {
r = sys_vircopy(SELF, D, (vir_bytes) &tp->tty_winsize,
m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS,
(vir_bytes) size);
}
break;
case TIOCSWINSZ:
r = sys_vircopy( m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS,
if(safe) {
r = sys_safecopyfrom(m_ptr->IO_ENDPT, (vir_bytes) m_ptr->ADDRESS, 0,
(vir_bytes) &tp->tty_winsize, (vir_bytes) size, D);
} else {
r = sys_vircopy( m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS,
SELF, D, (vir_bytes) &tp->tty_winsize, (vir_bytes) size);
}
sigchar(tp, SIGWINCH);
break;
#if ENABLE_SRCCOMPAT
case TIOCGETP:
compat_getp(tp, &param.sg);
r = sys_vircopy(SELF, D, (vir_bytes) &param.sg,
m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS,
(vir_bytes) size);
break;
case TIOCSETP:
r = sys_vircopy( m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS,
SELF, D, (vir_bytes) &param.sg, (vir_bytes) size);
if (r != OK) break;
compat_setp(tp, &param.sg);
break;
case TIOCGETC:
compat_getc(tp, &param.tc);
r = sys_vircopy(SELF, D, (vir_bytes) &param.tc,
m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS,
(vir_bytes) size);
break;
case TIOCSETC:
r = sys_vircopy( m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS,
SELF, D, (vir_bytes) &param.tc, (vir_bytes) size);
if (r != OK) break;
compat_setc(tp, &param.tc);
break;
#endif
#if (MACHINE == IBM_PC)
case KIOCSMAP:
/* Load a new keymap (only /dev/console). */
if (isconsole(tp)) r = kbd_loadmap(m_ptr);
if (isconsole(tp)) r = kbd_loadmap(m_ptr, safe);
break;
case TIOCSFON:
@ -729,12 +684,7 @@ message *m_ptr; /* pointer to message sent to task */
case TIOCGPGRP:
case TIOCSPGRP:
default:
#if ENABLE_BINCOMPAT
do_ioctl_compat(tp, m_ptr);
return;
#else
r = ENOTTY;
#endif
}
/* Send the reply. */
@ -801,26 +751,33 @@ message *m_ptr; /* pointer to message sent to task */
int proc_nr;
int mode;
int r = EINTR;
/* Check the parameters carefully, to avoid cancelling twice. */
proc_nr = m_ptr->IO_ENDPT;
mode = m_ptr->COUNT;
if ((mode & R_BIT) && tp->tty_inleft != 0 && proc_nr == tp->tty_inproc) {
if ((mode & R_BIT) && tp->tty_inleft != 0 && proc_nr == tp->tty_inproc &&
(!tp->tty_in_safe || tp->tty_in_vir_g==(vir_bytes)m_ptr->IO_GRANT)) {
/* Process was reading when killed. Clean up input. */
tty_icancel(tp);
tp->tty_inleft = tp->tty_incum = 0;
}
if ((mode & W_BIT) && tp->tty_outleft != 0 && proc_nr == tp->tty_outproc) {
tty_icancel(tp);
r = tp->tty_incum > 0 ? tp->tty_incum : EAGAIN;
tp->tty_inleft = tp->tty_incum = tp->tty_inrevived = 0;
}
if ((mode & W_BIT) && tp->tty_outleft != 0 && proc_nr == tp->tty_outproc &&
(!tp->tty_out_safe || tp->tty_out_vir_g==(vir_bytes)m_ptr->IO_GRANT)) {
/* Process was writing when killed. Clean up output. */
(*tp->tty_ocancel)(tp, 0);
tp->tty_outleft = tp->tty_outcum = 0;
}
#if DEAD_CODE
(*tp->tty_ocancel)(tp, 0);
#endif
r = tp->tty_outcum > 0 ? tp->tty_outcum : EAGAIN;
tp->tty_outleft = tp->tty_outcum = tp->tty_outrevived = 0;
}
if (tp->tty_ioreq != 0 && proc_nr == tp->tty_ioproc) {
/* Process was waiting for output to drain. */
tp->tty_ioreq = 0;
}
tp->tty_events = 1;
tty_reply(TASK_REPLY, m_ptr->m_source, proc_nr, EINTR);
tty_reply(TASK_REPLY, m_ptr->m_source, proc_nr, r);
}
PUBLIC int select_try(struct tty *tp, int ops)
@ -905,7 +862,7 @@ tty_t *tp; /* TTY to check for events. */
/* Reply if enough bytes are available. */
if (tp->tty_incum >= tp->tty_min && tp->tty_inleft > 0) {
if (tp->tty_inrepcode == REVIVE) {
if (tp->tty_inrepcode == TTY_REVIVE) {
notify(tp->tty_incaller);
tp->tty_inrevived = 1;
} else {
@ -952,10 +909,18 @@ register tty_t *tp; /* pointer to terminal to read from */
tp->tty_inleft--;
if (++bp == bufend(buf)) {
/* Temp buffer full, copy to user space. */
sys_vircopy(SELF, D, (vir_bytes) buf,
tp->tty_inproc, D, tp->tty_in_vir,
(vir_bytes) buflen(buf));
tp->tty_in_vir += buflen(buf);
if(tp->tty_in_safe) {
sys_safecopyto(tp->tty_inproc,
tp->tty_in_vir_g, tp->tty_in_vir_offset,
(vir_bytes) buf,
(vir_bytes) buflen(buf), D);
tp->tty_in_vir_offset += buflen(buf);
} else {
sys_vircopy(SELF, D, (vir_bytes) buf,
tp->tty_inproc, D, tp->tty_in_vir_g,
(vir_bytes) buflen(buf));
tp->tty_in_vir_g += buflen(buf);
}
tp->tty_incum += buflen(buf);
bp = buf;
}
@ -975,15 +940,22 @@ register tty_t *tp; /* pointer to terminal to read from */
if (bp > buf) {
/* Leftover characters in the buffer. */
count = bp - buf;
sys_vircopy(SELF, D, (vir_bytes) buf,
tp->tty_inproc, D, tp->tty_in_vir, (vir_bytes) count);
tp->tty_in_vir += count;
if(tp->tty_in_safe) {
sys_safecopyto(tp->tty_inproc,
tp->tty_in_vir_g, tp->tty_in_vir_offset,
(vir_bytes) buf, (vir_bytes) count, D);
tp->tty_in_vir_offset += count;
} else {
sys_vircopy(SELF, D, (vir_bytes) buf,
tp->tty_inproc, D, tp->tty_in_vir_g, (vir_bytes) count);
tp->tty_in_vir_g += count;
}
tp->tty_incum += count;
}
/* Usually reply to the reader, possibly even if incum == 0 (EOF). */
if (tp->tty_inleft == 0) {
if (tp->tty_inrepcode == REVIVE) {
if (tp->tty_inrepcode == TTY_REVIVE) {
notify(tp->tty_incaller);
tp->tty_inrevived = 1;
} else {
@ -1398,13 +1370,21 @@ tty_t *tp;
if (tp->tty_ioreq != TCDRAIN) {
if (tp->tty_ioreq == TCSETSF) tty_icancel(tp);
result = sys_vircopy(tp->tty_ioproc, D, tp->tty_iovir,
if(tp->tty_io_safe) {
result = sys_safecopyfrom(tp->tty_ioproc, tp->tty_iovir_g, 0,
(vir_bytes) &tp->tty_termios,
(vir_bytes) sizeof(tp->tty_termios), D);
} else {
result = sys_vircopy(tp->tty_ioproc, D, tp->tty_iovir_g,
SELF, D, (vir_bytes) &tp->tty_termios,
(vir_bytes) sizeof(tp->tty_termios));
}
setattr(tp);
}
tp->tty_ioreq = 0;
tty_reply(REVIVE, tp->tty_iocaller, tp->tty_ioproc, result);
notify(tp->tty_iocaller);
tp->tty_iorevived = 1;
tp->tty_iostatus = result;
}
/*===========================================================================*
@ -1463,7 +1443,11 @@ tty_t *tp;
/*===========================================================================*
* tty_reply *
*===========================================================================*/
PUBLIC void tty_reply(code, replyee, proc_nr, status)
PUBLIC void
tty_reply_f(
file, line, code, replyee, proc_nr, status)
char *file;
int line;
int code; /* TASK_REPLY or REVIVE */
int replyee; /* destination address for the reply */
int proc_nr; /* to whom should the reply go? */
@ -1476,8 +1460,17 @@ int status; /* reply code */
tty_mess.REP_ENDPT = proc_nr;
tty_mess.REP_STATUS = status;
/* TTY is not supposed to send a TTY_REVIVE message. The
* REVIVE message is gone, TTY_REVIVE is only used as an internal
* placeholder for something that is not supposed to be a message.
*/
if(code == TTY_REVIVE) {
panicing = 1;
printf("%s:%d: ", file, line);
panic("TTY","tty_reply sending TTY_REVIVE", NO_NUM);
}
if ((status = send(replyee, &tty_mess)) != OK) {
printf("TTY: couldn't reply to %d\n", replyee);
panic("TTY","tty_reply failed, status\n", status);
}
}
@ -1496,9 +1489,11 @@ int sig; /* SIGINT, SIGQUIT, SIGKILL or SIGHUP */
*/
int status;
if (tp->tty_pgrp != 0)
if (OK != (status = sys_kill(tp->tty_pgrp, sig)))
if (tp->tty_pgrp != 0) {
if (OK != (status = sys_kill(tp->tty_pgrp, sig))) {
panic("TTY","Error, call to sys_kill failed", status);
}
}
if (!(tp->tty_termios.c_lflag & NOFLSH)) {
tp->tty_incount = tp->tty_eotct = 0; /* kill earlier input */
@ -1685,341 +1680,3 @@ register message *m_ptr; /* pointer to message sent to the task */
return;
}
#if ENABLE_SRCCOMPAT || ENABLE_BINCOMPAT
/*===========================================================================*
* compat_getp *
*===========================================================================*/
PRIVATE int compat_getp(tp, sg)
tty_t *tp;
struct sgttyb *sg;
{
/* Translate an old TIOCGETP to the termios equivalent. */
int flgs;
sg->sg_erase = tp->tty_termios.c_cc[VERASE];
sg->sg_kill = tp->tty_termios.c_cc[VKILL];
sg->sg_ospeed = tspd2sgspd(cfgetospeed(&tp->tty_termios));
sg->sg_ispeed = tspd2sgspd(cfgetispeed(&tp->tty_termios));
flgs = 0;
/* XTABS - if OPOST and XTABS */
if ((tp->tty_termios.c_oflag & (OPOST|XTABS)) == (OPOST|XTABS))
flgs |= 0006000;
/* BITS5..BITS8 - map directly to CS5..CS8 */
flgs |= (tp->tty_termios.c_cflag & CSIZE) << (8-2);
/* EVENP - if PARENB and not PARODD */
if ((tp->tty_termios.c_cflag & (PARENB|PARODD)) == PARENB)
flgs |= 0000200;
/* ODDP - if PARENB and PARODD */
if ((tp->tty_termios.c_cflag & (PARENB|PARODD)) == (PARENB|PARODD))
flgs |= 0000100;
/* RAW - if not ICANON and not ISIG */
if (!(tp->tty_termios.c_lflag & (ICANON|ISIG)))
flgs |= 0000040;
/* CRMOD - if ICRNL */
if (tp->tty_termios.c_iflag & ICRNL)
flgs |= 0000020;
/* ECHO - if ECHO */
if (tp->tty_termios.c_lflag & ECHO)
flgs |= 0000010;
/* CBREAK - if not ICANON and ISIG */
if ((tp->tty_termios.c_lflag & (ICANON|ISIG)) == ISIG)
flgs |= 0000002;
sg->sg_flags = flgs;
return(OK);
}
/*===========================================================================*
* compat_getc *
*===========================================================================*/
PRIVATE int compat_getc(tp, tc)
tty_t *tp;
struct tchars *tc;
{
/* Translate an old TIOCGETC to the termios equivalent. */
tc->t_intrc = tp->tty_termios.c_cc[VINTR];
tc->t_quitc = tp->tty_termios.c_cc[VQUIT];
tc->t_startc = tp->tty_termios.c_cc[VSTART];
tc->t_stopc = tp->tty_termios.c_cc[VSTOP];
tc->t_brkc = tp->tty_termios.c_cc[VEOL];
tc->t_eofc = tp->tty_termios.c_cc[VEOF];
return(OK);
}
/*===========================================================================*
* compat_setp *
*===========================================================================*/
PRIVATE int compat_setp(tp, sg)
tty_t *tp;
struct sgttyb *sg;
{
/* Translate an old TIOCSETP to the termios equivalent. */
struct termios termios;
int flags;
termios = tp->tty_termios;
termios.c_cc[VERASE] = sg->sg_erase;
termios.c_cc[VKILL] = sg->sg_kill;
cfsetispeed(&termios, sgspd2tspd(sg->sg_ispeed & BYTE));
cfsetospeed(&termios, sgspd2tspd(sg->sg_ospeed & BYTE));
flags = sg->sg_flags;
/* Input flags */
/* BRKINT - not changed */
/* ICRNL - set if CRMOD is set and not RAW */
/* (CRMOD also controls output) */
termios.c_iflag &= ~ICRNL;
if ((flags & 0000020) && !(flags & 0000040))
termios.c_iflag |= ICRNL;
/* IGNBRK - not changed */
/* IGNCR - forced off (ignoring cr's is not supported) */
termios.c_iflag &= ~IGNCR;
/* IGNPAR - not changed */
/* INLCR - forced off (mapping nl's to cr's is not supported) */
termios.c_iflag &= ~INLCR;
/* INPCK - not changed */
/* ISTRIP - not changed */
/* IXOFF - not changed */
/* IXON - forced on if not RAW */
termios.c_iflag &= ~IXON;
if (!(flags & 0000040))
termios.c_iflag |= IXON;
/* PARMRK - not changed */
/* Output flags */
/* OPOST - forced on if not RAW */
termios.c_oflag &= ~OPOST;
if (!(flags & 0000040))
termios.c_oflag |= OPOST;
/* ONLCR - forced on if CRMOD */
termios.c_oflag &= ~ONLCR;
if (flags & 0000020)
termios.c_oflag |= ONLCR;
/* XTABS - forced on if XTABS */
termios.c_oflag &= ~XTABS;
if (flags & 0006000)
termios.c_oflag |= XTABS;
/* CLOCAL - not changed */
/* CREAD - forced on (receiver is always enabled) */
termios.c_cflag |= CREAD;
/* CSIZE - CS5-CS8 correspond directly to BITS5-BITS8 */
termios.c_cflag = (termios.c_cflag & ~CSIZE) | ((flags & 0001400) >> (8-2));
/* CSTOPB - not changed */
/* HUPCL - not changed */
/* PARENB - set if EVENP or ODDP is set */
termios.c_cflag &= ~PARENB;
if (flags & (0000200|0000100))
termios.c_cflag |= PARENB;
/* PARODD - set if ODDP is set */
termios.c_cflag &= ~PARODD;
if (flags & 0000100)
termios.c_cflag |= PARODD;
/* Local flags */
/* ECHO - set if ECHO is set */
termios.c_lflag &= ~ECHO;
if (flags & 0000010)
termios.c_lflag |= ECHO;
/* ECHOE - not changed */
/* ECHOK - not changed */
/* ECHONL - not changed */
/* ICANON - set if neither CBREAK nor RAW */
termios.c_lflag &= ~ICANON;
if (!(flags & (0000002|0000040)))
termios.c_lflag |= ICANON;
/* IEXTEN - set if not RAW */
/* ISIG - set if not RAW */
termios.c_lflag &= ~(IEXTEN|ISIG);
if (!(flags & 0000040))
termios.c_lflag |= (IEXTEN|ISIG);
/* NOFLSH - not changed */
/* TOSTOP - not changed */
tp->tty_termios = termios;
setattr(tp);
return(OK);
}
/*===========================================================================*
* compat_setc *
*===========================================================================*/
PRIVATE int compat_setc(tp, tc)
tty_t *tp;
struct tchars *tc;
{
/* Translate an old TIOCSETC to the termios equivalent. */
struct termios termios;
termios = tp->tty_termios;
termios.c_cc[VINTR] = tc->t_intrc;
termios.c_cc[VQUIT] = tc->t_quitc;
termios.c_cc[VSTART] = tc->t_startc;
termios.c_cc[VSTOP] = tc->t_stopc;
termios.c_cc[VEOL] = tc->t_brkc;
termios.c_cc[VEOF] = tc->t_eofc;
tp->tty_termios = termios;
setattr(tp);
return(OK);
}
/* Table of termios line speed to sgtty line speed translations. All termios
* speeds are present even if sgtty didn't know about them. (Now it does.)
*/
PRIVATE struct s2s {
speed_t tspd;
u8_t sgspd;
} ts2sgs[] = {
{ B0, 0 },
{ B50, 50 },
{ B75, 75 },
{ B110, 1 },
{ B134, 134 },
{ B200, 2 },
{ B300, 3 },
{ B600, 6 },
{ B1200, 12 },
{ B1800, 18 },
{ B2400, 24 },
{ B4800, 48 },
{ B9600, 96 },
{ B19200, 192 },
{ B38400, 195 },
{ B57600, 194 },
{ B115200, 193 },
};
/*===========================================================================*
* tspd2sgspd *
*===========================================================================*/
PRIVATE int tspd2sgspd(tspd)
speed_t tspd;
{
/* Translate a termios speed to sgtty speed. */
struct s2s *s;
for (s = ts2sgs; s < ts2sgs + sizeof(ts2sgs)/sizeof(ts2sgs[0]); s++) {
if (s->tspd == tspd) return(s->sgspd);
}
return 96;
}
/*===========================================================================*
* sgspd2tspd *
*===========================================================================*/
PRIVATE speed_t sgspd2tspd(sgspd)
int sgspd;
{
/* Translate a sgtty speed to termios speed. */
struct s2s *s;
for (s = ts2sgs; s < ts2sgs + sizeof(ts2sgs)/sizeof(ts2sgs[0]); s++) {
if (s->sgspd == sgspd) return(s->tspd);
}
return B9600;
}
#if ENABLE_BINCOMPAT
/*===========================================================================*
* do_ioctl_compat *
*===========================================================================*/
PRIVATE void do_ioctl_compat(tp, m_ptr)
tty_t *tp;
message *m_ptr;
{
/* Handle the old sgtty ioctl's that packed the sgtty or tchars struct into
* the Minix message. Efficient then, troublesome now.
*/
int minor, proc, func, result, r;
long flags, erki, spek;
u8_t erase, kill, intr, quit, xon, xoff, brk, eof, ispeed, ospeed;
struct sgttyb sg;
struct tchars tc;
message reply_mess;
minor = m_ptr->TTY_LINE;
proc = m_ptr->IO_ENDPT;
func = m_ptr->REQUEST;
spek = m_ptr->m2_l1;
flags = m_ptr->m2_l2;
switch(func)
{
case (('t'<<8) | 8): /* TIOCGETP */
r = compat_getp(tp, &sg);
erase = sg.sg_erase;
kill = sg.sg_kill;
ispeed = sg.sg_ispeed;
ospeed = sg.sg_ospeed;
flags = sg.sg_flags;
erki = ((long)ospeed<<24) | ((long)ispeed<<16) | ((long)erase<<8) |kill;
break;
case (('t'<<8) | 18): /* TIOCGETC */
r = compat_getc(tp, &tc);
intr = tc.t_intrc;
quit = tc.t_quitc;
xon = tc.t_startc;
xoff = tc.t_stopc;
brk = tc.t_brkc;
eof = tc.t_eofc;
erki = ((long)intr<<24) | ((long)quit<<16) | ((long)xon<<8) | xoff;
flags = (eof << 8) | brk;
break;
case (('t'<<8) | 17): /* TIOCSETC */
tc.t_stopc = (spek >> 0) & 0xFF;
tc.t_startc = (spek >> 8) & 0xFF;
tc.t_quitc = (spek >> 16) & 0xFF;
tc.t_intrc = (spek >> 24) & 0xFF;
tc.t_brkc = (flags >> 0) & 0xFF;
tc.t_eofc = (flags >> 8) & 0xFF;
r = compat_setc(tp, &tc);
break;
case (('t'<<8) | 9): /* TIOCSETP */
sg.sg_erase = (spek >> 8) & 0xFF;
sg.sg_kill = (spek >> 0) & 0xFF;
sg.sg_ispeed = (spek >> 16) & 0xFF;
sg.sg_ospeed = (spek >> 24) & 0xFF;
sg.sg_flags = flags;
r = compat_setp(tp, &sg);
break;
default:
r = ENOTTY;
}
reply_mess.m_type = TASK_REPLY;
reply_mess.REP_ENDPT = m_ptr->IO_ENDPT;
reply_mess.REP_STATUS = r;
reply_mess.m2_l1 = erki;
reply_mess.m2_l2 = flags;
send(m_ptr->m_source, &reply_mess);
}
#endif /* ENABLE_BINCOMPAT */
#endif /* ENABLE_SRCCOMPAT || ENABLE_BINCOMPAT */

View File

@ -7,6 +7,8 @@
#undef lock
#undef unlock
#define TTY_REVIVE 6767
/* First minor numbers for the various classes of TTY devices. */
#define CONS_MINOR 0
#define LOG_MINOR 15
@ -66,20 +68,27 @@ typedef struct tty {
char tty_inrevived; /* set to 1 if revive callback is pending */
int tty_incaller; /* process that made the call (usually FS) */
int tty_inproc; /* process that wants to read from tty */
vir_bytes tty_in_vir; /* virtual address where data is to go */
vir_bytes tty_in_vir_g; /* address or grant where data is to go */
vir_bytes tty_in_vir_offset; /* offset into grant */
int tty_in_safe; /* nonzero: safecopies (in_vir is grantid) */
int tty_inleft; /* how many chars are still needed */
int tty_incum; /* # chars input so far */
int tty_outrepcode; /* reply code, TASK_REPLY or REVIVE */
int tty_outrevived; /* set to 1 if revive callback is pending */
int tty_outcaller; /* process that made the call (usually FS) */
int tty_outproc; /* process that wants to write to tty */
vir_bytes tty_out_vir; /* virtual address where data comes from */
vir_bytes tty_out_vir_g; /* address or grant where data comes from */
vir_bytes tty_out_vir_offset; /* offset into grant */
int tty_out_safe; /* nonzero: safecopies (out_vir is grantid) */
int tty_outleft; /* # chars yet to be output */
int tty_outcum; /* # chars output so far */
int tty_iocaller; /* process that made the call (usually FS) */
int tty_iorevived; /* set to 1 if revive callback is pending */
int tty_ioproc; /* process that wants to do an ioctl */
int tty_iostatus; /* result */
int tty_ioreq; /* ioctl request code */
vir_bytes tty_iovir; /* virtual address of ioctl buffer */
int tty_io_safe; /* safe copy mode? (iovir is grant id) */
vir_bytes tty_iovir_g; /* virtual address of ioctl buffer or grant */
/* select() data */
int tty_select_ops; /* which operations are interesting */
@ -146,7 +155,8 @@ _PROTOTYPE( int in_process, (struct tty *tp, char *buf, int count) );
_PROTOTYPE( void out_process, (struct tty *tp, char *bstart, char *bpos,
char *bend, int *icount, int *ocount) );
_PROTOTYPE( void tty_wakeup, (clock_t now) );
_PROTOTYPE( void tty_reply, (int code, int replyee, int proc_nr,
#define tty_reply(c, r, p, s) tty_reply_f(__FILE__, __LINE__, (c), (r), (p), (s))
_PROTOTYPE( void tty_reply_f, (char *f, int l, int code, int replyee, int proc_nr,
int status) );
_PROTOTYPE( int tty_devnop, (struct tty *tp, int try) );
_PROTOTYPE( int select_try, (struct tty *tp, int ops) );
@ -161,7 +171,7 @@ _PROTOTYPE( void rs_interrupt, (message *m) );
_PROTOTYPE( void kputc, (int c) );
_PROTOTYPE( void cons_stop, (void) );
_PROTOTYPE( void do_new_kmess, (message *m) );
_PROTOTYPE( void do_diagnostics, (message *m) );
_PROTOTYPE( void do_diagnostics, (message *m, int safe) );
_PROTOTYPE( void do_get_kmess, (message *m) );
_PROTOTYPE( void scr_init, (struct tty *tp) );
_PROTOTYPE( void toggle_scroll, (void) );
@ -173,7 +183,7 @@ _PROTOTYPE( void do_video, (message *m) );
/* keyboard.c */
_PROTOTYPE( void kb_init, (struct tty *tp) );
_PROTOTYPE( void kb_init_once, (void) );
_PROTOTYPE( int kbd_loadmap, (message *m) );
_PROTOTYPE( int kbd_loadmap, (message *m, int safe) );
_PROTOTYPE( void do_panic_dumps, (message *m) );
_PROTOTYPE( void do_fkey_ctl, (message *m) );
_PROTOTYPE( void kbd_interrupt, (message *m) );