TTY: use libchardriver; clean up
- writing to a PTY master side blocks if there is not already a blocked reader on the slave side, and select now reflects this; - internally, TTY now uses a test based on "caller != NONE" rather than "grant != GRANT_INVALID" to identify whether a call is currently ongoing; - "offset" fields have been removed as they equal the corresponding "cum" fields; - improved variable typing and function naming here and there; - various other small fixes. Change-Id: I6b51452888942e864b4e034e8c8490576184a23e
This commit is contained in:
parent
701f2b4dd5
commit
3d697930dd
|
@ -1221,7 +1221,7 @@
|
||||||
./usr/include/minix/sysutil.h minix-sys
|
./usr/include/minix/sysutil.h minix-sys
|
||||||
./usr/include/minix/termios.h minix-sys
|
./usr/include/minix/termios.h minix-sys
|
||||||
./usr/include/minix/timers.h minix-sys
|
./usr/include/minix/timers.h minix-sys
|
||||||
./usr/include/minix/tty.h minix-sys
|
./usr/include/minix/tty.h minix-sys obsolete
|
||||||
./usr/include/minix/type.h minix-sys
|
./usr/include/minix/type.h minix-sys
|
||||||
./usr/include/minix/types.h minix-sys obsolete
|
./usr/include/minix/types.h minix-sys obsolete
|
||||||
./usr/include/minix/u64.h minix-sys
|
./usr/include/minix/u64.h minix-sys
|
||||||
|
|
|
@ -6,8 +6,8 @@ PROG= tty
|
||||||
|
|
||||||
SRCS += tty.c pty.c
|
SRCS += tty.c pty.c
|
||||||
|
|
||||||
DPADD+= ${LIBSYS} ${LIBTIMERS}
|
DPADD+= ${LIBCHARDRIVER} ${LIBSYS} ${LIBTIMERS}
|
||||||
LDADD+= -lsys -ltimers
|
LDADD+= -lchardriver -lsys -ltimers
|
||||||
|
|
||||||
MAN=
|
MAN=
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
|
|
||||||
void
|
void
|
||||||
do_video(message *m)
|
do_video(message *m, int ipc_status)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ cons_stop(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
con_loadfont(message *m)
|
con_loadfont(endpoint_t endpt, cp_grant_id_t grant)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,12 +19,7 @@ do_kb_inject(message *m)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
do_kbd(message *m)
|
do_kbd(message *m, int ipc_status)
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
do_kbdaux(message *m)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +29,7 @@ kb_init_once(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
kbd_loadmap(message *m)
|
kbd_loadmap(endpoint_t endpt, cp_grant_id_t grant)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -237,11 +237,11 @@ rs_write(register tty_t *tp, int try)
|
||||||
if (tp->tty_outcaller == KERNEL) {
|
if (tp->tty_outcaller == KERNEL) {
|
||||||
/* We're trying to print on kernel's behalf */
|
/* We're trying to print on kernel's behalf */
|
||||||
memcpy(rs->ohead,
|
memcpy(rs->ohead,
|
||||||
(void *) tp->tty_outgrant + tp->tty_outoffset,
|
(char *) tp->tty_outgrant + tp->tty_outcum,
|
||||||
count);
|
count);
|
||||||
} else {
|
} else {
|
||||||
if ((r = sys_safecopyfrom(tp->tty_outcaller,
|
if ((r = sys_safecopyfrom(tp->tty_outcaller,
|
||||||
tp->tty_outgrant, tp->tty_outoffset,
|
tp->tty_outgrant, tp->tty_outcum,
|
||||||
(vir_bytes) rs->ohead, count)) != OK) {
|
(vir_bytes) rs->ohead, count)) != OK) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -262,24 +262,21 @@ rs_write(register tty_t *tp, int try)
|
||||||
rs_ostart(rs);
|
rs_ostart(rs);
|
||||||
if ((rs->ohead += ocount) >= bufend(rs->obuf))
|
if ((rs->ohead += ocount) >= bufend(rs->obuf))
|
||||||
rs->ohead -= buflen(rs->obuf);
|
rs->ohead -= buflen(rs->obuf);
|
||||||
tp->tty_outoffset += count;
|
|
||||||
tp->tty_outcum += count;
|
tp->tty_outcum += count;
|
||||||
if ((tp->tty_outleft -= count) == 0) {
|
if ((tp->tty_outleft -= count) == 0) {
|
||||||
/* Output is finished, reply to the writer. */
|
/* Output is finished, reply to the writer. */
|
||||||
tty_reply(DEV_REVIVE, tp->tty_outcaller,
|
chardriver_reply_task(tp->tty_outcaller, tp->tty_outid,
|
||||||
tp->tty_outproc, tp->tty_outgrant,
|
|
||||||
tp->tty_outcum);
|
tp->tty_outcum);
|
||||||
tp->tty_outcum = 0;
|
tp->tty_outcum = 0;
|
||||||
tp->tty_outgrant = GRANT_INVALID;
|
tp->tty_outcaller = NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (tp->tty_outleft > 0 && tp->tty_termios.c_ospeed == B0) {
|
if (tp->tty_outleft > 0 && tp->tty_termios.c_ospeed == B0) {
|
||||||
/* Oops, the line has hung up. */
|
/* Oops, the line has hung up. */
|
||||||
tty_reply(DEV_REVIVE, tp->tty_outcaller, tp->tty_outproc,
|
chardriver_reply_task(tp->tty_outcaller, tp->tty_outid, EIO);
|
||||||
tp->tty_outgrant, EIO);
|
|
||||||
tp->tty_outleft = tp->tty_outcum = 0;
|
tp->tty_outleft = tp->tty_outcum = 0;
|
||||||
tp->tty_outgrant = GRANT_INVALID;
|
tp->tty_outcaller = NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -18,16 +18,10 @@
|
||||||
|
|
||||||
#include <minix/drivers.h>
|
#include <minix/drivers.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <assert.h>
|
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/vm.h>
|
#include <sys/vm.h>
|
||||||
#include <sys/video.h>
|
#include <sys/video.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <minix/tty.h>
|
|
||||||
#include <minix/callnr.h>
|
|
||||||
#include <minix/com.h>
|
|
||||||
#include <minix/sys_config.h>
|
|
||||||
#include <minix/vm.h>
|
|
||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
|
|
||||||
/* Set this to 1 if you want console output duplicated on the first
|
/* Set this to 1 if you want console output duplicated on the first
|
||||||
|
@ -142,6 +136,18 @@ static void vid_vid_copy(int src, int dst, int count);
|
||||||
static void get_6845(int reg, unsigned *val);
|
static void get_6845(int reg, unsigned *val);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int video_open(devminor_t minor, int access, endpoint_t user_endpt);
|
||||||
|
static int video_close(devminor_t minor);
|
||||||
|
static int video_ioctl(devminor_t minor, unsigned long request,
|
||||||
|
endpoint_t endpt, cp_grant_id_t grant, int flags,
|
||||||
|
endpoint_t user_endpt, cdev_id_t id);
|
||||||
|
|
||||||
|
static struct chardriver video_tab = {
|
||||||
|
.cdr_open = video_open,
|
||||||
|
.cdr_close = video_close,
|
||||||
|
.cdr_ioctl = video_ioctl
|
||||||
|
};
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* cons_write *
|
* cons_write *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
@ -174,16 +180,14 @@ int try;
|
||||||
if (count > sizeof(buf)) count = sizeof(buf);
|
if (count > sizeof(buf)) count = sizeof(buf);
|
||||||
if (tp->tty_outcaller == KERNEL) {
|
if (tp->tty_outcaller == KERNEL) {
|
||||||
/* We're trying to print on kernel's behalf */
|
/* We're trying to print on kernel's behalf */
|
||||||
memcpy(buf, (void *) tp->tty_outgrant + tp->tty_outoffset,
|
memcpy(buf, (char *) tp->tty_outgrant + tp->tty_outcum, count);
|
||||||
count);
|
|
||||||
} else {
|
} else {
|
||||||
if ((result = sys_safecopyfrom(tp->tty_outcaller,
|
if ((result = sys_safecopyfrom(tp->tty_outcaller,
|
||||||
tp->tty_outgrant, tp->tty_outoffset,
|
tp->tty_outgrant, tp->tty_outcum,
|
||||||
(vir_bytes) buf, count)) != OK) {
|
(vir_bytes) buf, count)) != OK) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tp->tty_outoffset += count;
|
|
||||||
tbuf = buf;
|
tbuf = buf;
|
||||||
|
|
||||||
/* Update terminal data structure. */
|
/* Update terminal data structure. */
|
||||||
|
@ -215,10 +219,10 @@ int try;
|
||||||
|
|
||||||
/* Reply to the writer if all output is finished or if an error occured. */
|
/* Reply to the writer if all output is finished or if an error occured. */
|
||||||
if (tp->tty_outleft == 0 || result != OK) {
|
if (tp->tty_outleft == 0 || result != OK) {
|
||||||
tty_reply(DEV_REVIVE, tp->tty_outcaller, tp->tty_outproc,
|
chardriver_reply_task(tp->tty_outcaller, tp->tty_outid,
|
||||||
tp->tty_outgrant, result != OK ? result : tp->tty_outcum);
|
result != OK ? result : tp->tty_outcum);
|
||||||
tp->tty_outcum = tp->tty_outleft = 0;
|
tp->tty_outcum = tp->tty_outleft = 0;
|
||||||
tp->tty_outgrant = GRANT_INVALID;
|
tp->tty_outcaller = NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -807,84 +811,69 @@ static void beep()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* video_open *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int video_open(devminor_t minor, int UNUSED(access),
|
||||||
|
endpoint_t UNUSED(user_endpt))
|
||||||
|
{
|
||||||
|
/* Should grant IOPL */
|
||||||
|
disable_console();
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* video_close *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int video_close(devminor_t minor)
|
||||||
|
{
|
||||||
|
reenable_console();
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* video_ioctl *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int video_ioctl(devminor_t minor, unsigned long request,
|
||||||
|
endpoint_t endpt, cp_grant_id_t grant, int flags,
|
||||||
|
endpoint_t user_endpt, cdev_id_t id)
|
||||||
|
{
|
||||||
|
struct mapreqvm mapreqvm;
|
||||||
|
int r, do_map;
|
||||||
|
|
||||||
|
switch (request) {
|
||||||
|
case TIOCMAPMEM:
|
||||||
|
case TIOCUNMAPMEM:
|
||||||
|
do_map = (request == TIOCMAPMEM); /* else unmap */
|
||||||
|
|
||||||
|
if ((r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &mapreqvm,
|
||||||
|
sizeof(mapreqvm))) != OK)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (do_map) {
|
||||||
|
mapreqvm.vaddr_ret = vm_map_phys(user_endpt,
|
||||||
|
(void *) mapreqvm.phys_offset, mapreqvm.size);
|
||||||
|
r = sys_safecopyto(endpt, grant, 0, (vir_bytes) &mapreqvm,
|
||||||
|
sizeof(mapreqvm));
|
||||||
|
} else {
|
||||||
|
r = vm_unmap_phys(user_endpt, mapreqvm.vaddr, mapreqvm.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ENOTTY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* do_video *
|
* do_video *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
void do_video(message *m)
|
void do_video(message *m, int ipc_status)
|
||||||
{
|
{
|
||||||
int r;
|
chardriver_process(&video_tab, m, ipc_status);
|
||||||
|
|
||||||
/* Execute the requested device driver function. */
|
|
||||||
r= EINVAL; /* just in case */
|
|
||||||
switch (m->m_type) {
|
|
||||||
case DEV_OPEN:
|
|
||||||
/* Should grant IOPL */
|
|
||||||
disable_console();
|
|
||||||
tty_reply(DEV_OPEN_REPL, m->m_source, m->USER_ENDPT,
|
|
||||||
(cp_grant_id_t) m->IO_GRANT, OK);
|
|
||||||
return;
|
|
||||||
case DEV_CLOSE:
|
|
||||||
reenable_console();
|
|
||||||
tty_reply(DEV_CLOSE_REPL, m->m_source, m->USER_ENDPT,
|
|
||||||
(cp_grant_id_t) m->IO_GRANT, OK);
|
|
||||||
return;
|
|
||||||
case DEV_IOCTL_S:
|
|
||||||
switch(m->REQUEST) {
|
|
||||||
case TIOCMAPMEM:
|
|
||||||
case TIOCUNMAPMEM: {
|
|
||||||
int r, do_map;
|
|
||||||
struct mapreqvm mapreqvm;
|
|
||||||
|
|
||||||
do_map= (m->REQUEST == TIOCMAPMEM); /* else unmap */
|
|
||||||
|
|
||||||
r = sys_safecopyfrom(m->m_source,
|
|
||||||
(cp_grant_id_t) m->IO_GRANT, 0,
|
|
||||||
(vir_bytes) &mapreqvm, sizeof(mapreqvm));
|
|
||||||
|
|
||||||
if (r != OK)
|
|
||||||
{
|
|
||||||
printf("tty: sys_safecopyfrom failed\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* In safe ioctl mode, the POSITION field contains
|
|
||||||
* the endpt number of the original requestor.
|
|
||||||
* USER_ENDPT is always FS.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if(do_map) {
|
|
||||||
mapreqvm.vaddr_ret = vm_map_phys(m->POSITION,
|
|
||||||
(void *) mapreqvm.phys_offset, mapreqvm.size);
|
|
||||||
if((r = sys_safecopyto(m->m_source,
|
|
||||||
(cp_grant_id_t) m->IO_GRANT, 0,
|
|
||||||
(vir_bytes) &mapreqvm,
|
|
||||||
sizeof(mapreqvm))) != OK) {
|
|
||||||
printf("tty: sys_safecopyto failed\n");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
r = vm_unmap_phys(m->POSITION,
|
|
||||||
mapreqvm.vaddr, mapreqvm.size);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
r= ENOTTY;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
printf(
|
|
||||||
"Warning, TTY(video) got unexpected request %d from %d\n",
|
|
||||||
m->m_type, m->m_source);
|
|
||||||
r= EINVAL;
|
|
||||||
}
|
|
||||||
tty_reply(DEV_REVIVE, m->m_source, m->USER_ENDPT,
|
|
||||||
(cp_grant_id_t) m->IO_GRANT, r);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* beep_x *
|
* beep_x *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
@ -1137,12 +1126,11 @@ void select_console(int cons_line)
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* con_loadfont *
|
* con_loadfont *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
int con_loadfont(m)
|
int con_loadfont(endpoint_t endpt, cp_grant_id_t grant)
|
||||||
message *m;
|
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Load a font into the EGA or VGA adapter. */
|
/* Load a font into the EGA or VGA adapter. */
|
||||||
int result;
|
int r, r2;
|
||||||
static struct sequence seq1[7] = {
|
static struct sequence seq1[7] = {
|
||||||
{ GA_SEQUENCER_INDEX, 0x00, 0x01 },
|
{ GA_SEQUENCER_INDEX, 0x00, 0x01 },
|
||||||
{ GA_SEQUENCER_INDEX, 0x02, 0x04 },
|
{ GA_SEQUENCER_INDEX, 0x02, 0x04 },
|
||||||
|
@ -1164,17 +1152,14 @@ message *m;
|
||||||
|
|
||||||
seq2[6].value= color ? 0x0E : 0x0A;
|
seq2[6].value= color ? 0x0E : 0x0A;
|
||||||
|
|
||||||
result = ga_program(seq1); /* bring font memory into view */
|
r = ga_program(seq1); /* bring font memory into view */
|
||||||
|
if (r != OK) return r;
|
||||||
|
|
||||||
if(sys_safecopyfrom(m->m_source, (cp_grant_id_t) m->IO_GRANT, 0,
|
r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) font_memory, GA_FONT_SIZE);
|
||||||
(vir_bytes) font_memory, GA_FONT_SIZE) != OK) {
|
|
||||||
printf("tty: copying from %d failed\n", m->m_source);
|
|
||||||
return EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = ga_program(seq2); /* restore */
|
r2 = ga_program(seq2); /* restore */
|
||||||
|
|
||||||
return(result);
|
return(r != OK ? r : r2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
|
|
@ -123,19 +123,17 @@ static obs_t sfkey_obs[12]; /* observers for SHIFT F1-F12 */
|
||||||
|
|
||||||
static struct kbd
|
static struct kbd
|
||||||
{
|
{
|
||||||
int minor;
|
devminor_t minor;
|
||||||
int nr_open;
|
int nr_open;
|
||||||
char buf[KBD_BUFSZ];
|
char buf[KBD_BUFSZ];
|
||||||
int offset;
|
int offset;
|
||||||
int avail;
|
int avail;
|
||||||
int req_size;
|
size_t req_size;
|
||||||
int req_proc;
|
cdev_id_t req_id;
|
||||||
cp_grant_id_t req_grant;
|
cp_grant_id_t req_grant;
|
||||||
vir_bytes req_addr_offset;
|
endpoint_t req_caller;
|
||||||
int incaller;
|
unsigned int select_ops;
|
||||||
int select_ops;
|
endpoint_t select_proc;
|
||||||
int select_proc;
|
|
||||||
int select_minor; /* sanity check only, can be removed */
|
|
||||||
} kbd, kbdaux;
|
} kbd, kbdaux;
|
||||||
|
|
||||||
/* Data that is to be sent to the keyboard. Each byte is ACKed by the
|
/* Data that is to be sent to the keyboard. Each byte is ACKed by the
|
||||||
|
@ -155,7 +153,6 @@ static long sticky_alt_mode = 0;
|
||||||
static long debug_fkeys = 1;
|
static long debug_fkeys = 1;
|
||||||
static timer_t tmr_kbd_wd;
|
static timer_t tmr_kbd_wd;
|
||||||
|
|
||||||
static void handle_req(struct kbd *kbdp, message *m);
|
|
||||||
static void kbc_cmd0(int cmd);
|
static void kbc_cmd0(int cmd);
|
||||||
static void kbc_cmd1(int cmd, int data);
|
static void kbc_cmd1(int cmd, int data);
|
||||||
static int kbc_read(void);
|
static int kbc_read(void);
|
||||||
|
@ -171,221 +168,285 @@ static int kb_read(struct tty *tp, int try);
|
||||||
static unsigned map_key(int scode);
|
static unsigned map_key(int scode);
|
||||||
static void kbd_watchdog(timer_t *tmrp);
|
static void kbd_watchdog(timer_t *tmrp);
|
||||||
|
|
||||||
int micro_delay(u32_t usecs)
|
static int kbd_open(devminor_t minor, int access, endpoint_t user_endpt);
|
||||||
|
static int kbd_close(devminor_t minor);
|
||||||
|
static ssize_t kbd_read(devminor_t minor, u64_t position, endpoint_t endpt,
|
||||||
|
cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
|
||||||
|
static ssize_t kbd_write(devminor_t minor, u64_t position, endpoint_t endpt,
|
||||||
|
cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
|
||||||
|
static int kbd_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt,
|
||||||
|
cp_grant_id_t grant, int flags, endpoint_t user_endpt, cdev_id_t id);
|
||||||
|
static int kbd_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id);
|
||||||
|
static int kbd_select(devminor_t minor, unsigned int ops, endpoint_t endpt);
|
||||||
|
|
||||||
|
static struct chardriver kbd_tab = {
|
||||||
|
.cdr_open = kbd_open,
|
||||||
|
.cdr_close = kbd_close,
|
||||||
|
.cdr_read = kbd_read,
|
||||||
|
.cdr_write = kbd_write,
|
||||||
|
.cdr_ioctl = kbd_ioctl,
|
||||||
|
.cdr_cancel = kbd_cancel,
|
||||||
|
.cdr_select = kbd_select
|
||||||
|
};
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* line2kbd *
|
||||||
|
*===========================================================================*/
|
||||||
|
static struct kbd *
|
||||||
|
line2kbd(devminor_t minor)
|
||||||
{
|
{
|
||||||
/* TTY can't use the library micro_delay() as that calls PM. */
|
switch (minor) {
|
||||||
tickdelay(micros_to_ticks(usecs));
|
case KBD_MINOR: return &kbd;
|
||||||
|
case KBDAUX_MINOR: return &kbdaux;
|
||||||
|
default: return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* kbd_open *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
kbd_open(devminor_t minor, int UNUSED(access), endpoint_t UNUSED(user_endpt))
|
||||||
|
{
|
||||||
|
struct kbd *kbdp;
|
||||||
|
|
||||||
|
if ((kbdp = line2kbd(minor)) == NULL)
|
||||||
|
return ENXIO;
|
||||||
|
|
||||||
|
kbdp->nr_open++;
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* kbd_close *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
kbd_close(devminor_t minor)
|
||||||
|
{
|
||||||
|
struct kbd *kbdp;
|
||||||
|
|
||||||
|
if ((kbdp = line2kbd(minor)) == NULL)
|
||||||
|
return ENXIO;
|
||||||
|
|
||||||
|
kbdp->nr_open--;
|
||||||
|
if (kbdp->nr_open < 0) {
|
||||||
|
printf("TTY(kbd): open count is negative\n");
|
||||||
|
kbdp->nr_open= 0;
|
||||||
|
}
|
||||||
|
if (kbdp->nr_open == 0)
|
||||||
|
kbdp->avail= 0;
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* kbd_read *
|
||||||
|
*===========================================================================*/
|
||||||
|
static ssize_t
|
||||||
|
kbd_read(devminor_t minor, u64_t UNUSED(position), endpoint_t endpt,
|
||||||
|
cp_grant_id_t grant, size_t size, int flags, cdev_id_t id)
|
||||||
|
{
|
||||||
|
ssize_t n, r;
|
||||||
|
struct kbd *kbdp;
|
||||||
|
|
||||||
|
if ((kbdp = line2kbd(minor)) == NULL)
|
||||||
|
return ENXIO;
|
||||||
|
|
||||||
|
/* We handle only one request at a time. */
|
||||||
|
if (kbdp->req_size)
|
||||||
|
return EIO;
|
||||||
|
|
||||||
|
if ((ssize_t) size <= 0)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
/* If no data is available, suspend the caller. */
|
||||||
|
if (kbdp->avail == 0) {
|
||||||
|
if (flags & FLG_OP_NONBLOCK)
|
||||||
|
return EAGAIN;
|
||||||
|
kbdp->req_size = size;
|
||||||
|
kbdp->req_id = id;
|
||||||
|
kbdp->req_grant = grant;
|
||||||
|
kbdp->req_caller = endpt;
|
||||||
|
return EDONTREPLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle read request. */
|
||||||
|
n = kbdp->avail;
|
||||||
|
if (n > (ssize_t) size)
|
||||||
|
n = size;
|
||||||
|
if (kbdp->offset + n > KBD_BUFSZ)
|
||||||
|
n = KBD_BUFSZ - kbdp->offset;
|
||||||
|
if (n <= 0)
|
||||||
|
panic("do_kbd(READ): bad n: %d", n);
|
||||||
|
r = sys_safecopyto(endpt, grant, 0,
|
||||||
|
(vir_bytes) &kbdp->buf[kbdp->offset], n);
|
||||||
|
if (r == OK) {
|
||||||
|
kbdp->offset = (kbdp->offset + n) % KBD_BUFSZ;
|
||||||
|
kbdp->avail -= n;
|
||||||
|
r = n;
|
||||||
|
} else
|
||||||
|
printf("TTY(kbd): copy in read kbd failed: %d\n", r);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* kbd_write *
|
||||||
|
*===========================================================================*/
|
||||||
|
static ssize_t
|
||||||
|
kbd_write(devminor_t minor, u64_t UNUSED(position), endpoint_t endpt,
|
||||||
|
cp_grant_id_t grant, size_t size, int flags, cdev_id_t id)
|
||||||
|
{
|
||||||
|
struct kbd *kbdp;
|
||||||
|
unsigned char c;
|
||||||
|
size_t i;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if ((kbdp = line2kbd(minor)) == NULL)
|
||||||
|
return ENXIO;
|
||||||
|
if (kbdp != &kbdaux) {
|
||||||
|
printf("TTY(kbd): write to keyboard not implemented\n");
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Assume that output to AUX only happens during initialization and we
|
||||||
|
* can afford to lose input. This should be fixed at a later time.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
r = sys_safecopyfrom(endpt, grant, i, (vir_bytes) &c, 1);
|
||||||
|
if (r != OK)
|
||||||
|
return i ? i : r;
|
||||||
|
kbc_cmd1(KBC_WRITE_AUX, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* kbd_ioctl *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
kbd_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt,
|
||||||
|
cp_grant_id_t grant, int flags, endpoint_t UNUSED(user_endpt),
|
||||||
|
cdev_id_t id)
|
||||||
|
{
|
||||||
|
struct kbd *kbdp;
|
||||||
|
kio_leds_t leds;
|
||||||
|
kio_bell_t bell;
|
||||||
|
clock_t ticks;
|
||||||
|
unsigned char b;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if ((kbdp = line2kbd(minor)) == NULL)
|
||||||
|
return ENXIO;
|
||||||
|
if (kbdp != &kbd)
|
||||||
|
return ENOTTY; /* we only support ioctls on keyboards now */
|
||||||
|
|
||||||
|
switch (request) {
|
||||||
|
case KIOCSLEDS:
|
||||||
|
r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &leds,
|
||||||
|
sizeof(leds));
|
||||||
|
if (r != OK)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
b = 0;
|
||||||
|
if (leds.kl_bits & KBD_LEDS_NUM) b |= NUM_LOCK;
|
||||||
|
if (leds.kl_bits & KBD_LEDS_CAPS) b |= CAPS_LOCK;
|
||||||
|
if (leds.kl_bits & KBD_LEDS_SCROLL) b |= SCROLL_LOCK;
|
||||||
|
if (kbdout.avail == 0)
|
||||||
|
kbdout.offset = 0;
|
||||||
|
if (kbdout.offset + kbdout.avail + 2 > KBD_OUT_BUFSZ) {
|
||||||
|
/* Output buffer is full. Ignore this command.
|
||||||
|
* Reset ACK flag.
|
||||||
|
*/
|
||||||
|
kbdout.expect_ack = 0;
|
||||||
|
} else {
|
||||||
|
kbdout.buf[kbdout.offset+kbdout.avail] = LED_CODE;
|
||||||
|
kbdout.buf[kbdout.offset+kbdout.avail+1] = b;
|
||||||
|
kbdout.avail += 2;
|
||||||
|
}
|
||||||
|
if (!kbdout.expect_ack)
|
||||||
|
kbd_send();
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
|
||||||
|
case KIOCBELL:
|
||||||
|
r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &bell,
|
||||||
|
sizeof(bell));
|
||||||
|
if (r != OK)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
ticks = bell.kb_duration.tv_usec * system_hz / 1000000;
|
||||||
|
ticks += bell.kb_duration.tv_sec * system_hz;
|
||||||
|
if (!ticks)
|
||||||
|
ticks++;
|
||||||
|
beep_x(bell.kb_pitch, ticks);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ENOTTY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* kbd_cancel *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
kbd_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id)
|
||||||
|
{
|
||||||
|
struct kbd *kbdp;
|
||||||
|
|
||||||
|
if ((kbdp = line2kbd(minor)) == NULL)
|
||||||
|
return ENXIO;
|
||||||
|
|
||||||
|
if (kbdp->req_size > 0 && endpt == kbdp->req_caller &&
|
||||||
|
id == kbdp->req_id)
|
||||||
|
return EINTR;
|
||||||
|
|
||||||
|
return EDONTREPLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* kbd_select *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
kbd_select(devminor_t minor, unsigned int ops, endpoint_t endpt)
|
||||||
|
{
|
||||||
|
struct kbd *kbdp;
|
||||||
|
int watch, ready_ops;
|
||||||
|
|
||||||
|
if ((kbdp = line2kbd(minor)) == NULL)
|
||||||
|
return ENXIO;
|
||||||
|
|
||||||
|
watch = (ops & SEL_NOTIFY);
|
||||||
|
ops &= (SEL_RD | SEL_WR | SEL_ERR);
|
||||||
|
|
||||||
|
ready_ops = 0;
|
||||||
|
if (kbdp->avail && (ops & SEL_RD))
|
||||||
|
ready_ops |= SEL_RD;
|
||||||
|
if (ops & SEL_WR)
|
||||||
|
ready_ops |= SEL_WR; /* writes never block */
|
||||||
|
|
||||||
|
ops &= ~ready_ops;
|
||||||
|
if (ops && watch) {
|
||||||
|
kbdp->select_ops |= ops;
|
||||||
|
kbdp->select_proc = endpt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ready_ops;
|
||||||
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* do_kbd *
|
* do_kbd *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
void do_kbd(message *m)
|
void
|
||||||
|
do_kbd(message *m, int ipc_status)
|
||||||
{
|
{
|
||||||
handle_req(&kbd, m);
|
chardriver_process(&kbd_tab, m, ipc_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
|
||||||
* do_kbdaux *
|
|
||||||
*===========================================================================*/
|
|
||||||
void do_kbdaux(message *m)
|
|
||||||
{
|
|
||||||
handle_req(&kbdaux, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
|
||||||
* handle_req *
|
|
||||||
*===========================================================================*/
|
|
||||||
static void handle_req(kbdp, m)
|
|
||||||
struct kbd *kbdp;
|
|
||||||
message *m;
|
|
||||||
{
|
|
||||||
int i, n, r, ops, watch;
|
|
||||||
unsigned char c;
|
|
||||||
|
|
||||||
/* Execute the requested device driver function. */
|
|
||||||
r= EINVAL; /* just in case */
|
|
||||||
switch (m->m_type) {
|
|
||||||
case DEV_OPEN:
|
|
||||||
kbdp->nr_open++;
|
|
||||||
tty_reply(DEV_OPEN_REPL, m->m_source, m->USER_ENDPT,
|
|
||||||
(cp_grant_id_t) m->IO_GRANT, OK);
|
|
||||||
return;
|
|
||||||
case DEV_CLOSE:
|
|
||||||
kbdp->nr_open--;
|
|
||||||
if (kbdp->nr_open < 0)
|
|
||||||
{
|
|
||||||
printf("TTY(kbd): open count is negative\n");
|
|
||||||
kbdp->nr_open= 0;
|
|
||||||
}
|
|
||||||
if (kbdp->nr_open == 0)
|
|
||||||
kbdp->avail= 0;
|
|
||||||
tty_reply(DEV_CLOSE_REPL, m->m_source, m->USER_ENDPT,
|
|
||||||
(cp_grant_id_t) m->IO_GRANT, OK);
|
|
||||||
return;
|
|
||||||
case DEV_READ_S:
|
|
||||||
if (kbdp->req_size)
|
|
||||||
{
|
|
||||||
/* We handle only request at a time */
|
|
||||||
r= EIO;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (kbdp->avail == 0)
|
|
||||||
{
|
|
||||||
if (m->FLAGS & FLG_OP_NONBLOCK) {
|
|
||||||
r = EAGAIN;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* Should record proc */
|
|
||||||
kbdp->req_size= m->COUNT;
|
|
||||||
kbdp->req_proc= m->USER_ENDPT;
|
|
||||||
kbdp->req_grant= (cp_grant_id_t) m->IO_GRANT;
|
|
||||||
kbdp->req_addr_offset= 0;
|
|
||||||
kbdp->incaller= m->m_source;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Handle read request */
|
|
||||||
n= kbdp->avail;
|
|
||||||
if (n > m->COUNT)
|
|
||||||
n= m->COUNT;
|
|
||||||
if (kbdp->offset + n > KBD_BUFSZ)
|
|
||||||
n= KBD_BUFSZ-kbdp->offset;
|
|
||||||
if (n <= 0)
|
|
||||||
panic("do_kbd(READ): bad n: %d", n);
|
|
||||||
r= sys_safecopyto(m->m_source, (cp_grant_id_t) m->IO_GRANT, 0,
|
|
||||||
(vir_bytes) &kbdp->buf[kbdp->offset], 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:
|
|
||||||
if (kbdp != &kbdaux)
|
|
||||||
{
|
|
||||||
printf("write to keyboard not implemented\n");
|
|
||||||
r= EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Assume that output to AUX only happens during
|
|
||||||
* initialization and we can afford to lose input. This should
|
|
||||||
* be fixed at a later time.
|
|
||||||
*/
|
|
||||||
for (i= 0; i<m->COUNT; i++)
|
|
||||||
{
|
|
||||||
r= sys_safecopyfrom(m->m_source, (cp_grant_id_t)
|
|
||||||
m->IO_GRANT, i, (vir_bytes) &c, 1);
|
|
||||||
if (r != OK)
|
|
||||||
break;
|
|
||||||
kbc_cmd1(KBC_WRITE_AUX, c);
|
|
||||||
}
|
|
||||||
r= i;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CANCEL:
|
|
||||||
kbdp->req_size= 0;
|
|
||||||
r= EAGAIN;
|
|
||||||
break;
|
|
||||||
case DEV_SELECT:
|
|
||||||
ops = m->DEV_SEL_OPS & (SEL_RD|SEL_WR|SEL_ERR);
|
|
||||||
watch = (m->DEV_SEL_OPS & SEL_NOTIFY) ? 1 : 0;
|
|
||||||
|
|
||||||
r= 0;
|
|
||||||
if (kbdp->avail && (ops & SEL_RD))
|
|
||||||
{
|
|
||||||
r |= SEL_RD;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ops && watch)
|
|
||||||
{
|
|
||||||
kbdp->select_ops |= ops;
|
|
||||||
kbdp->select_proc= m->m_source;
|
|
||||||
kbdp->select_minor= m->DEV_MINOR;
|
|
||||||
}
|
|
||||||
assert(kbdp->minor == m->DEV_MINOR);
|
|
||||||
select_reply(DEV_SEL_REPL1, m->m_source, m->DEV_MINOR, r);
|
|
||||||
return;
|
|
||||||
case DEV_IOCTL_S:
|
|
||||||
if (kbdp == &kbd && m->REQUEST == KIOCSLEDS)
|
|
||||||
{
|
|
||||||
kio_leds_t leds;
|
|
||||||
unsigned char b;
|
|
||||||
|
|
||||||
|
|
||||||
r= sys_safecopyfrom(m->m_source, (cp_grant_id_t)
|
|
||||||
m->IO_GRANT, 0, (vir_bytes) &leds,
|
|
||||||
sizeof(leds));
|
|
||||||
if (r != OK)
|
|
||||||
break;
|
|
||||||
b= 0;
|
|
||||||
if (leds.kl_bits & KBD_LEDS_NUM) b |= NUM_LOCK;
|
|
||||||
if (leds.kl_bits & KBD_LEDS_CAPS) b |= CAPS_LOCK;
|
|
||||||
if (leds.kl_bits & KBD_LEDS_SCROLL) b |= SCROLL_LOCK;
|
|
||||||
if (kbdout.avail == 0)
|
|
||||||
kbdout.offset= 0;
|
|
||||||
if (kbdout.offset + kbdout.avail + 2 > KBD_OUT_BUFSZ)
|
|
||||||
{
|
|
||||||
/* Output buffer is full. Ignore this command.
|
|
||||||
* Reset ACK flag.
|
|
||||||
*/
|
|
||||||
kbdout.expect_ack= 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
kbdout.buf[kbdout.offset+kbdout.avail]=
|
|
||||||
LED_CODE;
|
|
||||||
kbdout.buf[kbdout.offset+kbdout.avail+1]= b;
|
|
||||||
kbdout.avail += 2;
|
|
||||||
}
|
|
||||||
if (!kbdout.expect_ack)
|
|
||||||
kbd_send();
|
|
||||||
r= OK;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (kbdp == &kbd && m->REQUEST == KIOCBELL)
|
|
||||||
{
|
|
||||||
kio_bell_t bell;
|
|
||||||
clock_t ticks;
|
|
||||||
|
|
||||||
r = sys_safecopyfrom(m->m_source, (cp_grant_id_t)
|
|
||||||
m->IO_GRANT, 0, (vir_bytes) &bell,
|
|
||||||
sizeof(bell));
|
|
||||||
if (r != OK)
|
|
||||||
break;
|
|
||||||
|
|
||||||
ticks= bell.kb_duration.tv_usec * system_hz / 1000000;
|
|
||||||
ticks += bell.kb_duration.tv_sec * system_hz;
|
|
||||||
if (!ticks)
|
|
||||||
ticks++;
|
|
||||||
beep_x(bell.kb_pitch, ticks);
|
|
||||||
|
|
||||||
r= OK;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
r= ENOTTY;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
printf("Warning, TTY(kbd) got unexpected request %d from %d\n",
|
|
||||||
m->m_type, m->m_source);
|
|
||||||
r= EINVAL;
|
|
||||||
}
|
|
||||||
tty_reply(DEV_REVIVE, m->m_source, m->USER_ENDPT,
|
|
||||||
(cp_grant_id_t) m->IO_GRANT, r);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* map_key *
|
* map_key *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
@ -469,7 +530,7 @@ void kbd_interrupt(message *UNUSED(m_ptr))
|
||||||
if (n <= 0)
|
if (n <= 0)
|
||||||
panic("kbd_interrupt: bad n: %d", n);
|
panic("kbd_interrupt: bad n: %d", n);
|
||||||
kbdp->req_size= 0;
|
kbdp->req_size= 0;
|
||||||
r= sys_safecopyto(kbdp->incaller, kbdp->req_grant, 0,
|
r= sys_safecopyto(kbdp->req_caller, kbdp->req_grant, 0,
|
||||||
(vir_bytes)&kbdp->buf[kbdp->offset], n);
|
(vir_bytes)&kbdp->buf[kbdp->offset], n);
|
||||||
if (r == OK)
|
if (r == OK)
|
||||||
{
|
{
|
||||||
|
@ -478,14 +539,12 @@ void kbd_interrupt(message *UNUSED(m_ptr))
|
||||||
r= n;
|
r= n;
|
||||||
} else printf("copy in revive kbd failed: %d\n", r);
|
} else printf("copy in revive kbd failed: %d\n", r);
|
||||||
|
|
||||||
tty_reply(DEV_REVIVE, kbdp->incaller, kbdp->req_proc,
|
chardriver_reply_task(kbdp->req_caller, kbdp->req_id, r);
|
||||||
kbdp->req_grant, r);
|
kbdp->req_caller = NONE;
|
||||||
kbdp->req_grant = GRANT_INVALID;
|
|
||||||
}
|
}
|
||||||
/* Only satisfy pending select if characters weren't just read. */
|
/* Only satisfy pending select if characters weren't just read. */
|
||||||
if (kbdp->avail && (kbdp->select_ops & SEL_RD)) {
|
if (kbdp->avail && (kbdp->select_ops & SEL_RD)) {
|
||||||
assert(kbdp->select_minor == kbdp->minor);
|
chardriver_reply_select(kbdp->select_proc, kbdp->minor,
|
||||||
select_reply(DEV_SEL_REPL2, kbdp->select_proc, kbdp->minor,
|
|
||||||
SEL_RD);
|
SEL_RD);
|
||||||
kbdp->select_ops &= ~SEL_RD;
|
kbdp->select_ops &= ~SEL_RD;
|
||||||
}
|
}
|
||||||
|
@ -1024,12 +1083,10 @@ void kb_init_once(void)
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* kbd_loadmap *
|
* kbd_loadmap *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
int kbd_loadmap(m)
|
int kbd_loadmap(endpoint_t endpt, cp_grant_id_t grant)
|
||||||
message *m;
|
|
||||||
{
|
{
|
||||||
/* Load a new keymap. */
|
/* Load a new keymap. */
|
||||||
return sys_safecopyfrom(m->m_source, (cp_grant_id_t) m->IO_GRANT,
|
return sys_safecopyfrom(endpt, grant, 0, (vir_bytes) keymap, sizeof(keymap));
|
||||||
0, (vir_bytes) keymap, (vir_bytes) sizeof(keymap));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
|
|
@ -246,10 +246,11 @@ static int rs_write(register tty_t *tp, int try)
|
||||||
/* Copy from user space to the RS232 output buffer. */
|
/* Copy from user space to the RS232 output buffer. */
|
||||||
if (tp->tty_outcaller == KERNEL) {
|
if (tp->tty_outcaller == KERNEL) {
|
||||||
/* We're trying to print on kernel's behalf */
|
/* We're trying to print on kernel's behalf */
|
||||||
memcpy(rs->ohead, (void *) tp->tty_outgrant + tp->tty_outoffset, count);
|
memcpy(rs->ohead, (char *) tp->tty_outgrant + tp->tty_outcum,
|
||||||
|
count);
|
||||||
} else {
|
} else {
|
||||||
if ((r = sys_safecopyfrom(tp->tty_outcaller, tp->tty_outgrant,
|
if ((r = sys_safecopyfrom(tp->tty_outcaller, tp->tty_outgrant,
|
||||||
tp->tty_outoffset, (vir_bytes) rs->ohead, count)) != OK)
|
tp->tty_outcum, (vir_bytes) rs->ohead, count)) != OK)
|
||||||
printf("TTY: sys_safecopyfrom() failed: %d", r);
|
printf("TTY: sys_safecopyfrom() failed: %d", r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,22 +266,20 @@ static int rs_write(register tty_t *tp, int try)
|
||||||
rs_ostart(rs);
|
rs_ostart(rs);
|
||||||
if ((rs->ohead += ocount) >= bufend(rs->obuf))
|
if ((rs->ohead += ocount) >= bufend(rs->obuf))
|
||||||
rs->ohead -= buflen(rs->obuf);
|
rs->ohead -= buflen(rs->obuf);
|
||||||
tp->tty_outoffset += count;
|
|
||||||
tp->tty_outcum += count;
|
tp->tty_outcum += count;
|
||||||
if ((tp->tty_outleft -= count) == 0) {
|
if ((tp->tty_outleft -= count) == 0) {
|
||||||
/* Output is finished, reply to the writer. */
|
/* Output is finished, reply to the writer. */
|
||||||
tty_reply(DEV_REVIVE, tp->tty_outcaller, tp->tty_outproc,
|
chardriver_reply_task(tp->tty_outcaller, tp->tty_outid,
|
||||||
tp->tty_outgrant, tp->tty_outcum);
|
tp->tty_outcum);
|
||||||
tp->tty_outcum = 0;
|
tp->tty_outcum = 0;
|
||||||
tp->tty_outgrant = GRANT_INVALID;
|
tp->tty_outcaller = NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tp->tty_outleft > 0 && tp->tty_termios.c_ospeed == B0) {
|
if (tp->tty_outleft > 0 && tp->tty_termios.c_ospeed == B0) {
|
||||||
/* Oops, the line has hung up. */
|
/* Oops, the line has hung up. */
|
||||||
tty_reply(DEV_REVIVE, tp->tty_outcaller, tp->tty_outproc,
|
chardriver_reply_task(tp->tty_outcaller, tp->tty_outid, EIO);
|
||||||
tp->tty_outgrant, EIO);
|
|
||||||
tp->tty_outleft = tp->tty_outcum = 0;
|
tp->tty_outleft = tp->tty_outcum = 0;
|
||||||
tp->tty_outgrant = GRANT_INVALID;
|
tp->tty_outcaller = NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -9,20 +9,16 @@
|
||||||
* This file takes care of copying data between the tty/pty device pairs and
|
* This file takes care of copying data between the tty/pty device pairs and
|
||||||
* the open/read/write/close calls on the pty devices. The TTY task takes
|
* the open/read/write/close calls on the pty devices. The TTY task takes
|
||||||
* care of the input and output processing (interrupt, backspace, raw I/O,
|
* care of the input and output processing (interrupt, backspace, raw I/O,
|
||||||
* etc.) using the pty_read() and pty_write() functions as the "keyboard" and
|
* etc.) using the pty_slave_read() and pty_slave_write() functions as the
|
||||||
* "screen" functions of the ttypX devices.
|
* "keyboard" and "screen" functions of the ttypX devices.
|
||||||
* Be careful when reading this code, the terms "reading" and "writing" are
|
* Be careful when reading this code, the terms "reading" and "writing" are
|
||||||
* used both for the tty and the pty end of the pseudo tty. Writes to one
|
* used both for the tty (slave) and the pty (master) end of the pseudo tty.
|
||||||
* end are to be read at the other end and vice-versa.
|
* Writes to one end are to be read at the other end and vice-versa.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <minix/drivers.h>
|
#include <minix/drivers.h>
|
||||||
#include <assert.h>
|
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <minix/com.h>
|
|
||||||
#include <minix/callnr.h>
|
|
||||||
#include <sys/select.h>
|
|
||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
|
|
||||||
#if NR_PTYS > 0
|
#if NR_PTYS > 0
|
||||||
|
@ -32,21 +28,19 @@ typedef struct pty {
|
||||||
tty_t *tty; /* associated TTY structure */
|
tty_t *tty; /* associated TTY structure */
|
||||||
char state; /* flags: busy, closed, ... */
|
char state; /* flags: busy, closed, ... */
|
||||||
|
|
||||||
/* Read call on /dev/ptypX. */
|
/* Read call on master (/dev/ptypX). */
|
||||||
int rdcaller; /* process making the call (usually FS) */
|
endpoint_t rdcaller; /* process making the call, or NONE if none */
|
||||||
int rdproc; /* process that wants to read from the pty */
|
cdev_id_t rdid; /* ID of suspended read request */
|
||||||
cp_grant_id_t rdgrant; /* grant for readers address space */
|
cp_grant_id_t rdgrant; /* grant for reader's address space */
|
||||||
vir_bytes rdoffset; /* offset in above grant */
|
size_t rdleft; /* # bytes yet to be read */
|
||||||
int rdleft; /* # bytes yet to be read */
|
size_t rdcum; /* # bytes written so far */
|
||||||
int rdcum; /* # bytes written so far */
|
|
||||||
|
|
||||||
/* Write call to /dev/ptypX. */
|
/* Write call to master (/dev/ptypX). */
|
||||||
int wrcaller; /* process making the call (usually FS) */
|
endpoint_t wrcaller; /* process making the call, or NONE if none*/
|
||||||
int wrproc; /* process that wants to write to the pty */
|
cdev_id_t wrid; /* ID of suspended write request */
|
||||||
cp_grant_id_t wrgrant; /* grant for writers address space */
|
cp_grant_id_t wrgrant; /* grant for writer's address space */
|
||||||
vir_bytes wroffset; /* offset in above grant */
|
size_t wrleft; /* # bytes yet to be written */
|
||||||
int wrleft; /* # bytes yet to be written */
|
size_t wrcum; /* # bytes written so far */
|
||||||
int wrcum; /* # bytes written so far */
|
|
||||||
|
|
||||||
/* Output buffer. */
|
/* Output buffer. */
|
||||||
int ocount; /* # characters in the buffer */
|
int ocount; /* # characters in the buffer */
|
||||||
|
@ -54,9 +48,8 @@ typedef struct pty {
|
||||||
char obuf[2048]; /* buffer for bytes going to the pty reader */
|
char obuf[2048]; /* buffer for bytes going to the pty reader */
|
||||||
|
|
||||||
/* select() data. */
|
/* select() data. */
|
||||||
int select_ops; /* Which operations do we want to know about? */
|
unsigned int select_ops; /* Which operations do we want to know about? */
|
||||||
int select_proc; /* Who wants to know about it? */
|
endpoint_t select_proc; /* Who wants to know about it? */
|
||||||
dev_t select_minor; /* sanity check only, can be removed */
|
|
||||||
} pty_t;
|
} pty_t;
|
||||||
|
|
||||||
#define TTY_ACTIVE 0x01 /* tty is open/active */
|
#define TTY_ACTIVE 0x01 /* tty is open/active */
|
||||||
|
@ -66,159 +59,288 @@ typedef struct pty {
|
||||||
|
|
||||||
static pty_t pty_table[NR_PTYS]; /* PTY bookkeeping */
|
static pty_t pty_table[NR_PTYS]; /* PTY bookkeeping */
|
||||||
|
|
||||||
static int pty_write(tty_t *tp, int try);
|
|
||||||
static void pty_echo(tty_t *tp, int c);
|
|
||||||
static void pty_start(pty_t *pp);
|
static void pty_start(pty_t *pp);
|
||||||
static void pty_finish(pty_t *pp);
|
static void pty_finish(pty_t *pp);
|
||||||
static int pty_read(tty_t *tp, int try);
|
|
||||||
static int pty_close(tty_t *tp, int try);
|
static int pty_master_open(devminor_t minor, int access,
|
||||||
static int pty_icancel(tty_t *tp, int try);
|
endpoint_t user_endpt);
|
||||||
static int pty_ocancel(tty_t *tp, int try);
|
static int pty_master_close(devminor_t minor);
|
||||||
static void pty_select(tty_t *tp, message *m);
|
static ssize_t pty_master_read(devminor_t minor, u64_t position,
|
||||||
|
endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags,
|
||||||
|
cdev_id_t id);
|
||||||
|
static ssize_t pty_master_write(devminor_t minor, u64_t position,
|
||||||
|
endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags,
|
||||||
|
cdev_id_t id);
|
||||||
|
static int pty_master_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id);
|
||||||
|
static int pty_master_select(devminor_t minor, unsigned int ops,
|
||||||
|
endpoint_t endpt);
|
||||||
|
|
||||||
|
static struct chardriver pty_master_tab = {
|
||||||
|
.cdr_open = pty_master_open,
|
||||||
|
.cdr_close = pty_master_close,
|
||||||
|
.cdr_read = pty_master_read,
|
||||||
|
.cdr_write = pty_master_write,
|
||||||
|
.cdr_cancel = pty_master_cancel,
|
||||||
|
.cdr_select = pty_master_select
|
||||||
|
};
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* pty_master_open *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int pty_master_open(devminor_t minor, int UNUSED(access),
|
||||||
|
endpoint_t UNUSED(user_endpt))
|
||||||
|
{
|
||||||
|
tty_t *tp;
|
||||||
|
pty_t *pp;
|
||||||
|
|
||||||
|
if ((tp = line2tty(minor)) == NULL)
|
||||||
|
return ENXIO;
|
||||||
|
pp = tp->tty_priv;
|
||||||
|
|
||||||
|
if (pp->state & PTY_ACTIVE)
|
||||||
|
return EIO;
|
||||||
|
|
||||||
|
pp->state |= PTY_ACTIVE;
|
||||||
|
pp->rdcum = 0;
|
||||||
|
pp->wrcum = 0;
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* pty_master_close *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int pty_master_close(devminor_t minor)
|
||||||
|
{
|
||||||
|
tty_t *tp;
|
||||||
|
pty_t *pp;
|
||||||
|
|
||||||
|
if ((tp = line2tty(minor)) == NULL)
|
||||||
|
return ENXIO;
|
||||||
|
pp = tp->tty_priv;
|
||||||
|
|
||||||
|
if ((pp->state & (TTY_ACTIVE | TTY_CLOSED)) != TTY_ACTIVE) {
|
||||||
|
pp->state = 0;
|
||||||
|
} else {
|
||||||
|
pp->state |= PTY_CLOSED;
|
||||||
|
sigchar(tp, SIGHUP, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* pty_master_read *
|
||||||
|
*===========================================================================*/
|
||||||
|
static ssize_t pty_master_read(devminor_t minor, u64_t UNUSED(position),
|
||||||
|
endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags,
|
||||||
|
cdev_id_t id)
|
||||||
|
{
|
||||||
|
tty_t *tp;
|
||||||
|
pty_t *pp;
|
||||||
|
ssize_t r;
|
||||||
|
|
||||||
|
if ((tp = line2tty(minor)) == NULL)
|
||||||
|
return ENXIO;
|
||||||
|
pp = tp->tty_priv;
|
||||||
|
|
||||||
|
/* Check, store information on the reader, do I/O. */
|
||||||
|
if (pp->state & TTY_CLOSED)
|
||||||
|
return 0; /* EOF */
|
||||||
|
|
||||||
|
if (pp->rdcaller != NONE || pp->rdleft != 0 || pp->rdcum != 0)
|
||||||
|
return EIO;
|
||||||
|
|
||||||
|
if (size <= 0)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
pp->rdcaller = endpt;
|
||||||
|
pp->rdid = id;
|
||||||
|
pp->rdgrant = grant;
|
||||||
|
pp->rdleft = size;
|
||||||
|
pty_start(pp);
|
||||||
|
|
||||||
|
handle_events(tp);
|
||||||
|
|
||||||
|
if (pp->rdleft == 0) {
|
||||||
|
pp->rdcaller = NONE;
|
||||||
|
return EDONTREPLY; /* already done */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & FLG_OP_NONBLOCK) {
|
||||||
|
r = pp->rdcum > 0 ? pp->rdcum : EAGAIN;
|
||||||
|
pp->rdleft = pp->rdcum = 0;
|
||||||
|
pp->rdcaller = NONE;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EDONTREPLY; /* do suspend */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* pty_master_write *
|
||||||
|
*===========================================================================*/
|
||||||
|
static ssize_t pty_master_write(devminor_t minor, u64_t UNUSED(position),
|
||||||
|
endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags,
|
||||||
|
cdev_id_t id)
|
||||||
|
{
|
||||||
|
tty_t *tp;
|
||||||
|
pty_t *pp;
|
||||||
|
ssize_t r;
|
||||||
|
|
||||||
|
if ((tp = line2tty(minor)) == NULL)
|
||||||
|
return ENXIO;
|
||||||
|
pp = tp->tty_priv;
|
||||||
|
|
||||||
|
/* Check, store information on the writer, do I/O. */
|
||||||
|
if (pp->state & TTY_CLOSED)
|
||||||
|
return EIO;
|
||||||
|
|
||||||
|
if (pp->wrcaller != NONE || pp->wrleft != 0 || pp->wrcum != 0)
|
||||||
|
return EIO;
|
||||||
|
|
||||||
|
if (size <= 0)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
pp->wrcaller = endpt;
|
||||||
|
pp->wrid = id;
|
||||||
|
pp->wrgrant = grant;
|
||||||
|
pp->wrleft = size;
|
||||||
|
|
||||||
|
handle_events(tp);
|
||||||
|
|
||||||
|
if (pp->wrleft == 0) {
|
||||||
|
pp->wrcaller = NONE;
|
||||||
|
return EDONTREPLY; /* already done */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & FLG_OP_NONBLOCK) {
|
||||||
|
r = pp->wrcum > 0 ? pp->wrcum : EAGAIN;
|
||||||
|
pp->wrleft = pp->wrcum = 0;
|
||||||
|
pp->wrcaller = NONE;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EDONTREPLY; /* do suspend */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* pty_master_cancel *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int pty_master_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id)
|
||||||
|
{
|
||||||
|
tty_t *tp;
|
||||||
|
pty_t *pp;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if ((tp = line2tty(minor)) == NULL)
|
||||||
|
return ENXIO;
|
||||||
|
pp = tp->tty_priv;
|
||||||
|
|
||||||
|
if (pp->rdcaller == endpt && pp->rdid == id) {
|
||||||
|
/* Cancel a read from a PTY. */
|
||||||
|
r = pp->rdcum > 0 ? pp->rdcum : EINTR;
|
||||||
|
pp->rdleft = pp->rdcum = 0;
|
||||||
|
pp->rdcaller = NONE;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pp->wrcaller == endpt && pp->wrid == id) {
|
||||||
|
/* Cancel a write to a PTY. */
|
||||||
|
r = pp->wrcum > 0 ? pp->wrcum : EINTR;
|
||||||
|
pp->wrleft = pp->wrcum = 0;
|
||||||
|
pp->wrcaller = NONE;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Request not found. */
|
||||||
|
return EDONTREPLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* select_try_pty *
|
||||||
|
*===========================================================================*/
|
||||||
|
static 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 if (tp->tty_inleft > 0) r |= SEL_WR; /* There's a reader. */
|
||||||
|
}
|
||||||
|
|
||||||
|
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 *
|
||||||
|
*===========================================================================*/
|
||||||
|
void select_retry_pty(tty_t *tp)
|
||||||
|
{
|
||||||
|
pty_t *pp = tp->tty_priv;
|
||||||
|
devminor_t minor;
|
||||||
|
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))) {
|
||||||
|
minor = PTYPX_MINOR + (int) (pp - pty_table);
|
||||||
|
chardriver_reply_select(pp->select_proc, minor, r);
|
||||||
|
pp->select_ops &= ~r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* pty_master_select *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int pty_master_select(devminor_t minor, unsigned int ops,
|
||||||
|
endpoint_t endpt)
|
||||||
|
{
|
||||||
|
tty_t *tp;
|
||||||
|
pty_t *pp;
|
||||||
|
int ready_ops, watch;
|
||||||
|
|
||||||
|
if ((tp = line2tty(minor)) == NULL)
|
||||||
|
return ENXIO;
|
||||||
|
pp = tp->tty_priv;
|
||||||
|
|
||||||
|
watch = (ops & SEL_NOTIFY);
|
||||||
|
ops &= (SEL_RD | SEL_WR | SEL_ERR);
|
||||||
|
|
||||||
|
ready_ops = select_try_pty(tp, ops);
|
||||||
|
|
||||||
|
ops &= ~ready_ops;
|
||||||
|
if (ops && watch) {
|
||||||
|
pp->select_ops |= ops;
|
||||||
|
pp->select_proc = endpt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ready_ops;
|
||||||
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* do_pty *
|
* do_pty *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
void do_pty(tty_t *tp, message *m_ptr)
|
void do_pty(message *m_ptr, int ipc_status)
|
||||||
{
|
{
|
||||||
/* Perform an open/close/read/write call on a /dev/ptypX device. */
|
/* Process a request for a PTY master (/dev/ptypX) device. */
|
||||||
pty_t *pp = tp->tty_priv;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
switch (m_ptr->m_type) {
|
chardriver_process(&pty_master_tab, m_ptr, ipc_status);
|
||||||
case DEV_READ_S:
|
|
||||||
/* Check, store information on the reader, do I/O. */
|
|
||||||
if (pp->state & TTY_CLOSED) {
|
|
||||||
r = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (pp->rdleft != 0 || pp->rdcum != 0) {
|
|
||||||
r = EIO;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (m_ptr->COUNT <= 0) {
|
|
||||||
r = EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (pp->rdgrant != GRANT_INVALID) {
|
|
||||||
r = ENOBUFS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
pp->rdcaller = m_ptr->m_source;
|
|
||||||
pp->rdproc = m_ptr->USER_ENDPT;
|
|
||||||
pp->rdgrant = (cp_grant_id_t) m_ptr->IO_GRANT;
|
|
||||||
pp->rdoffset = 0;
|
|
||||||
pp->rdleft = m_ptr->COUNT;
|
|
||||||
pty_start(pp);
|
|
||||||
handle_events(tp);
|
|
||||||
if (pp->rdleft == 0) {
|
|
||||||
pp->rdgrant = GRANT_INVALID;
|
|
||||||
return; /* already done */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_ptr->FLAGS & FLG_OP_NONBLOCK) {
|
|
||||||
r = pp->rdcum > 0 ? pp->rdcum : EAGAIN;
|
|
||||||
pp->rdleft = pp->rdcum = 0;
|
|
||||||
pp->rdgrant = GRANT_INVALID;
|
|
||||||
} else {
|
|
||||||
return; /* do suspend */
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DEV_WRITE_S:
|
|
||||||
/* Check, store information on the writer, do I/O. */
|
|
||||||
if (pp->state & TTY_CLOSED) {
|
|
||||||
r = EIO;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (pp->wrleft != 0 || pp->wrcum != 0) {
|
|
||||||
r = EIO;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (m_ptr->COUNT <= 0) {
|
|
||||||
r = EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (pp->wrgrant != GRANT_INVALID) {
|
|
||||||
r = ENOBUFS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
pp->wrcaller = m_ptr->m_source;
|
|
||||||
pp->wrproc = m_ptr->USER_ENDPT;
|
|
||||||
pp->wrgrant = (cp_grant_id_t) m_ptr->IO_GRANT;
|
|
||||||
pp->wroffset = 0;
|
|
||||||
pp->wrleft = m_ptr->COUNT;
|
|
||||||
handle_events(tp);
|
|
||||||
if (pp->wrleft == 0) {
|
|
||||||
pp->wrgrant = GRANT_INVALID;
|
|
||||||
return; /* already done */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_ptr->FLAGS & FLG_OP_NONBLOCK) {
|
|
||||||
r = pp->wrcum > 0 ? pp->wrcum : EAGAIN;
|
|
||||||
pp->wrleft = pp->wrcum = 0;
|
|
||||||
pp->wrgrant = GRANT_INVALID;
|
|
||||||
r = EAGAIN;
|
|
||||||
} else {
|
|
||||||
return; /* do suspend */
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DEV_OPEN:
|
|
||||||
if (!(pp->state & PTY_ACTIVE)) {
|
|
||||||
pp->state |= PTY_ACTIVE;
|
|
||||||
pp->rdcum = 0;
|
|
||||||
pp->wrcum = 0;
|
|
||||||
r = OK;
|
|
||||||
} else {
|
|
||||||
r = EIO;
|
|
||||||
}
|
|
||||||
tty_reply(DEV_OPEN_REPL, m_ptr->m_source, m_ptr->USER_ENDPT,
|
|
||||||
(cp_grant_id_t) m_ptr->IO_GRANT, r);
|
|
||||||
return;
|
|
||||||
|
|
||||||
case DEV_CLOSE:
|
|
||||||
if ((pp->state & (TTY_ACTIVE | TTY_CLOSED)) != TTY_ACTIVE) {
|
|
||||||
pp->state = 0;
|
|
||||||
} else {
|
|
||||||
pp->state |= PTY_CLOSED;
|
|
||||||
sigchar(tp, SIGHUP, 1);
|
|
||||||
}
|
|
||||||
tty_reply(DEV_CLOSE_REPL, m_ptr->m_source, m_ptr->USER_ENDPT,
|
|
||||||
(cp_grant_id_t) m_ptr->IO_GRANT, OK);
|
|
||||||
return;
|
|
||||||
|
|
||||||
case DEV_SELECT:
|
|
||||||
pty_select(tp, m_ptr);
|
|
||||||
return;
|
|
||||||
|
|
||||||
case CANCEL:
|
|
||||||
r = EINTR;
|
|
||||||
if (m_ptr->USER_ENDPT == pp->rdproc) {
|
|
||||||
/* Cancel a read from a PTY. */
|
|
||||||
r = pp->rdcum > 0 ? pp->rdcum : EAGAIN;
|
|
||||||
pp->rdleft = pp->rdcum = 0;
|
|
||||||
pp->rdgrant = GRANT_INVALID;
|
|
||||||
}
|
|
||||||
if (m_ptr->USER_ENDPT == pp->wrproc) {
|
|
||||||
/* Cancel a write to a PTY. */
|
|
||||||
r = pp->wrcum > 0 ? pp->wrcum : EAGAIN;
|
|
||||||
pp->wrleft = pp->wrcum = 0;
|
|
||||||
pp->wrgrant = GRANT_INVALID;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
r = EINVAL;
|
|
||||||
}
|
|
||||||
tty_reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT,
|
|
||||||
(cp_grant_id_t) m_ptr->IO_GRANT, r);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* pty_write *
|
* pty_slave_write *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
static int pty_write(tty_t *tp, int try)
|
static int pty_slave_write(tty_t *tp, int try)
|
||||||
{
|
{
|
||||||
/* (*dev_write)() routine for PTYs. Transfer bytes from the writer on
|
/* (*dev_write)() routine for PTYs. Transfer bytes from the writer on
|
||||||
* /dev/ttypX to the output buffer.
|
* /dev/ttypX to the output buffer.
|
||||||
|
@ -226,15 +348,13 @@ static int pty_write(tty_t *tp, int try)
|
||||||
pty_t *pp = tp->tty_priv;
|
pty_t *pp = tp->tty_priv;
|
||||||
int count, ocount, s;
|
int count, ocount, s;
|
||||||
|
|
||||||
|
|
||||||
/* PTY closed down? */
|
/* PTY closed down? */
|
||||||
if (pp->state & PTY_CLOSED) {
|
if (pp->state & PTY_CLOSED) {
|
||||||
if (try) return 1;
|
if (try) return 1;
|
||||||
if (tp->tty_outleft > 0) {
|
if (tp->tty_outleft > 0) {
|
||||||
tty_reply(DEV_REVIVE, tp->tty_outcaller, tp->tty_outproc,
|
chardriver_reply_task(tp->tty_outcaller, tp->tty_outid, EIO);
|
||||||
tp->tty_outgrant, EIO);
|
|
||||||
tp->tty_outleft = tp->tty_outcum = 0;
|
tp->tty_outleft = tp->tty_outcum = 0;
|
||||||
tp->tty_outgrant = GRANT_INVALID;
|
tp->tty_outcaller = NONE;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -252,11 +372,11 @@ static int pty_write(tty_t *tp, int try)
|
||||||
/* Copy from user space to the PTY output buffer. */
|
/* Copy from user space to the PTY output buffer. */
|
||||||
if (tp->tty_outcaller == KERNEL) {
|
if (tp->tty_outcaller == KERNEL) {
|
||||||
/* We're trying to print on kernel's behalf */
|
/* We're trying to print on kernel's behalf */
|
||||||
memcpy(pp->ohead, (void *) tp->tty_outgrant + tp->tty_outoffset,
|
memcpy(pp->ohead, (void *) tp->tty_outgrant + tp->tty_outcum,
|
||||||
count);
|
count);
|
||||||
} else {
|
} else {
|
||||||
if ((s = sys_safecopyfrom(tp->tty_outcaller, tp->tty_outgrant,
|
if ((s = sys_safecopyfrom(tp->tty_outcaller, tp->tty_outgrant,
|
||||||
tp->tty_outoffset, (vir_bytes) pp->ohead,
|
tp->tty_outcum, (vir_bytes) pp->ohead,
|
||||||
count)) != OK) {
|
count)) != OK) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -275,15 +395,13 @@ static int pty_write(tty_t *tp, int try)
|
||||||
pp->ohead -= buflen(pp->obuf);
|
pp->ohead -= buflen(pp->obuf);
|
||||||
pty_start(pp);
|
pty_start(pp);
|
||||||
|
|
||||||
tp->tty_outoffset += count;
|
|
||||||
|
|
||||||
tp->tty_outcum += count;
|
tp->tty_outcum += count;
|
||||||
if ((tp->tty_outleft -= count) == 0) {
|
if ((tp->tty_outleft -= count) == 0) {
|
||||||
/* Output is finished, reply to the writer. */
|
/* Output is finished, reply to the writer. */
|
||||||
tty_reply(DEV_REVIVE, tp->tty_outcaller, tp->tty_outproc,
|
chardriver_reply_task(tp->tty_outcaller, tp->tty_outid,
|
||||||
tp->tty_outgrant, tp->tty_outcum);
|
tp->tty_outcum);
|
||||||
tp->tty_outcum = 0;
|
tp->tty_outcum = 0;
|
||||||
tp->tty_outgrant = GRANT_INVALID;
|
tp->tty_outcaller = NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pty_finish(pp);
|
pty_finish(pp);
|
||||||
|
@ -291,9 +409,9 @@ static int pty_write(tty_t *tp, int try)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* pty_echo *
|
* pty_slave_echo *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
static void pty_echo(tty_t *tp, int c)
|
static void pty_slave_echo(tty_t *tp, int c)
|
||||||
{
|
{
|
||||||
/* Echo one character. (Like pty_write, but only one character, optionally.) */
|
/* Echo one character. (Like pty_write, but only one character, optionally.) */
|
||||||
|
|
||||||
|
@ -330,11 +448,10 @@ static void pty_start(pty_t *pp)
|
||||||
if (count == 0) break;
|
if (count == 0) break;
|
||||||
|
|
||||||
/* Copy from the output buffer to the readers address space. */
|
/* Copy from the output buffer to the readers address space. */
|
||||||
if((s = sys_safecopyto(pp->rdcaller, pp->rdgrant,
|
if((s = sys_safecopyto(pp->rdcaller, pp->rdgrant, pp->rdcum,
|
||||||
pp->rdoffset, (vir_bytes) pp->otail, count)) != OK) {
|
(vir_bytes) pp->otail, count)) != OK) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pp->rdoffset += count;
|
|
||||||
|
|
||||||
/* Bookkeeping. */
|
/* Bookkeeping. */
|
||||||
pp->ocount -= count;
|
pp->ocount -= count;
|
||||||
|
@ -352,19 +469,18 @@ static void pty_finish(pty_t *pp)
|
||||||
/* Finish the read request of a PTY reader if there is at least one byte
|
/* Finish the read request of a PTY reader if there is at least one byte
|
||||||
* transferred.
|
* transferred.
|
||||||
*/
|
*/
|
||||||
if (pp->rdcum > 0) {
|
|
||||||
tty_reply(DEV_REVIVE, pp->rdcaller, pp->rdproc, pp->rdgrant,
|
|
||||||
pp->rdcum);
|
|
||||||
pp->rdleft = pp->rdcum = 0;
|
|
||||||
pp->rdgrant = GRANT_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (pp->rdcum > 0) {
|
||||||
|
chardriver_reply_task(pp->rdcaller, pp->rdid, pp->rdcum);
|
||||||
|
pp->rdleft = pp->rdcum = 0;
|
||||||
|
pp->rdcaller = NONE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* pty_read *
|
* pty_slave_read *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
static int pty_read(tty_t *tp, int try)
|
static int pty_slave_read(tty_t *tp, int try)
|
||||||
{
|
{
|
||||||
/* Offer bytes from the PTY writer for input on the TTY. (Do it one byte at
|
/* Offer bytes from the PTY writer for input on the TTY. (Do it one byte at
|
||||||
* a time, 99% of the writes will be for one byte, so no sense in being smart.)
|
* a time, 99% of the writes will be for one byte, so no sense in being smart.)
|
||||||
|
@ -375,10 +491,10 @@ static int pty_read(tty_t *tp, int try)
|
||||||
if (pp->state & PTY_CLOSED) {
|
if (pp->state & PTY_CLOSED) {
|
||||||
if (try) return 1;
|
if (try) return 1;
|
||||||
if (tp->tty_inleft > 0) {
|
if (tp->tty_inleft > 0) {
|
||||||
tty_reply(DEV_REVIVE, tp->tty_incaller, tp->tty_inproc,
|
chardriver_reply_task(tp->tty_incaller, tp->tty_inid,
|
||||||
tp->tty_ingrant, tp->tty_incum);
|
tp->tty_incum);
|
||||||
tp->tty_inleft = tp->tty_incum = 0;
|
tp->tty_inleft = tp->tty_incum = 0;
|
||||||
tp->tty_ingrant = GRANT_INVALID;
|
tp->tty_incaller = NONE;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -393,12 +509,11 @@ static int pty_read(tty_t *tp, int try)
|
||||||
int s;
|
int s;
|
||||||
|
|
||||||
/* Transfer one character to 'c'. */
|
/* Transfer one character to 'c'. */
|
||||||
if ((s = sys_safecopyfrom(pp->wrcaller, pp->wrgrant, pp->wroffset,
|
if ((s = sys_safecopyfrom(pp->wrcaller, pp->wrgrant, pp->wrcum,
|
||||||
(vir_bytes) &c, 1)) != OK) {
|
(vir_bytes) &c, 1)) != OK) {
|
||||||
printf("pty: safecopy failed (error %d)\n", s);
|
printf("pty: safecopy failed (error %d)\n", s);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pp->wroffset++;
|
|
||||||
|
|
||||||
/* Input processing. */
|
/* Input processing. */
|
||||||
if (in_process(tp, &c, 1, -1) == 0) break;
|
if (in_process(tp, &c, 1, -1) == 0) break;
|
||||||
|
@ -406,10 +521,9 @@ static int pty_read(tty_t *tp, int try)
|
||||||
/* PTY writer bookkeeping. */
|
/* PTY writer bookkeeping. */
|
||||||
pp->wrcum++;
|
pp->wrcum++;
|
||||||
if (--pp->wrleft == 0) {
|
if (--pp->wrleft == 0) {
|
||||||
tty_reply(DEV_REVIVE, pp->wrcaller, pp->wrproc, pp->wrgrant,
|
chardriver_reply_task(pp->wrcaller, pp->wrid, pp->wrcum);
|
||||||
pp->wrcum);
|
|
||||||
pp->wrcum = 0;
|
pp->wrcum = 0;
|
||||||
pp->wrgrant = GRANT_INVALID;
|
pp->wrcaller = NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,9 +531,9 @@ static int pty_read(tty_t *tp, int try)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* pty_open *
|
* pty_slave_open *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
static int pty_open(tty_t *tp, int UNUSED(try))
|
static int pty_slave_open(tty_t *tp, int UNUSED(try))
|
||||||
{
|
{
|
||||||
/* The tty side has been opened. */
|
/* The tty side has been opened. */
|
||||||
pty_t *pp = tp->tty_priv;
|
pty_t *pp = tp->tty_priv;
|
||||||
|
@ -435,9 +549,9 @@ static int pty_open(tty_t *tp, int UNUSED(try))
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* pty_close *
|
* pty_slave_close *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
static int pty_close(tty_t *tp, int UNUSED(try))
|
static int pty_slave_close(tty_t *tp, int UNUSED(try))
|
||||||
{
|
{
|
||||||
/* The tty side has closed, so shut down the pty side. */
|
/* The tty side has closed, so shut down the pty side. */
|
||||||
pty_t *pp = tp->tty_priv;
|
pty_t *pp = tp->tty_priv;
|
||||||
|
@ -445,17 +559,15 @@ static int pty_close(tty_t *tp, int UNUSED(try))
|
||||||
if (!(pp->state & PTY_ACTIVE)) return 0;
|
if (!(pp->state & PTY_ACTIVE)) return 0;
|
||||||
|
|
||||||
if (pp->rdleft > 0) {
|
if (pp->rdleft > 0) {
|
||||||
tty_reply(DEV_REVIVE, pp->rdcaller, pp->rdproc, pp->rdgrant,
|
chardriver_reply_task(pp->rdcaller, pp->rdid, pp->rdcum);
|
||||||
pp->rdcum);
|
|
||||||
pp->rdleft = pp->rdcum = 0;
|
pp->rdleft = pp->rdcum = 0;
|
||||||
pp->rdgrant = GRANT_INVALID;
|
pp->rdcaller = NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pp->wrleft > 0) {
|
if (pp->wrleft > 0) {
|
||||||
tty_reply(DEV_REVIVE, pp->wrcaller, pp->wrproc, pp->wrgrant,
|
chardriver_reply_task(pp->wrcaller, pp->wrid, pp->wrcum);
|
||||||
pp->wrcum);
|
pp->wrleft = pp->wrcum = 0;
|
||||||
pp->wrcum = 0;
|
pp->wrcaller = NONE;
|
||||||
pp->wrgrant = GRANT_INVALID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pp->state & PTY_CLOSED) pp->state = 0;
|
if (pp->state & PTY_CLOSED) pp->state = 0;
|
||||||
|
@ -465,27 +577,26 @@ static int pty_close(tty_t *tp, int UNUSED(try))
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* pty_icancel *
|
* pty_slave_icancel *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
static int pty_icancel(tty_t *tp, int UNUSED(try))
|
static int pty_slave_icancel(tty_t *tp, int UNUSED(try))
|
||||||
{
|
{
|
||||||
/* Discard waiting input. */
|
/* Discard waiting input. */
|
||||||
pty_t *pp = tp->tty_priv;
|
pty_t *pp = tp->tty_priv;
|
||||||
|
|
||||||
if (pp->wrleft > 0) {
|
if (pp->wrleft > 0) {
|
||||||
tty_reply(DEV_REVIVE, pp->wrcaller, pp->wrproc, pp->wrgrant,
|
chardriver_reply_task(pp->wrcaller, pp->wrid, pp->wrcum + pp->wrleft);
|
||||||
pp->wrcum + pp->wrleft);
|
|
||||||
pp->wrcum = pp->wrleft = 0;
|
pp->wrcum = pp->wrleft = 0;
|
||||||
pp->wrgrant = GRANT_INVALID;
|
pp->wrcaller = NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* pty_ocancel *
|
* pty_slave_ocancel *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
static int pty_ocancel(tty_t *tp, int UNUSED(try))
|
static int pty_slave_ocancel(tty_t *tp, int UNUSED(try))
|
||||||
{
|
{
|
||||||
/* Drain the output buffer. */
|
/* Drain the output buffer. */
|
||||||
pty_t *pp = tp->tty_priv;
|
pty_t *pp = tp->tty_priv;
|
||||||
|
@ -509,86 +620,21 @@ void pty_init(tty_t *tp)
|
||||||
pp = tp->tty_priv = &pty_table[line];
|
pp = tp->tty_priv = &pty_table[line];
|
||||||
pp->tty = tp;
|
pp->tty = tp;
|
||||||
pp->select_ops = 0;
|
pp->select_ops = 0;
|
||||||
pp->rdgrant = GRANT_INVALID;
|
pp->rdcaller = NONE;
|
||||||
pp->wrgrant = GRANT_INVALID;
|
pp->wrcaller = NONE;
|
||||||
|
|
||||||
/* Set up output queue. */
|
/* Set up output queue. */
|
||||||
pp->ohead = pp->otail = pp->obuf;
|
pp->ohead = pp->otail = pp->obuf;
|
||||||
|
|
||||||
/* Fill in TTY function hooks. */
|
/* Fill in TTY function hooks. */
|
||||||
tp->tty_devread = pty_read;
|
tp->tty_devread = pty_slave_read;
|
||||||
tp->tty_devwrite = pty_write;
|
tp->tty_devwrite = pty_slave_write;
|
||||||
tp->tty_echo = pty_echo;
|
tp->tty_echo = pty_slave_echo;
|
||||||
tp->tty_icancel = pty_icancel;
|
tp->tty_icancel = pty_slave_icancel;
|
||||||
tp->tty_ocancel = pty_ocancel;
|
tp->tty_ocancel = pty_slave_ocancel;
|
||||||
tp->tty_open = pty_open;
|
tp->tty_open = pty_slave_open;
|
||||||
tp->tty_close = pty_close;
|
tp->tty_close = pty_slave_close;
|
||||||
tp->tty_select_ops = 0;
|
tp->tty_select_ops = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
|
||||||
* select_try_pty *
|
|
||||||
*===========================================================================*/
|
|
||||||
static 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 *
|
|
||||||
*===========================================================================*/
|
|
||||||
void select_retry_pty(tty_t *tp)
|
|
||||||
{
|
|
||||||
pty_t *pp = tp->tty_priv;
|
|
||||||
dev_t minor;
|
|
||||||
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))) {
|
|
||||||
minor = PTYPX_MINOR + (int) (pp - pty_table);
|
|
||||||
assert(minor == pp->select_minor);
|
|
||||||
select_reply(DEV_SEL_REPL2, pp->select_proc, minor, r);
|
|
||||||
pp->select_ops &= ~r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*===========================================================================*
|
|
||||||
* pty_select *
|
|
||||||
*===========================================================================*/
|
|
||||||
static void pty_select(tty_t *tp, message *m)
|
|
||||||
{
|
|
||||||
pty_t *pp = tp->tty_priv;
|
|
||||||
int ops, ready_ops = 0, watch;
|
|
||||||
|
|
||||||
ops = m->DEV_SEL_OPS & (SEL_RD|SEL_WR|SEL_ERR);
|
|
||||||
watch = (m->DEV_SEL_OPS & 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;
|
|
||||||
pp->select_minor = m->DEV_MINOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
select_reply(DEV_SEL_REPL1, m->m_source, m->DEV_MINOR, ready_ops);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* NR_PTYS > 0 */
|
#endif /* NR_PTYS > 0 */
|
||||||
|
|
|
@ -60,11 +60,7 @@
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <sys/ioc_tty.h>
|
#include <sys/ioc_tty.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <minix/callnr.h>
|
|
||||||
#include <minix/sys_config.h>
|
|
||||||
#include <minix/tty.h>
|
|
||||||
#include <minix/keymap.h>
|
#include <minix/keymap.h>
|
||||||
#include <minix/endpoint.h>
|
|
||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
|
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
@ -101,13 +97,6 @@ struct kmessages kmess;
|
||||||
|
|
||||||
static void tty_timed_out(timer_t *tp);
|
static void tty_timed_out(timer_t *tp);
|
||||||
static void settimer(tty_t *tty_ptr, int enable);
|
static void settimer(tty_t *tty_ptr, int enable);
|
||||||
static void do_cancel(tty_t *tp, message *m_ptr);
|
|
||||||
static void do_ioctl(tty_t *tp, message *m_ptr);
|
|
||||||
static void do_open(tty_t *tp, message *m_ptr);
|
|
||||||
static void do_close(tty_t *tp, message *m_ptr);
|
|
||||||
static void do_read(tty_t *tp, message *m_ptr);
|
|
||||||
static void do_write(tty_t *tp, message *m_ptr);
|
|
||||||
static void do_select(tty_t *tp, message *m_ptr);
|
|
||||||
static void in_transfer(tty_t *tp);
|
static void in_transfer(tty_t *tp);
|
||||||
static int tty_echo(tty_t *tp, int ch);
|
static int tty_echo(tty_t *tp, int ch);
|
||||||
static void rawecho(tty_t *tp, int ch);
|
static void rawecho(tty_t *tp, int ch);
|
||||||
|
@ -118,12 +107,32 @@ static void setattr(tty_t *tp);
|
||||||
static void tty_icancel(tty_t *tp);
|
static void tty_icancel(tty_t *tp);
|
||||||
static void tty_init(void);
|
static void tty_init(void);
|
||||||
static void do_new_kmess(void);
|
static void do_new_kmess(void);
|
||||||
static tty_t * line2tty(int line);
|
|
||||||
static void set_console_line(char term[CONS_ARG]);
|
static void set_console_line(char term[CONS_ARG]);
|
||||||
static void set_kernel_color(char color[CONS_ARG]);
|
static void set_kernel_color(char color[CONS_ARG]);
|
||||||
static void set_color(tty_t *tp, int color);
|
static void set_color(tty_t *tp, int color);
|
||||||
static void reset_color(tty_t *tp);
|
static void reset_color(tty_t *tp);
|
||||||
|
|
||||||
|
static int do_open(devminor_t minor, int access, endpoint_t user_endpt);
|
||||||
|
static int do_close(devminor_t minor);
|
||||||
|
static ssize_t do_read(devminor_t minor, u64_t position, endpoint_t endpt,
|
||||||
|
cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
|
||||||
|
static ssize_t do_write(devminor_t minor, u64_t position, endpoint_t endpt,
|
||||||
|
cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
|
||||||
|
static int do_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt,
|
||||||
|
cp_grant_id_t grant, int flags, endpoint_t user_endpt, cdev_id_t id);
|
||||||
|
static int do_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id);
|
||||||
|
static int do_select(devminor_t minor, unsigned int ops, endpoint_t endpt);
|
||||||
|
|
||||||
|
static struct chardriver tty_tab = {
|
||||||
|
.cdr_open = do_open,
|
||||||
|
.cdr_close = do_close,
|
||||||
|
.cdr_read = do_read,
|
||||||
|
.cdr_write = do_write,
|
||||||
|
.cdr_ioctl = do_ioctl,
|
||||||
|
.cdr_cancel = do_cancel,
|
||||||
|
.cdr_select = do_select
|
||||||
|
};
|
||||||
|
|
||||||
/* Default attributes. */
|
/* Default attributes. */
|
||||||
static struct termios termios_defaults = {
|
static struct termios termios_defaults = {
|
||||||
TINPUT_DEF, TOUTPUT_DEF, TCTRL_DEF, TLOCAL_DEF,
|
TINPUT_DEF, TOUTPUT_DEF, TCTRL_DEF, TLOCAL_DEF,
|
||||||
|
@ -160,7 +169,7 @@ int main(void)
|
||||||
message tty_mess; /* buffer for all incoming messages */
|
message tty_mess; /* buffer for all incoming messages */
|
||||||
int ipc_status;
|
int ipc_status;
|
||||||
unsigned line;
|
unsigned line;
|
||||||
int r, code;
|
int r;
|
||||||
register tty_t *tp;
|
register tty_t *tp;
|
||||||
|
|
||||||
/* SEF local startup. */
|
/* SEF local startup. */
|
||||||
|
@ -217,7 +226,6 @@ int main(void)
|
||||||
|
|
||||||
switch (tty_mess.m_type) {
|
switch (tty_mess.m_type) {
|
||||||
case TTY_FKEY_CONTROL: /* (un)register a fkey observer */
|
case TTY_FKEY_CONTROL: /* (un)register a fkey observer */
|
||||||
case OLD_FKEY_CONTROL: /* old number */
|
|
||||||
do_fkey_ctl(&tty_mess);
|
do_fkey_ctl(&tty_mess);
|
||||||
continue;
|
continue;
|
||||||
case INPUT_EVENT:
|
case INPUT_EVENT:
|
||||||
|
@ -227,76 +235,34 @@ int main(void)
|
||||||
; /* do nothing; end switch */
|
; /* do nothing; end switch */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!IS_DEV_RQ(tty_mess.m_type)) {
|
||||||
|
chardriver_process(&tty_tab, &tty_mess, ipc_status);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* Only device requests should get to this point.
|
/* Only device requests should get to this point.
|
||||||
* All requests have a minor device number.
|
* All requests have a minor device number.
|
||||||
*/
|
*/
|
||||||
line = tty_mess.DEVICE;
|
line = tty_mess.DEVICE;
|
||||||
if (line == CONS_MINOR || line == LOG_MINOR) {
|
if (line == KBD_MINOR || line == KBDAUX_MINOR) {
|
||||||
/* /dev/log output goes to /dev/console */
|
do_kbd(&tty_mess, ipc_status);
|
||||||
if (consoleline != CONS_MINOR) {
|
|
||||||
/* Console output must redirected */
|
|
||||||
line = consoleline;
|
|
||||||
tty_mess.DEVICE = line;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (line == KBD_MINOR) {
|
|
||||||
do_kbd(&tty_mess);
|
|
||||||
continue;
|
|
||||||
} else if (line == KBDAUX_MINOR) {
|
|
||||||
do_kbdaux(&tty_mess);
|
|
||||||
continue;
|
continue;
|
||||||
} else if (line == VIDEO_MINOR) {
|
} else if (line == VIDEO_MINOR) {
|
||||||
do_video(&tty_mess);
|
do_video(&tty_mess, ipc_status);
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else if (line - PTYPX_MINOR < NR_PTYS &&
|
||||||
tp = line2tty(line);
|
tty_mess.m_type != DEV_IOCTL_S) {
|
||||||
|
|
||||||
/* Terminals and pseudo terminals belong together. We can only
|
/* Terminals and pseudo terminals belong together. We can only
|
||||||
* make a distinction between the two based on position in the
|
* make a distinction between the two based on position in the
|
||||||
* tty_table and not on minor number (i.e., use ispty macro).
|
* tty_table and not on minor number (i.e., use ispty macro).
|
||||||
* Hence this special case.
|
* Hence this special case.
|
||||||
*/
|
*/
|
||||||
if (line - PTYPX_MINOR < NR_PTYS &&
|
do_pty(&tty_mess, ipc_status);
|
||||||
tty_mess.m_type != DEV_IOCTL_S){
|
|
||||||
do_pty(tp, &tty_mess);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If the device doesn't exist or is not configured return ENXIO. */
|
|
||||||
if (tp == NULL || ! tty_active(tp)) {
|
|
||||||
if (tty_mess.m_source == LOG_PROC_NR)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Can all of these occur? Probably not. We're by far most
|
|
||||||
* likely to see DEV_OPEN, but better safe than sorry..
|
|
||||||
*/
|
|
||||||
switch (tty_mess.m_type) {
|
|
||||||
case DEV_OPEN: code = DEV_OPEN_REPL; break;
|
|
||||||
case DEV_CLOSE: code = DEV_CLOSE_REPL; break;
|
|
||||||
default: code = DEV_REVIVE; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
tty_reply(code, tty_mess.m_source, tty_mess.USER_ENDPT,
|
|
||||||
(cp_grant_id_t) tty_mess.IO_GRANT, ENXIO);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Execute the requested device driver function. */
|
/* Execute the requested device driver function. */
|
||||||
switch (tty_mess.m_type) {
|
chardriver_process(&tty_tab, &tty_mess, ipc_status);
|
||||||
case DEV_READ_S: do_read(tp, &tty_mess); break;
|
|
||||||
case DEV_WRITE_S: do_write(tp, &tty_mess); break;
|
|
||||||
case DEV_IOCTL_S: do_ioctl(tp, &tty_mess); 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;
|
|
||||||
case CANCEL: do_cancel(tp, &tty_mess); break;
|
|
||||||
default:
|
|
||||||
printf("Warning, TTY got unexpected request %d from %d\n",
|
|
||||||
tty_mess.m_type, tty_mess.m_source);
|
|
||||||
tty_reply(DEV_REVIVE, tty_mess.m_source, tty_mess.USER_ENDPT,
|
|
||||||
(cp_grant_id_t) tty_mess.IO_GRANT, EINVAL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -305,47 +271,41 @@ int main(void)
|
||||||
static void
|
static void
|
||||||
set_color(tty_t *tp, int color)
|
set_color(tty_t *tp, int color)
|
||||||
{
|
{
|
||||||
message msg;
|
|
||||||
char buf[8];
|
char buf[8];
|
||||||
|
|
||||||
buf[0] = '\033';
|
buf[0] = '\033';
|
||||||
snprintf(&buf[1], sizeof(buf) - 1, "[1;%dm", color);
|
snprintf(&buf[1], sizeof(buf) - 1, "[1;%dm", color);
|
||||||
memset(&msg, 0, sizeof(msg));
|
do_write(tp->tty_minor, 0, KERNEL, (cp_grant_id_t) buf, sizeof(buf),
|
||||||
msg.m_source = KERNEL;
|
FLG_OP_NONBLOCK, 0);
|
||||||
msg.IO_GRANT = buf;
|
|
||||||
msg.COUNT = sizeof(buf);
|
|
||||||
do_write(tp, &msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
reset_color(tty_t *tp)
|
reset_color(tty_t *tp)
|
||||||
{
|
{
|
||||||
message msg;
|
|
||||||
char buf[8];
|
char buf[8];
|
||||||
|
|
||||||
#define SGR_COLOR_RESET 39
|
#define SGR_COLOR_RESET 39
|
||||||
buf[0] = '\033';
|
buf[0] = '\033';
|
||||||
snprintf(&buf[1], sizeof(buf) - 1, "[0;%dm", SGR_COLOR_RESET);
|
snprintf(&buf[1], sizeof(buf) - 1, "[0;%dm", SGR_COLOR_RESET);
|
||||||
memset(&msg, 0, sizeof(msg));
|
do_write(tp->tty_minor, 0, KERNEL, (cp_grant_id_t) buf, sizeof(buf),
|
||||||
msg.m_source = KERNEL;
|
FLG_OP_NONBLOCK, 0);
|
||||||
msg.IO_GRANT = buf;
|
|
||||||
msg.COUNT = sizeof(buf);
|
|
||||||
do_write(tp, &msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static tty_t *
|
tty_t *
|
||||||
line2tty(int line)
|
line2tty(devminor_t line)
|
||||||
{
|
{
|
||||||
/* Convert a terminal line to tty_table pointer */
|
/* Convert a terminal line to tty_table pointer */
|
||||||
|
|
||||||
tty_t* tp;
|
tty_t* tp;
|
||||||
|
|
||||||
|
/* /dev/log goes to /dev/console, and both may be redirected. */
|
||||||
|
if (line == CONS_MINOR || line == LOG_MINOR)
|
||||||
|
line = consoleline;
|
||||||
|
|
||||||
if (line == KBD_MINOR || line == KBDAUX_MINOR || line == VIDEO_MINOR) {
|
if (line == KBD_MINOR || line == KBDAUX_MINOR || line == VIDEO_MINOR) {
|
||||||
return(NULL);
|
return(NULL);
|
||||||
} else if ((line - CONS_MINOR) < NR_CONS) {
|
} else if ((line - CONS_MINOR) < NR_CONS) {
|
||||||
tp = tty_addr(line - CONS_MINOR);
|
tp = tty_addr(line - CONS_MINOR);
|
||||||
} else if (line == LOG_MINOR) {
|
|
||||||
tp = tty_addr(consoleline);
|
|
||||||
} else if ((line - RS232_MINOR) < NR_RS_LINES) {
|
} else if ((line - RS232_MINOR) < NR_RS_LINES) {
|
||||||
tp = tty_addr(line - RS232_MINOR + NR_CONS);
|
tp = tty_addr(line - RS232_MINOR + NR_CONS);
|
||||||
} else if ((line - TTYPX_MINOR) < NR_PTYS) {
|
} else if ((line - TTYPX_MINOR) < NR_PTYS) {
|
||||||
|
@ -356,6 +316,9 @@ line2tty(int line)
|
||||||
tp = NULL;
|
tp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tp != NULL && !tty_active(tp))
|
||||||
|
tp = NULL;
|
||||||
|
|
||||||
return(tp);
|
return(tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -430,7 +393,7 @@ set_console_line(char term[CONS_ARG])
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Serial lines */
|
/* Serial lines */
|
||||||
assert(NR_RS_LINES <= 9);/* bellow assumes this is the case */
|
assert(NR_RS_LINES <= 9);/* below assumes this is the case */
|
||||||
for (i = 0; i < NR_RS_LINES; i++) {
|
for (i = 0; i < NR_RS_LINES; i++) {
|
||||||
char sercons[6];
|
char sercons[6];
|
||||||
strlcpy(sercons, "tty00", sizeof(sercons));
|
strlcpy(sercons, "tty00", sizeof(sercons));
|
||||||
|
@ -465,7 +428,6 @@ do_new_kmess(void)
|
||||||
static int prev_next = 0;
|
static int prev_next = 0;
|
||||||
int next, bytes, copy, restore = 0;
|
int next, bytes, copy, restore = 0;
|
||||||
tty_t *tp, rtp;
|
tty_t *tp, rtp;
|
||||||
message print_kmsg;
|
|
||||||
|
|
||||||
assert(_minix_kerninfo);
|
assert(_minix_kerninfo);
|
||||||
kmess_ptr = _minix_kerninfo->kmessages;
|
kmess_ptr = _minix_kerninfo->kmessages;
|
||||||
|
@ -491,7 +453,7 @@ do_new_kmess(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
tp = line2tty(consoleline);
|
tp = line2tty(consoleline);
|
||||||
if (tp == NULL || !tty_active(tp))
|
if (tp == NULL)
|
||||||
panic("Don't know where to send kernel messages");
|
panic("Don't know where to send kernel messages");
|
||||||
if (tp->tty_outleft > 0) {
|
if (tp->tty_outleft > 0) {
|
||||||
/* Terminal is already printing */
|
/* Terminal is already printing */
|
||||||
|
@ -502,11 +464,9 @@ do_new_kmess(void)
|
||||||
|
|
||||||
if (kernel_msg_color != 0)
|
if (kernel_msg_color != 0)
|
||||||
set_color(tp, kernel_msg_color);
|
set_color(tp, kernel_msg_color);
|
||||||
memset(&print_kmsg, 0, sizeof(print_kmsg));
|
do_write(tp->tty_minor, 0, KERNEL,
|
||||||
print_kmsg.m_source = KERNEL;
|
(cp_grant_id_t) kernel_buf_copy, bytes,
|
||||||
print_kmsg.IO_GRANT = kernel_buf_copy;
|
FLG_OP_NONBLOCK, 0);
|
||||||
print_kmsg.COUNT = bytes;
|
|
||||||
do_write(tp, &print_kmsg);
|
|
||||||
if (kernel_msg_color != 0)
|
if (kernel_msg_color != 0)
|
||||||
reset_color(tp);
|
reset_color(tp);
|
||||||
if (restore) {
|
if (restore) {
|
||||||
|
@ -541,141 +501,138 @@ static void sef_cb_signal_handler(int signo)
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* do_read *
|
* do_read *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
static void do_read(tp, m_ptr)
|
static ssize_t do_read(devminor_t minor, u64_t UNUSED(position),
|
||||||
register tty_t *tp; /* pointer to tty struct */
|
endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags,
|
||||||
register message *m_ptr; /* pointer to message sent to the task */
|
cdev_id_t id)
|
||||||
{
|
{
|
||||||
/* A process wants to read from a terminal. */
|
/* A process wants to read from a terminal. */
|
||||||
|
tty_t *tp;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
if ((tp = line2tty(minor)) == NULL)
|
||||||
|
return ENXIO;
|
||||||
|
|
||||||
/* Check if there is already a process hanging in a read, check if the
|
/* Check if there is already a process hanging in a read, check if the
|
||||||
* parameters are correct, do I/O.
|
* parameters are correct, do I/O.
|
||||||
*/
|
*/
|
||||||
if (tp->tty_inleft > 0) {
|
if (tp->tty_incaller != NONE || tp->tty_inleft > 0)
|
||||||
r = EIO;
|
return EIO;
|
||||||
} else
|
if (size <= 0)
|
||||||
if (m_ptr->COUNT <= 0) {
|
return EINVAL;
|
||||||
r = EINVAL;
|
|
||||||
} else if (tp->tty_ingrant != GRANT_INVALID) {
|
|
||||||
/* This is actually a fundamental problem with TTY; it can handle
|
|
||||||
* only one reader per minor device. If we don't return an error,
|
|
||||||
* we'll overwrite the previous reader and that process will get
|
|
||||||
* stuck forever. */
|
|
||||||
r = ENOBUFS;
|
|
||||||
} else {
|
|
||||||
/* Copy information from the message to the tty struct. */
|
|
||||||
tp->tty_incaller = m_ptr->m_source;
|
|
||||||
tp->tty_inproc = m_ptr->USER_ENDPT;
|
|
||||||
tp->tty_ingrant = (cp_grant_id_t) m_ptr->IO_GRANT;
|
|
||||||
tp->tty_inoffset = 0;
|
|
||||||
tp->tty_inleft = m_ptr->COUNT;
|
|
||||||
|
|
||||||
if (!(tp->tty_termios.c_lflag & ICANON)
|
/* Copy information from the message to the tty struct. */
|
||||||
&& tp->tty_termios.c_cc[VTIME] > 0) {
|
tp->tty_incaller = endpt;
|
||||||
if (tp->tty_termios.c_cc[VMIN] == 0) {
|
tp->tty_inid = id;
|
||||||
/* MIN & TIME specify a read timer that finishes the
|
tp->tty_ingrant = grant;
|
||||||
* read in TIME/10 seconds if no bytes are available.
|
assert(tp->tty_incum == 0);
|
||||||
*/
|
tp->tty_inleft = size;
|
||||||
settimer(tp, TRUE);
|
|
||||||
tp->tty_min = 1;
|
if (!(tp->tty_termios.c_lflag & ICANON) && tp->tty_termios.c_cc[VTIME] > 0) {
|
||||||
} else {
|
if (tp->tty_termios.c_cc[VMIN] == 0) {
|
||||||
/* MIN & TIME specify an inter-byte timer that may
|
/* MIN & TIME specify a read timer that finishes the
|
||||||
* have to be cancelled if there are no bytes yet.
|
* read in TIME/10 seconds if no bytes are available.
|
||||||
*/
|
*/
|
||||||
if (tp->tty_eotct == 0) {
|
settimer(tp, TRUE);
|
||||||
settimer(tp, FALSE);
|
tp->tty_min = 1;
|
||||||
tp->tty_min = tp->tty_termios.c_cc[VMIN];
|
} else {
|
||||||
}
|
/* MIN & TIME specify an inter-byte timer that may
|
||||||
|
* have to be cancelled if there are no bytes yet.
|
||||||
|
*/
|
||||||
|
if (tp->tty_eotct == 0) {
|
||||||
|
settimer(tp, FALSE);
|
||||||
|
tp->tty_min = tp->tty_termios.c_cc[VMIN];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Anything waiting in the input buffer? Clear it out... */
|
|
||||||
in_transfer(tp);
|
|
||||||
/* ...then go back for more. */
|
|
||||||
handle_events(tp);
|
|
||||||
if (tp->tty_inleft == 0) {
|
|
||||||
return; /* already done */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* There were no bytes in the input queue available. */
|
|
||||||
if (m_ptr->FLAGS & FLG_OP_NONBLOCK) {
|
|
||||||
tty_icancel(tp);
|
|
||||||
r = tp->tty_incum > 0 ? tp->tty_incum : EAGAIN;
|
|
||||||
tp->tty_inleft = tp->tty_incum = 0;
|
|
||||||
tp->tty_ingrant = GRANT_INVALID;
|
|
||||||
} else {
|
|
||||||
return; /* suspend the caller */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
tty_reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT,
|
|
||||||
(cp_grant_id_t) m_ptr->IO_GRANT, r);
|
/* Anything waiting in the input buffer? Clear it out... */
|
||||||
|
in_transfer(tp);
|
||||||
|
/* ...then go back for more. */
|
||||||
|
handle_events(tp);
|
||||||
|
if (tp->tty_inleft == 0)
|
||||||
|
return EDONTREPLY; /* already done */
|
||||||
|
|
||||||
|
/* There were no bytes in the input queue available. */
|
||||||
|
if (flags & FLG_OP_NONBLOCK) {
|
||||||
|
tty_icancel(tp);
|
||||||
|
r = tp->tty_incum > 0 ? tp->tty_incum : EAGAIN;
|
||||||
|
tp->tty_inleft = tp->tty_incum = 0;
|
||||||
|
tp->tty_incaller = NONE;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
if (tp->tty_select_ops)
|
if (tp->tty_select_ops)
|
||||||
select_retry(tp);
|
select_retry(tp);
|
||||||
|
|
||||||
|
return EDONTREPLY; /* suspend the caller */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* do_write *
|
* do_write *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
static void do_write(tp, m_ptr)
|
static ssize_t do_write(devminor_t minor, u64_t UNUSED(position),
|
||||||
register tty_t *tp;
|
endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags,
|
||||||
register message *m_ptr; /* pointer to message sent to the task */
|
cdev_id_t id)
|
||||||
{
|
{
|
||||||
/* A process wants to write on a terminal. */
|
/* A process wants to write on a terminal. */
|
||||||
|
tty_t *tp;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
if ((tp = line2tty(minor)) == NULL)
|
||||||
|
return ENXIO;
|
||||||
|
|
||||||
/* Check if there is already a process hanging in a write, check if the
|
/* Check if there is already a process hanging in a write, check if the
|
||||||
* parameters are correct, do I/O.
|
* parameters are correct, do I/O.
|
||||||
*/
|
*/
|
||||||
if (tp->tty_outleft > 0) {
|
if (tp->tty_outcaller != NONE || tp->tty_outleft > 0)
|
||||||
r = EIO;
|
return EIO;
|
||||||
} else
|
if (size <= 0)
|
||||||
if (m_ptr->COUNT <= 0) {
|
return EINVAL;
|
||||||
r = EINVAL;
|
|
||||||
} else {
|
|
||||||
/* Copy message parameters to the tty structure. */
|
|
||||||
tp->tty_outcaller = m_ptr->m_source;
|
|
||||||
tp->tty_outproc = m_ptr->USER_ENDPT;
|
|
||||||
tp->tty_outgrant = (cp_grant_id_t) m_ptr->IO_GRANT;
|
|
||||||
tp->tty_outoffset = 0;
|
|
||||||
tp->tty_outleft = m_ptr->COUNT;
|
|
||||||
|
|
||||||
/* Try to write. */
|
/* Copy message parameters to the tty structure. */
|
||||||
handle_events(tp);
|
tp->tty_outcaller = endpt;
|
||||||
if (tp->tty_outleft == 0)
|
tp->tty_outid = id;
|
||||||
return; /* already done */
|
tp->tty_outgrant = grant;
|
||||||
|
assert(tp->tty_outcum == 0);
|
||||||
|
tp->tty_outleft = size;
|
||||||
|
|
||||||
/* None or not all the bytes could be written. */
|
/* Try to write. */
|
||||||
if (m_ptr->FLAGS & FLG_OP_NONBLOCK) {
|
handle_events(tp);
|
||||||
r = tp->tty_outcum > 0 ? tp->tty_outcum : EAGAIN;
|
if (tp->tty_outleft == 0)
|
||||||
tp->tty_outleft = tp->tty_outcum = 0;
|
return EDONTREPLY; /* already done */
|
||||||
tp->tty_outgrant = GRANT_INVALID;
|
|
||||||
} else {
|
/* None or not all the bytes could be written. */
|
||||||
return; /* suspend the caller */
|
if (flags & FLG_OP_NONBLOCK) {
|
||||||
}
|
r = tp->tty_outcum > 0 ? tp->tty_outcum : EAGAIN;
|
||||||
|
tp->tty_outleft = tp->tty_outcum = 0;
|
||||||
|
tp->tty_outcaller = NONE;
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
tty_reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT,
|
|
||||||
(cp_grant_id_t) m_ptr->IO_GRANT, r);
|
if (tp->tty_select_ops)
|
||||||
|
select_retry(tp);
|
||||||
|
|
||||||
|
return EDONTREPLY; /* suspend the caller */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* do_ioctl *
|
* do_ioctl *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
static void do_ioctl(tp, m_ptr)
|
static int do_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt,
|
||||||
register tty_t *tp;
|
cp_grant_id_t grant, int flags, endpoint_t user_endpt, cdev_id_t id)
|
||||||
message *m_ptr; /* pointer to message sent to task */
|
|
||||||
{
|
{
|
||||||
/* Perform an IOCTL on this terminal. Posix termios calls are handled
|
/* Perform an IOCTL on this terminal. POSIX termios calls are handled
|
||||||
* by the IOCTL system call
|
* by the IOCTL system call.
|
||||||
*/
|
*/
|
||||||
|
tty_t *tp;
|
||||||
int r;
|
int i, r;
|
||||||
union {
|
|
||||||
int i;
|
|
||||||
} param;
|
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
||||||
|
if ((tp = line2tty(minor)) == NULL)
|
||||||
|
return ENXIO;
|
||||||
|
|
||||||
/* Size of the ioctl parameter. */
|
/* Size of the ioctl parameter. */
|
||||||
switch (m_ptr->REQUEST) {
|
switch (request) {
|
||||||
case TCGETS: /* Posix tcgetattr function */
|
case TCGETS: /* Posix tcgetattr function */
|
||||||
case TCSETS: /* Posix tcsetattr function, TCSANOW option */
|
case TCSETS: /* Posix tcsetattr function, TCSANOW option */
|
||||||
case TCSETSW: /* Posix tcsetattr function, TCSADRAIN option */
|
case TCSETSW: /* Posix tcsetattr function, TCSADRAIN option */
|
||||||
|
@ -709,60 +666,55 @@ message *m_ptr; /* pointer to message sent to task */
|
||||||
}
|
}
|
||||||
|
|
||||||
r = OK;
|
r = OK;
|
||||||
switch (m_ptr->REQUEST) {
|
switch (request) {
|
||||||
case TCGETS:
|
case TCGETS:
|
||||||
/* Get the termios attributes. */
|
/* Get the termios attributes. */
|
||||||
r = sys_safecopyto(m_ptr->m_source, (cp_grant_id_t) m_ptr->IO_GRANT, 0,
|
r = sys_safecopyto(endpt, grant, 0, (vir_bytes) &tp->tty_termios,
|
||||||
(vir_bytes) &tp->tty_termios, (vir_bytes) size);
|
size);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TCSETSW:
|
case TCSETSW:
|
||||||
case TCSETSF:
|
case TCSETSF:
|
||||||
case TCDRAIN:
|
case TCDRAIN:
|
||||||
if (tp->tty_outleft > 0) {
|
if (tp->tty_outleft > 0) {
|
||||||
if (m_ptr->FLAGS & FLG_OP_NONBLOCK) {
|
if (flags & FLG_OP_NONBLOCK)
|
||||||
r = EAGAIN;
|
return EAGAIN;
|
||||||
} else {
|
/* Wait for all ongoing output processing to finish. */
|
||||||
/* Wait for all ongoing output processing to finish. */
|
tp->tty_iocaller = endpt;
|
||||||
tp->tty_iocaller = m_ptr->m_source;
|
tp->tty_ioid = id;
|
||||||
tp->tty_ioproc = m_ptr->USER_ENDPT;
|
tp->tty_ioreq = request;
|
||||||
tp->tty_ioreq = m_ptr->REQUEST;
|
tp->tty_iogrant = grant;
|
||||||
tp->tty_iogrant = (cp_grant_id_t) m_ptr->IO_GRANT;
|
return EDONTREPLY; /* suspend the caller */
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (m_ptr->REQUEST == TCDRAIN) break;
|
if (request == TCDRAIN) break;
|
||||||
if (m_ptr->REQUEST == TCSETSF) tty_icancel(tp);
|
if (request == TCSETSF) tty_icancel(tp);
|
||||||
/*FALL THROUGH*/
|
/*FALL THROUGH*/
|
||||||
case TCSETS:
|
case TCSETS:
|
||||||
/* Set the termios attributes. */
|
/* Set the termios attributes. */
|
||||||
r = sys_safecopyfrom(m_ptr->m_source, (cp_grant_id_t) m_ptr->IO_GRANT,
|
r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &tp->tty_termios,
|
||||||
0, (vir_bytes) &tp->tty_termios, (vir_bytes) size);
|
size);
|
||||||
if (r != OK) break;
|
if (r != OK) break;
|
||||||
setattr(tp);
|
setattr(tp);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TCFLSH:
|
case TCFLSH:
|
||||||
r = sys_safecopyfrom(m_ptr->m_source, (cp_grant_id_t) m_ptr->IO_GRANT,
|
r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &i, size);
|
||||||
0, (vir_bytes) ¶m.i, (vir_bytes) size);
|
|
||||||
if (r != OK) break;
|
if (r != OK) break;
|
||||||
switch (param.i) {
|
switch (i) {
|
||||||
case TCIFLUSH: tty_icancel(tp); break;
|
case TCIFLUSH: tty_icancel(tp); break;
|
||||||
case TCOFLUSH: (*tp->tty_ocancel)(tp, 0); break;
|
case TCOFLUSH: (*tp->tty_ocancel)(tp, 0); break;
|
||||||
case TCIOFLUSH: tty_icancel(tp); (*tp->tty_ocancel)(tp, 0); break;
|
case TCIOFLUSH: tty_icancel(tp); (*tp->tty_ocancel)(tp, 0); break;
|
||||||
default: r = EINVAL;
|
default: r = EINVAL;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TCFLOW:
|
case TCFLOW:
|
||||||
r = sys_safecopyfrom(m_ptr->m_source, (cp_grant_id_t) m_ptr->IO_GRANT,
|
r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &i, size);
|
||||||
0, (vir_bytes) ¶m.i, (vir_bytes) size);
|
|
||||||
if (r != OK) break;
|
if (r != OK) break;
|
||||||
switch (param.i) {
|
switch (i) {
|
||||||
case TCOOFF:
|
case TCOOFF:
|
||||||
case TCOON:
|
case TCOON:
|
||||||
tp->tty_inhibited = (param.i == TCOOFF);
|
tp->tty_inhibited = (i == TCOOFF);
|
||||||
tp->tty_events = 1;
|
tp->tty_events = 1;
|
||||||
break;
|
break;
|
||||||
case TCIOFF:
|
case TCIOFF:
|
||||||
|
@ -781,27 +733,24 @@ message *m_ptr; /* pointer to message sent to task */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TIOCGWINSZ:
|
case TIOCGWINSZ:
|
||||||
r = sys_safecopyto(m_ptr->m_source, (cp_grant_id_t) m_ptr->IO_GRANT, 0,
|
r = sys_safecopyto(endpt, grant, 0, (vir_bytes) &tp->tty_winsize,
|
||||||
(vir_bytes) &tp->tty_winsize, (vir_bytes) size);
|
size);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TIOCSWINSZ:
|
case TIOCSWINSZ:
|
||||||
r = sys_safecopyfrom(m_ptr->m_source, (cp_grant_id_t) m_ptr->IO_GRANT,
|
r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &tp->tty_winsize,
|
||||||
0, (vir_bytes) &tp->tty_winsize, (vir_bytes) size);
|
size);
|
||||||
sigchar(tp, SIGWINCH, 0);
|
sigchar(tp, SIGWINCH, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KIOCSMAP:
|
case KIOCSMAP:
|
||||||
/* Load a new keymap (only /dev/console). */
|
/* Load a new keymap (only /dev/console). */
|
||||||
if (isconsole(tp)) r = kbd_loadmap(m_ptr);
|
if (isconsole(tp)) r = kbd_loadmap(endpt, grant);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TIOCSFON_OLD:
|
|
||||||
printf("TTY: old TIOCSFON ignored.\n");
|
|
||||||
break;
|
|
||||||
case TIOCSFON:
|
case TIOCSFON:
|
||||||
/* Load a font into an EGA or VGA card (hs@hck.hr) */
|
/* Load a font into an EGA or VGA card (hs@hck.hr) */
|
||||||
if (isconsole(tp)) r = con_loadfont(m_ptr);
|
if (isconsole(tp)) r = con_loadfont(endpt, grant);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* These Posix functions are allowed to fail if _POSIX_JOB_CONTROL is
|
/* These Posix functions are allowed to fail if _POSIX_JOB_CONTROL is
|
||||||
|
@ -813,30 +762,30 @@ message *m_ptr; /* pointer to message sent to task */
|
||||||
r = ENOTTY;
|
r = ENOTTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send the reply. */
|
return r;
|
||||||
tty_reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT,
|
|
||||||
(cp_grant_id_t) m_ptr->IO_GRANT, r);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* do_open *
|
* do_open *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
static void do_open(tp, m_ptr)
|
static int do_open(devminor_t minor, int access, endpoint_t user_endpt)
|
||||||
register tty_t *tp;
|
|
||||||
message *m_ptr; /* pointer to message sent to task */
|
|
||||||
{
|
{
|
||||||
/* A tty line has been opened. Make it the callers controlling tty if
|
/* A tty line has been opened. Make it the callers controlling tty if
|
||||||
* O_NOCTTY is *not* set and it is not the log device. 1 is returned if
|
* O_NOCTTY is *not* set and it is not the log device. 1 is returned if
|
||||||
* the tty is made the controlling tty, otherwise OK or an error code.
|
* the tty is made the controlling tty, otherwise OK or an error code.
|
||||||
*/
|
*/
|
||||||
|
tty_t *tp;
|
||||||
int r = OK;
|
int r = OK;
|
||||||
|
|
||||||
if (m_ptr->DEVICE == LOG_MINOR) {
|
if ((tp = line2tty(minor)) == NULL)
|
||||||
|
return ENXIO;
|
||||||
|
|
||||||
|
if (minor == LOG_MINOR) {
|
||||||
/* The log device is a write-only diagnostics device. */
|
/* The log device is a write-only diagnostics device. */
|
||||||
if (m_ptr->COUNT & R_BIT) r = EACCES;
|
if (access & R_BIT) return EACCES;
|
||||||
} else {
|
} else {
|
||||||
if (!(m_ptr->COUNT & O_NOCTTY)) {
|
if (!(access & O_NOCTTY)) {
|
||||||
tp->tty_pgrp = m_ptr->USER_ENDPT;
|
tp->tty_pgrp = user_endpt;
|
||||||
r = 1;
|
r = 1;
|
||||||
}
|
}
|
||||||
tp->tty_openct++;
|
tp->tty_openct++;
|
||||||
|
@ -845,20 +794,22 @@ message *m_ptr; /* pointer to message sent to task */
|
||||||
(*tp->tty_open)(tp, 0);
|
(*tp->tty_open)(tp, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tty_reply(DEV_OPEN_REPL, m_ptr->m_source, m_ptr->USER_ENDPT,
|
|
||||||
(cp_grant_id_t) m_ptr->IO_GRANT, r);
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* do_close *
|
* do_close *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
static void do_close(tp, m_ptr)
|
static int do_close(devminor_t minor)
|
||||||
register tty_t *tp;
|
|
||||||
message *m_ptr; /* pointer to message sent to task */
|
|
||||||
{
|
{
|
||||||
/* A tty line has been closed. Clean up the line if it is the last close. */
|
/* A tty line has been closed. Clean up the line if it is the last close. */
|
||||||
|
tty_t *tp;
|
||||||
|
|
||||||
if (m_ptr->DEVICE != LOG_MINOR && --tp->tty_openct == 0) {
|
if ((tp = line2tty(minor)) == NULL)
|
||||||
|
return ENXIO;
|
||||||
|
|
||||||
|
if (minor != LOG_MINOR && --tp->tty_openct == 0) {
|
||||||
tp->tty_pgrp = 0;
|
tp->tty_pgrp = 0;
|
||||||
tty_icancel(tp);
|
tty_icancel(tp);
|
||||||
(*tp->tty_ocancel)(tp, 0);
|
(*tp->tty_ocancel)(tp, 0);
|
||||||
|
@ -867,53 +818,49 @@ message *m_ptr; /* pointer to message sent to task */
|
||||||
tp->tty_winsize = winsize_defaults;
|
tp->tty_winsize = winsize_defaults;
|
||||||
setattr(tp);
|
setattr(tp);
|
||||||
}
|
}
|
||||||
tty_reply(DEV_CLOSE_REPL, m_ptr->m_source, m_ptr->USER_ENDPT,
|
|
||||||
(cp_grant_id_t) m_ptr->IO_GRANT, OK);
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* do_cancel *
|
* do_cancel *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
static void do_cancel(tp, m_ptr)
|
static int do_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id)
|
||||||
register tty_t *tp;
|
|
||||||
message *m_ptr; /* pointer to message sent to task */
|
|
||||||
{
|
{
|
||||||
/* A signal has been sent to a process that is hanging trying to read or write.
|
/* A signal has been sent to a process that is hanging trying to read or write.
|
||||||
* The pending read or write must be finished off immediately.
|
* The pending read or write must be finished off immediately.
|
||||||
*/
|
*/
|
||||||
endpoint_t proc_nr;
|
tty_t *tp;
|
||||||
cp_grant_id_t grant;
|
int r;
|
||||||
int mode;
|
|
||||||
int r = EDONTREPLY;
|
if ((tp = line2tty(minor)) == NULL)
|
||||||
|
return ENXIO;
|
||||||
|
|
||||||
/* Check the parameters carefully, to avoid cancelling twice. */
|
/* Check the parameters carefully, to avoid cancelling twice. */
|
||||||
proc_nr = m_ptr->USER_ENDPT;
|
r = EDONTREPLY;
|
||||||
grant = (cp_grant_id_t) m_ptr->IO_GRANT;
|
if (tp->tty_inleft != 0 && endpt == tp->tty_incaller && id == tp->tty_inid) {
|
||||||
mode = m_ptr->COUNT;
|
|
||||||
if ((mode & R_BIT) && tp->tty_inleft != 0 && proc_nr == tp->tty_inproc &&
|
|
||||||
tp->tty_ingrant == grant) {
|
|
||||||
/* Process was reading when killed. Clean up input. */
|
/* Process was reading when killed. Clean up input. */
|
||||||
tty_icancel(tp);
|
tty_icancel(tp);
|
||||||
r = tp->tty_incum > 0 ? tp->tty_incum : EAGAIN;
|
r = tp->tty_incum > 0 ? tp->tty_incum : EAGAIN;
|
||||||
tp->tty_inleft = tp->tty_incum = 0;
|
tp->tty_inleft = tp->tty_incum = 0;
|
||||||
tp->tty_ingrant = GRANT_INVALID;
|
tp->tty_incaller = NONE;
|
||||||
}
|
} else if (tp->tty_outleft != 0 && endpt == tp->tty_outcaller &&
|
||||||
if ((mode & W_BIT) && tp->tty_outleft != 0 && proc_nr == tp->tty_outproc &&
|
id == tp->tty_outid) {
|
||||||
tp->tty_outgrant == grant) {
|
|
||||||
/* Process was writing when killed. Clean up output. */
|
/* Process was writing when killed. Clean up output. */
|
||||||
r = tp->tty_outcum > 0 ? tp->tty_outcum : EAGAIN;
|
r = tp->tty_outcum > 0 ? tp->tty_outcum : EAGAIN;
|
||||||
tp->tty_outleft = tp->tty_outcum = 0;
|
tp->tty_outleft = tp->tty_outcum = 0;
|
||||||
tp->tty_outgrant = GRANT_INVALID;
|
tp->tty_outcaller = NONE;
|
||||||
}
|
} else if (tp->tty_ioreq != 0 && endpt == tp->tty_iocaller &&
|
||||||
if (tp->tty_ioreq != 0 && proc_nr == tp->tty_ioproc) {
|
id == tp->tty_ioid) {
|
||||||
/* Process was waiting for output to drain. */
|
/* Process was waiting for output to drain. */
|
||||||
tp->tty_ioreq = 0;
|
|
||||||
r = EINTR;
|
r = EINTR;
|
||||||
|
tp->tty_ioreq = 0;
|
||||||
|
tp->tty_iocaller = NONE;
|
||||||
}
|
}
|
||||||
tp->tty_events = 1;
|
|
||||||
/* Only reply if we found a matching request. */
|
|
||||||
if (r != EDONTREPLY)
|
if (r != EDONTREPLY)
|
||||||
tty_reply(DEV_REVIVE, m_ptr->m_source, proc_nr, grant, r);
|
tp->tty_events = 1;
|
||||||
|
/* Only reply if we found a matching request. */
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int select_try(struct tty *tp, int ops)
|
int select_try(struct tty *tp, int ops)
|
||||||
|
@ -955,14 +902,43 @@ int select_retry(struct tty *tp)
|
||||||
int ops;
|
int ops;
|
||||||
|
|
||||||
if (tp->tty_select_ops && (ops = select_try(tp, tp->tty_select_ops))) {
|
if (tp->tty_select_ops && (ops = select_try(tp, tp->tty_select_ops))) {
|
||||||
assert(tp->tty_select_minor == tp->tty_minor);
|
chardriver_reply_select(tp->tty_select_proc, tp->tty_minor,
|
||||||
select_reply(DEV_SEL_REPL2, tp->tty_select_proc, tp->tty_minor,
|
|
||||||
ops);
|
ops);
|
||||||
tp->tty_select_ops &= ~ops;
|
tp->tty_select_ops &= ~ops;
|
||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* do_select *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int do_select(devminor_t minor, unsigned int ops, endpoint_t endpt)
|
||||||
|
{
|
||||||
|
tty_t *tp;
|
||||||
|
int ready_ops, watch;
|
||||||
|
|
||||||
|
if ((tp = line2tty(minor)) == NULL)
|
||||||
|
return ENXIO;
|
||||||
|
|
||||||
|
/* Translated minor numbers are a problem when sending late replies. */
|
||||||
|
if (tp->tty_minor != minor)
|
||||||
|
return EBADF;
|
||||||
|
|
||||||
|
watch = (ops & SEL_NOTIFY);
|
||||||
|
ops &= (SEL_RD | SEL_WR | SEL_ERR);
|
||||||
|
|
||||||
|
ready_ops = select_try(tp, ops);
|
||||||
|
|
||||||
|
ops &= ~ready_ops;
|
||||||
|
if (ops && watch) {
|
||||||
|
tp->tty_select_ops |= ops;
|
||||||
|
tp->tty_select_proc = endpt;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(tp->tty_minor == minor);
|
||||||
|
return ready_ops;
|
||||||
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* handle_events *
|
* handle_events *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
@ -979,8 +955,8 @@ tty_t *tp; /* TTY to check for events. */
|
||||||
* to avoid swamping the TTY task. Messages may be overwritten when the
|
* to avoid swamping the TTY task. Messages may be overwritten when the
|
||||||
* lines are fast or when there are races between different lines, input
|
* lines are fast or when there are races between different lines, input
|
||||||
* and output, because MINIX only provides single buffering for interrupt
|
* and output, because MINIX only provides single buffering for interrupt
|
||||||
* messages (in proc.c). This is handled by explicitly checking each line
|
* messages. This is handled by explicitly checking each line for fresh input
|
||||||
* for fresh input and completed output on each interrupt.
|
* and completed output on each interrupt.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
@ -1001,10 +977,9 @@ tty_t *tp; /* TTY to check for events. */
|
||||||
|
|
||||||
/* Reply if enough bytes are available. */
|
/* Reply if enough bytes are available. */
|
||||||
if (tp->tty_incum >= tp->tty_min && tp->tty_inleft > 0) {
|
if (tp->tty_incum >= tp->tty_min && tp->tty_inleft > 0) {
|
||||||
tty_reply(DEV_REVIVE, tp->tty_incaller, tp->tty_inproc,
|
chardriver_reply_task(tp->tty_incaller, tp->tty_inid, tp->tty_incum);
|
||||||
tp->tty_ingrant, tp->tty_incum);
|
|
||||||
tp->tty_inleft = tp->tty_incum = 0;
|
tp->tty_inleft = tp->tty_incum = 0;
|
||||||
tp->tty_ingrant = GRANT_INVALID;
|
tp->tty_incaller = NONE;
|
||||||
}
|
}
|
||||||
if (tp->tty_select_ops)
|
if (tp->tty_select_ops)
|
||||||
{
|
{
|
||||||
|
@ -1045,10 +1020,8 @@ register tty_t *tp; /* pointer to terminal to read from */
|
||||||
if (++bp == bufend(buf)) {
|
if (++bp == bufend(buf)) {
|
||||||
/* Temp buffer full, copy to user space. */
|
/* Temp buffer full, copy to user space. */
|
||||||
sys_safecopyto(tp->tty_incaller,
|
sys_safecopyto(tp->tty_incaller,
|
||||||
tp->tty_ingrant, tp->tty_inoffset,
|
tp->tty_ingrant, tp->tty_incum,
|
||||||
(vir_bytes) buf,
|
(vir_bytes) buf, (vir_bytes) buflen(buf));
|
||||||
(vir_bytes) buflen(buf));
|
|
||||||
tp->tty_inoffset += buflen(buf);
|
|
||||||
tp->tty_incum += buflen(buf);
|
tp->tty_incum += buflen(buf);
|
||||||
bp = buf;
|
bp = buf;
|
||||||
}
|
}
|
||||||
|
@ -1068,19 +1041,16 @@ register tty_t *tp; /* pointer to terminal to read from */
|
||||||
if (bp > buf) {
|
if (bp > buf) {
|
||||||
/* Leftover characters in the buffer. */
|
/* Leftover characters in the buffer. */
|
||||||
count = bp - buf;
|
count = bp - buf;
|
||||||
sys_safecopyto(tp->tty_incaller,
|
sys_safecopyto(tp->tty_incaller, tp->tty_ingrant, tp->tty_incum,
|
||||||
tp->tty_ingrant, tp->tty_inoffset,
|
|
||||||
(vir_bytes) buf, (vir_bytes) count);
|
(vir_bytes) buf, (vir_bytes) count);
|
||||||
tp->tty_inoffset += count;
|
|
||||||
tp->tty_incum += count;
|
tp->tty_incum += count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Usually reply to the reader, possibly even if incum == 0 (EOF). */
|
/* Usually reply to the reader, possibly even if incum == 0 (EOF). */
|
||||||
if (tp->tty_inleft == 0) {
|
if (tp->tty_inleft == 0) {
|
||||||
tty_reply(DEV_REVIVE, tp->tty_incaller, tp->tty_inproc,
|
chardriver_reply_task(tp->tty_incaller, tp->tty_inid, tp->tty_incum);
|
||||||
tp->tty_ingrant, tp->tty_incum);
|
|
||||||
tp->tty_inleft = tp->tty_incum = 0;
|
tp->tty_inleft = tp->tty_incum = 0;
|
||||||
tp->tty_ingrant = GRANT_INVALID;
|
tp->tty_incaller = NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1510,9 +1480,8 @@ tty_t *tp;
|
||||||
if (result == OK) setattr(tp);
|
if (result == OK) setattr(tp);
|
||||||
}
|
}
|
||||||
tp->tty_ioreq = 0;
|
tp->tty_ioreq = 0;
|
||||||
tty_reply(DEV_REVIVE, tp->tty_iocaller, tp->tty_ioproc, tp->tty_iogrant,
|
chardriver_reply_task(tp->tty_iocaller, tp->tty_ioid, result);
|
||||||
result);
|
tp->tty_iocaller = NONE;
|
||||||
tp->tty_iogrant = GRANT_INVALID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
@ -1571,57 +1540,6 @@ tty_t *tp;
|
||||||
(*tp->tty_ioctl)(tp, 0);
|
(*tp->tty_ioctl)(tp, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
|
||||||
* tty_reply *
|
|
||||||
*===========================================================================*/
|
|
||||||
void
|
|
||||||
tty_reply_f(
|
|
||||||
file, line, code, replyee, proc_nr, grant, status)
|
|
||||||
char *file;
|
|
||||||
int line;
|
|
||||||
int code; /* DEV_OPEN_REPL, DEV_CLOSE_REPL, DEV_REVIVE */
|
|
||||||
endpoint_t replyee; /* destination address for the reply */
|
|
||||||
endpoint_t proc_nr; /* to whom should the reply go? */
|
|
||||||
cp_grant_id_t grant; /* which grant was involved? */
|
|
||||||
int status; /* reply code */
|
|
||||||
{
|
|
||||||
message m;
|
|
||||||
|
|
||||||
assert(code == DEV_OPEN_REPL || code == DEV_CLOSE_REPL || code == DEV_REVIVE);
|
|
||||||
|
|
||||||
/* Don't reply to KERNEL (kernel messages) */
|
|
||||||
if (replyee == KERNEL) return;
|
|
||||||
|
|
||||||
memset(&m, 0, sizeof(m));
|
|
||||||
|
|
||||||
m.REP_ENDPT = proc_nr;
|
|
||||||
m.REP_IO_GRANT = grant;
|
|
||||||
m.REP_STATUS = status;
|
|
||||||
|
|
||||||
status = _sendcall(replyee, code, &m);
|
|
||||||
if (status != OK)
|
|
||||||
printf("tty`tty_reply: send to %d failed: %d\n", replyee, status);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*===========================================================================*
|
|
||||||
* select_reply *
|
|
||||||
*===========================================================================*/
|
|
||||||
void select_reply(int code, endpoint_t replyee, dev_t minor, int ops)
|
|
||||||
{
|
|
||||||
message m;
|
|
||||||
int status;
|
|
||||||
|
|
||||||
memset(&m, 0, sizeof(m));
|
|
||||||
|
|
||||||
m.DEV_MINOR = minor;
|
|
||||||
m.DEV_SEL_OPS = ops;
|
|
||||||
|
|
||||||
status = _sendcall(replyee, code, &m);
|
|
||||||
if (status != OK)
|
|
||||||
printf("tty`select_reply: send to %d failed: %d\n", replyee, status);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* sigchar *
|
* sigchar *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
@ -1696,7 +1614,7 @@ static void tty_init()
|
||||||
|
|
||||||
tp->tty_intail = tp->tty_inhead = tp->tty_inbuf;
|
tp->tty_intail = tp->tty_inhead = tp->tty_inbuf;
|
||||||
tp->tty_min = 1;
|
tp->tty_min = 1;
|
||||||
tp->tty_ingrant = tp->tty_outgrant = tp->tty_iogrant = GRANT_INVALID;
|
tp->tty_incaller = tp->tty_outcaller = tp->tty_iocaller = NONE;
|
||||||
tp->tty_termios = termios_defaults;
|
tp->tty_termios = termios_defaults;
|
||||||
tp->tty_icancel = tp->tty_ocancel = tp->tty_ioctl = tp->tty_close =
|
tp->tty_icancel = tp->tty_ocancel = tp->tty_ioctl = tp->tty_close =
|
||||||
tp->tty_open = tty_devnop;
|
tp->tty_open = tty_devnop;
|
||||||
|
@ -1750,27 +1668,3 @@ int enable; /* set timer if true, otherwise unset */
|
||||||
cancel_timer(&tty_ptr->tty_tmr);
|
cancel_timer(&tty_ptr->tty_tmr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
|
||||||
* do_select *
|
|
||||||
*===========================================================================*/
|
|
||||||
static void do_select(tp, m_ptr)
|
|
||||||
register tty_t *tp; /* pointer to tty struct */
|
|
||||||
register message *m_ptr; /* pointer to message sent to the task */
|
|
||||||
{
|
|
||||||
int ops, ready_ops = 0, watch;
|
|
||||||
|
|
||||||
ops = m_ptr->DEV_SEL_OPS & (SEL_RD|SEL_WR|SEL_ERR);
|
|
||||||
watch = (m_ptr->DEV_SEL_OPS & SEL_NOTIFY) ? 1 : 0;
|
|
||||||
|
|
||||||
ready_ops = select_try(tp, ops);
|
|
||||||
|
|
||||||
if (!ready_ops && ops && watch) {
|
|
||||||
tp->tty_select_ops |= ops;
|
|
||||||
tp->tty_select_proc = m_ptr->m_source;
|
|
||||||
tp->tty_select_minor = m_ptr->DEV_MINOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(tp->tty_minor == m_ptr->DEV_MINOR);
|
|
||||||
select_reply(DEV_SEL_REPL1, m_ptr->m_source, tp->tty_minor, ready_ops);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/* tty.h - Terminals */
|
/* tty.h - Terminals */
|
||||||
|
|
||||||
|
#include <minix/chardriver.h>
|
||||||
#include <timers.h>
|
#include <timers.h>
|
||||||
|
|
||||||
#undef lock
|
#undef lock
|
||||||
|
@ -34,7 +35,7 @@ typedef void(*devfunarg_t) (struct tty *tp, int c);
|
||||||
typedef struct tty {
|
typedef struct tty {
|
||||||
int tty_events; /* set when TTY should inspect this line */
|
int tty_events; /* set when TTY should inspect this line */
|
||||||
int tty_index; /* index into TTY table */
|
int tty_index; /* index into TTY table */
|
||||||
int tty_minor; /* device minor number */
|
devminor_t tty_minor; /* device minor number */
|
||||||
|
|
||||||
/* Input queue. Typed characters are stored here until read by a program. */
|
/* Input queue. Typed characters are stored here until read by a program. */
|
||||||
u16_t *tty_inhead; /* pointer to place where next char goes */
|
u16_t *tty_inhead; /* pointer to place where next char goes */
|
||||||
|
@ -61,27 +62,24 @@ typedef struct tty {
|
||||||
char tty_openct; /* count of number of opens of this tty */
|
char tty_openct; /* count of number of opens of this tty */
|
||||||
|
|
||||||
/* Information about incomplete I/O requests is stored here. */
|
/* Information about incomplete I/O requests is stored here. */
|
||||||
endpoint_t tty_incaller; /* process that made the call (usually VFS) */
|
endpoint_t tty_incaller; /* process that made the call, or NONE */
|
||||||
endpoint_t tty_inproc; /* process that wants to read from tty */
|
cdev_id_t tty_inid; /* ID of suspended read request */
|
||||||
cp_grant_id_t tty_ingrant; /* grant where data is to go */
|
cp_grant_id_t tty_ingrant; /* grant where data is to go */
|
||||||
vir_bytes tty_inoffset; /* offset into grant */
|
size_t tty_inleft; /* how many chars are still needed */
|
||||||
int tty_inleft; /* how many chars are still needed */
|
size_t tty_incum; /* # chars input so far */
|
||||||
int tty_incum; /* # chars input so far */
|
endpoint_t tty_outcaller; /* process that made the call, or NONE */
|
||||||
endpoint_t tty_outcaller; /* process that made the call (usually VFS) */
|
cdev_id_t tty_outid; /* ID of suspended write request */
|
||||||
endpoint_t tty_outproc; /* process that wants to write to tty */
|
|
||||||
cp_grant_id_t tty_outgrant; /* grant where data comes from */
|
cp_grant_id_t tty_outgrant; /* grant where data comes from */
|
||||||
vir_bytes tty_outoffset; /* offset into grant */
|
size_t tty_outleft; /* # chars yet to be output */
|
||||||
int tty_outleft; /* # chars yet to be output */
|
size_t tty_outcum; /* # chars output so far */
|
||||||
int tty_outcum; /* # chars output so far */
|
endpoint_t tty_iocaller; /* process that made the call, or NONE */
|
||||||
endpoint_t tty_iocaller; /* process that made the call (usually VFS) */
|
cdev_id_t tty_ioid; /* ID of suspended ioctl request */
|
||||||
endpoint_t tty_ioproc; /* process that wants to do an ioctl */
|
unsigned int tty_ioreq; /* ioctl request code */
|
||||||
int tty_ioreq; /* ioctl request code */
|
|
||||||
cp_grant_id_t tty_iogrant; /* virtual address of ioctl buffer or grant */
|
cp_grant_id_t tty_iogrant; /* virtual address of ioctl buffer or grant */
|
||||||
|
|
||||||
/* select() data */
|
/* select() data */
|
||||||
int tty_select_ops; /* which operations are interesting */
|
int tty_select_ops; /* which operations are interesting */
|
||||||
endpoint_t tty_select_proc; /* which process wants notification */
|
endpoint_t tty_select_proc; /* which process wants notification */
|
||||||
dev_t tty_select_minor; /* sanity check only, can be removed */
|
|
||||||
|
|
||||||
/* Miscellaneous. */
|
/* Miscellaneous. */
|
||||||
devfun_t tty_ioctl; /* set line speed, etc. at the device level */
|
devfun_t tty_ioctl; /* set line speed, etc. at the device level */
|
||||||
|
@ -135,14 +133,11 @@ extern struct kmessages kmess;
|
||||||
void handle_events(struct tty *tp);
|
void handle_events(struct tty *tp);
|
||||||
void sigchar(struct tty *tp, int sig, int mayflush);
|
void sigchar(struct tty *tp, int sig, int mayflush);
|
||||||
void tty_task(void);
|
void tty_task(void);
|
||||||
|
tty_t *line2tty(devminor_t minor);
|
||||||
int in_process(struct tty *tp, char *buf, int count, int scode);
|
int in_process(struct tty *tp, char *buf, int count, int scode);
|
||||||
void out_process(struct tty *tp, char *bstart, char *bpos, char *bend,
|
void out_process(struct tty *tp, char *bstart, char *bpos, char *bend,
|
||||||
int *icount, int *ocount);
|
int *icount, int *ocount);
|
||||||
void tty_wakeup(clock_t now);
|
void tty_wakeup(clock_t now);
|
||||||
#define tty_reply(c, r, p, g, s) tty_reply_f(__FILE__, __LINE__, (c), (r), (p), (g), (s))
|
|
||||||
void tty_reply_f(char *f, int l, int code, endpoint_t replyee,
|
|
||||||
endpoint_t proc_nr, cp_grant_id_t grant, int status);
|
|
||||||
void select_reply(int code, endpoint_t replyee, dev_t minor, int ops);
|
|
||||||
int select_try(struct tty *tp, int ops);
|
int select_try(struct tty *tp, int ops);
|
||||||
int select_retry(struct tty *tp);
|
int select_retry(struct tty *tp);
|
||||||
|
|
||||||
|
@ -155,22 +150,21 @@ void kputc(int c);
|
||||||
void cons_stop(void);
|
void cons_stop(void);
|
||||||
void scr_init(struct tty *tp);
|
void scr_init(struct tty *tp);
|
||||||
void toggle_scroll(void);
|
void toggle_scroll(void);
|
||||||
int con_loadfont(message *m);
|
int con_loadfont(endpoint_t endpt, cp_grant_id_t grant);
|
||||||
void select_console(int cons_line);
|
void select_console(int cons_line);
|
||||||
void beep_x( unsigned freq, clock_t dur);
|
void beep_x( unsigned freq, clock_t dur);
|
||||||
void do_video(message *m);
|
void do_video(message *m, int ipc_status);
|
||||||
|
|
||||||
/* keyboard.c */
|
/* keyboard.c */
|
||||||
void kb_init(struct tty *tp);
|
void kb_init(struct tty *tp);
|
||||||
void kb_init_once(void);
|
void kb_init_once(void);
|
||||||
int kbd_loadmap(message *m);
|
int kbd_loadmap(endpoint_t endpt, cp_grant_id_t grant);
|
||||||
void do_fkey_ctl(message *m);
|
void do_fkey_ctl(message *m);
|
||||||
void kbd_interrupt(message *m);
|
void kbd_interrupt(message *m);
|
||||||
void do_kbd(message *m);
|
void do_kbd(message *m, int ipc_status);
|
||||||
void do_kb_inject(message *m);
|
void do_kb_inject(message *m);
|
||||||
void do_kbdaux(message *m);
|
|
||||||
|
|
||||||
/* pty.c */
|
/* pty.c */
|
||||||
void do_pty(struct tty *tp, message *m_ptr);
|
void do_pty(message *m_ptr, int ipc_status);
|
||||||
void pty_init(struct tty *tp);
|
void pty_init(struct tty *tp);
|
||||||
void select_retry_pty(struct tty *tp);
|
void select_retry_pty(struct tty *tp);
|
||||||
|
|
|
@ -18,7 +18,7 @@ INCS+= acpi.h audio_fw.h bitmap.h \
|
||||||
reboot.h rs.h safecopies.h sched.h sef.h sffs.h \
|
reboot.h rs.h safecopies.h sched.h sef.h sffs.h \
|
||||||
sound.h spin.h sys_config.h sysinfo.h \
|
sound.h spin.h sys_config.h sysinfo.h \
|
||||||
syslib.h sysutil.h termios.h timers.h type.h \
|
syslib.h sysutil.h termios.h timers.h type.h \
|
||||||
tty.h u64.h usb.h usb_ch9.h vbox.h \
|
u64.h usb.h usb_ch9.h vbox.h \
|
||||||
vboxfs.h vboxif.h vboxtype.h vm.h \
|
vboxfs.h vboxif.h vboxtype.h vm.h \
|
||||||
vfsif.h vtreefs.h libminixfs.h netsock.h \
|
vfsif.h vtreefs.h libminixfs.h netsock.h \
|
||||||
virtio.h
|
virtio.h
|
||||||
|
|
|
@ -1275,7 +1275,6 @@
|
||||||
|
|
||||||
|
|
||||||
#define TTY_FKEY_CONTROL (TTY_RQ_BASE + 1) /* control an F-key at TTY */
|
#define TTY_FKEY_CONTROL (TTY_RQ_BASE + 1) /* control an F-key at TTY */
|
||||||
#define OLD_FKEY_CONTROL 98 /* previously used for TTY_FKEY_CONTROL */
|
|
||||||
# define FKEY_REQUEST m2_i1 /* request to perform at TTY */
|
# define FKEY_REQUEST m2_i1 /* request to perform at TTY */
|
||||||
# define FKEY_MAP 10 /* observe function key */
|
# define FKEY_MAP 10 /* observe function key */
|
||||||
# define FKEY_UNMAP 11 /* stop observing function key */
|
# define FKEY_UNMAP 11 /* stop observing function key */
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
|
|
||||||
#ifndef _MINIX_TTY_H
|
|
||||||
#define _MINIX_TTY_H
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#define TTYMAGIC 0xb105
|
|
||||||
|
|
||||||
/* A struct that the tty driver can use to pass values to the boot monitor.
|
|
||||||
* Currently only the value of the origin of the first vty (console), so the
|
|
||||||
* boot monitor can properly display it when panicing (tty isn't scheduled
|
|
||||||
* to switch to the first vty). It's written at the end of video memory
|
|
||||||
* (video memory base + video memory size - sizeof(struct boot_tty_info).
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct boot_tty_info {
|
|
||||||
u16_t reserved[30]; /* reserved, set to 0 */
|
|
||||||
u16_t consorigin; /* origin in video memory of console */
|
|
||||||
u16_t conscursor; /* position of cursor of console */
|
|
||||||
u16_t flags; /* flags indicating which fields are valid */
|
|
||||||
u16_t magic; /* magic number indicating struct is valid */
|
|
||||||
};
|
|
||||||
|
|
||||||
#define BTIF_CONSORIGIN 0x01 /* consorigin is set */
|
|
||||||
#define BTIF_CONSCURSOR 0x02 /* conscursor is set */
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
#define TIOCSWINSZ _IOW('T', 17, struct winsize)
|
#define TIOCSWINSZ _IOW('T', 17, struct winsize)
|
||||||
#define TIOCGPGRP _IOW('T', 18, int)
|
#define TIOCGPGRP _IOW('T', 18, int)
|
||||||
#define TIOCSPGRP _IOW('T', 19, int)
|
#define TIOCSPGRP _IOW('T', 19, int)
|
||||||
#define TIOCSFON_OLD _IOW('T', 20, u8_t [8192])
|
|
||||||
#define TIOCSFON _IOW_BIG(1, u8_t [8192])
|
#define TIOCSFON _IOW_BIG(1, u8_t [8192])
|
||||||
|
|
||||||
/* Keyboard ioctls. */
|
/* Keyboard ioctls. */
|
||||||
|
|
Loading…
Reference in a new issue