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
15 changed files with 997 additions and 1060 deletions
|
@ -1221,7 +1221,7 @@
|
|||
./usr/include/minix/sysutil.h minix-sys
|
||||
./usr/include/minix/termios.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/types.h minix-sys obsolete
|
||||
./usr/include/minix/u64.h minix-sys
|
||||
|
|
|
@ -6,8 +6,8 @@ PROG= tty
|
|||
|
||||
SRCS += tty.c pty.c
|
||||
|
||||
DPADD+= ${LIBSYS} ${LIBTIMERS}
|
||||
LDADD+= -lsys -ltimers
|
||||
DPADD+= ${LIBCHARDRIVER} ${LIBSYS} ${LIBTIMERS}
|
||||
LDADD+= -lchardriver -lsys -ltimers
|
||||
|
||||
MAN=
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include "tty.h"
|
||||
|
||||
void
|
||||
do_video(message *m)
|
||||
do_video(message *m, int ipc_status)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ cons_stop(void)
|
|||
}
|
||||
|
||||
int
|
||||
con_loadfont(message *m)
|
||||
con_loadfont(endpoint_t endpt, cp_grant_id_t grant)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -19,12 +19,7 @@ do_kb_inject(message *m)
|
|||
}
|
||||
|
||||
void
|
||||
do_kbd(message *m)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
do_kbdaux(message *m)
|
||||
do_kbd(message *m, int ipc_status)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -34,7 +29,7 @@ kb_init_once(void)
|
|||
}
|
||||
|
||||
int
|
||||
kbd_loadmap(message *m)
|
||||
kbd_loadmap(endpoint_t endpt, cp_grant_id_t grant)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -237,11 +237,11 @@ rs_write(register tty_t *tp, int try)
|
|||
if (tp->tty_outcaller == KERNEL) {
|
||||
/* We're trying to print on kernel's behalf */
|
||||
memcpy(rs->ohead,
|
||||
(void *) tp->tty_outgrant + tp->tty_outoffset,
|
||||
(char *) tp->tty_outgrant + tp->tty_outcum,
|
||||
count);
|
||||
} else {
|
||||
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) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -262,24 +262,21 @@ rs_write(register tty_t *tp, int try)
|
|||
rs_ostart(rs);
|
||||
if ((rs->ohead += ocount) >= bufend(rs->obuf))
|
||||
rs->ohead -= buflen(rs->obuf);
|
||||
tp->tty_outoffset += count;
|
||||
tp->tty_outcum += count;
|
||||
if ((tp->tty_outleft -= count) == 0) {
|
||||
/* Output is finished, reply to the writer. */
|
||||
tty_reply(DEV_REVIVE, tp->tty_outcaller,
|
||||
tp->tty_outproc, tp->tty_outgrant,
|
||||
chardriver_reply_task(tp->tty_outcaller, tp->tty_outid,
|
||||
tp->tty_outcum);
|
||||
tp->tty_outcum = 0;
|
||||
tp->tty_outgrant = GRANT_INVALID;
|
||||
tp->tty_outcaller = NONE;
|
||||
}
|
||||
|
||||
}
|
||||
if (tp->tty_outleft > 0 && tp->tty_termios.c_ospeed == B0) {
|
||||
/* Oops, the line has hung up. */
|
||||
tty_reply(DEV_REVIVE, tp->tty_outcaller, tp->tty_outproc,
|
||||
tp->tty_outgrant, EIO);
|
||||
chardriver_reply_task(tp->tty_outcaller, tp->tty_outid, EIO);
|
||||
tp->tty_outleft = tp->tty_outcum = 0;
|
||||
tp->tty_outgrant = GRANT_INVALID;
|
||||
tp->tty_outcaller = NONE;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
|
|
@ -18,16 +18,10 @@
|
|||
|
||||
#include <minix/drivers.h>
|
||||
#include <termios.h>
|
||||
#include <assert.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/vm.h>
|
||||
#include <sys/video.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"
|
||||
|
||||
/* 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);
|
||||
#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 *
|
||||
*===========================================================================*/
|
||||
|
@ -174,16 +180,14 @@ int try;
|
|||
if (count > sizeof(buf)) count = sizeof(buf);
|
||||
if (tp->tty_outcaller == KERNEL) {
|
||||
/* We're trying to print on kernel's behalf */
|
||||
memcpy(buf, (void *) tp->tty_outgrant + tp->tty_outoffset,
|
||||
count);
|
||||
memcpy(buf, (char *) tp->tty_outgrant + tp->tty_outcum, count);
|
||||
} else {
|
||||
if ((result = sys_safecopyfrom(tp->tty_outcaller,
|
||||
tp->tty_outgrant, tp->tty_outoffset,
|
||||
tp->tty_outgrant, tp->tty_outcum,
|
||||
(vir_bytes) buf, count)) != OK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
tp->tty_outoffset += count;
|
||||
tbuf = buf;
|
||||
|
||||
/* Update terminal data structure. */
|
||||
|
@ -215,10 +219,10 @@ int try;
|
|||
|
||||
/* Reply to the writer if all output is finished or if an error occured. */
|
||||
if (tp->tty_outleft == 0 || result != OK) {
|
||||
tty_reply(DEV_REVIVE, tp->tty_outcaller, tp->tty_outproc,
|
||||
tp->tty_outgrant, result != OK ? result : tp->tty_outcum);
|
||||
chardriver_reply_task(tp->tty_outcaller, tp->tty_outid,
|
||||
result != OK ? result : tp->tty_outcum);
|
||||
tp->tty_outcum = tp->tty_outleft = 0;
|
||||
tp->tty_outgrant = GRANT_INVALID;
|
||||
tp->tty_outcaller = NONE;
|
||||
}
|
||||
|
||||
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 *
|
||||
*===========================================================================*/
|
||||
void do_video(message *m)
|
||||
void do_video(message *m, int ipc_status)
|
||||
{
|
||||
int r;
|
||||
|
||||
/* 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);
|
||||
chardriver_process(&video_tab, m, ipc_status);
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* beep_x *
|
||||
*===========================================================================*/
|
||||
|
@ -1137,12 +1126,11 @@ void select_console(int cons_line)
|
|||
/*===========================================================================*
|
||||
* con_loadfont *
|
||||
*===========================================================================*/
|
||||
int con_loadfont(m)
|
||||
message *m;
|
||||
int con_loadfont(endpoint_t endpt, cp_grant_id_t grant)
|
||||
{
|
||||
|
||||
/* Load a font into the EGA or VGA adapter. */
|
||||
int result;
|
||||
int r, r2;
|
||||
static struct sequence seq1[7] = {
|
||||
{ GA_SEQUENCER_INDEX, 0x00, 0x01 },
|
||||
{ GA_SEQUENCER_INDEX, 0x02, 0x04 },
|
||||
|
@ -1164,17 +1152,14 @@ message *m;
|
|||
|
||||
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,
|
||||
(vir_bytes) font_memory, GA_FONT_SIZE) != OK) {
|
||||
printf("tty: copying from %d failed\n", m->m_source);
|
||||
return EFAULT;
|
||||
}
|
||||
r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) font_memory, GA_FONT_SIZE);
|
||||
|
||||
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
|
||||
{
|
||||
int minor;
|
||||
devminor_t minor;
|
||||
int nr_open;
|
||||
char buf[KBD_BUFSZ];
|
||||
int offset;
|
||||
int avail;
|
||||
int req_size;
|
||||
int req_proc;
|
||||
size_t req_size;
|
||||
cdev_id_t req_id;
|
||||
cp_grant_id_t req_grant;
|
||||
vir_bytes req_addr_offset;
|
||||
int incaller;
|
||||
int select_ops;
|
||||
int select_proc;
|
||||
int select_minor; /* sanity check only, can be removed */
|
||||
endpoint_t req_caller;
|
||||
unsigned int select_ops;
|
||||
endpoint_t select_proc;
|
||||
} kbd, kbdaux;
|
||||
|
||||
/* 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 timer_t tmr_kbd_wd;
|
||||
|
||||
static void handle_req(struct kbd *kbdp, message *m);
|
||||
static void kbc_cmd0(int cmd);
|
||||
static void kbc_cmd1(int cmd, int data);
|
||||
static int kbc_read(void);
|
||||
|
@ -171,220 +168,284 @@ static int kb_read(struct tty *tp, int try);
|
|||
static unsigned map_key(int scode);
|
||||
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. */
|
||||
tickdelay(micros_to_ticks(usecs));
|
||||
switch (minor) {
|
||||
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;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* do_kbd *
|
||||
* kbd_close *
|
||||
*===========================================================================*/
|
||||
void do_kbd(message *m)
|
||||
static int
|
||||
kbd_close(devminor_t minor)
|
||||
{
|
||||
handle_req(&kbd, m);
|
||||
}
|
||||
struct kbd *kbdp;
|
||||
|
||||
if ((kbdp = line2kbd(minor)) == NULL)
|
||||
return ENXIO;
|
||||
|
||||
/*===========================================================================*
|
||||
* 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)
|
||||
{
|
||||
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:
|
||||
|
||||
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)
|
||||
{
|
||||
/* 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;
|
||||
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 > m->COUNT)
|
||||
n= m->COUNT;
|
||||
/* Handle read request. */
|
||||
n = kbdp->avail;
|
||||
if (n > (ssize_t) size)
|
||||
n = size;
|
||||
if (kbdp->offset + n > KBD_BUFSZ)
|
||||
n= KBD_BUFSZ-kbdp->offset;
|
||||
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,
|
||||
r = sys_safecopyto(endpt, grant, 0,
|
||||
(vir_bytes) &kbdp->buf[kbdp->offset], n);
|
||||
if (r == OK)
|
||||
{
|
||||
kbdp->offset= (kbdp->offset+n) % KBD_BUFSZ;
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
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.
|
||||
/*
|
||||
* 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);
|
||||
for (i = 0; i < size; i++) {
|
||||
r = sys_safecopyfrom(endpt, grant, i, (vir_bytes) &c, 1);
|
||||
if (r != OK)
|
||||
break;
|
||||
return i ? i : r;
|
||||
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;
|
||||
return r;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
/*===========================================================================*
|
||||
* 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 */
|
||||
|
||||
r= sys_safecopyfrom(m->m_source, (cp_grant_id_t)
|
||||
m->IO_GRANT, 0, (vir_bytes) &leds,
|
||||
switch (request) {
|
||||
case KIOCSLEDS:
|
||||
r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &leds,
|
||||
sizeof(leds));
|
||||
if (r != OK)
|
||||
break;
|
||||
b= 0;
|
||||
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)
|
||||
{
|
||||
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.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,
|
||||
return OK;
|
||||
|
||||
case KIOCBELL:
|
||||
r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &bell,
|
||||
sizeof(bell));
|
||||
if (r != OK)
|
||||
break;
|
||||
return r;
|
||||
|
||||
ticks= bell.kb_duration.tv_usec * system_hz / 1000000;
|
||||
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;
|
||||
return OK;
|
||||
|
||||
default:
|
||||
printf("Warning, TTY(kbd) got unexpected request %d from %d\n",
|
||||
m->m_type, m->m_source);
|
||||
r= EINVAL;
|
||||
return ENOTTY;
|
||||
}
|
||||
tty_reply(DEV_REVIVE, m->m_source, m->USER_ENDPT,
|
||||
(cp_grant_id_t) m->IO_GRANT, r);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* 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 *
|
||||
*===========================================================================*/
|
||||
void
|
||||
do_kbd(message *m, int ipc_status)
|
||||
{
|
||||
chardriver_process(&kbd_tab, m, ipc_status);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* map_key *
|
||||
|
@ -469,7 +530,7 @@ void kbd_interrupt(message *UNUSED(m_ptr))
|
|||
if (n <= 0)
|
||||
panic("kbd_interrupt: bad n: %d", n);
|
||||
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);
|
||||
if (r == OK)
|
||||
{
|
||||
|
@ -478,14 +539,12 @@ void kbd_interrupt(message *UNUSED(m_ptr))
|
|||
r= n;
|
||||
} else printf("copy in revive kbd failed: %d\n", r);
|
||||
|
||||
tty_reply(DEV_REVIVE, kbdp->incaller, kbdp->req_proc,
|
||||
kbdp->req_grant, r);
|
||||
kbdp->req_grant = GRANT_INVALID;
|
||||
chardriver_reply_task(kbdp->req_caller, kbdp->req_id, r);
|
||||
kbdp->req_caller = NONE;
|
||||
}
|
||||
/* Only satisfy pending select if characters weren't just read. */
|
||||
if (kbdp->avail && (kbdp->select_ops & SEL_RD)) {
|
||||
assert(kbdp->select_minor == kbdp->minor);
|
||||
select_reply(DEV_SEL_REPL2, kbdp->select_proc, kbdp->minor,
|
||||
chardriver_reply_select(kbdp->select_proc, kbdp->minor,
|
||||
SEL_RD);
|
||||
kbdp->select_ops &= ~SEL_RD;
|
||||
}
|
||||
|
@ -1024,12 +1083,10 @@ void kb_init_once(void)
|
|||
/*===========================================================================*
|
||||
* kbd_loadmap *
|
||||
*===========================================================================*/
|
||||
int kbd_loadmap(m)
|
||||
message *m;
|
||||
int kbd_loadmap(endpoint_t endpt, cp_grant_id_t grant)
|
||||
{
|
||||
/* Load a new keymap. */
|
||||
return sys_safecopyfrom(m->m_source, (cp_grant_id_t) m->IO_GRANT,
|
||||
0, (vir_bytes) keymap, (vir_bytes) sizeof(keymap));
|
||||
return sys_safecopyfrom(endpt, grant, 0, (vir_bytes) keymap, 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. */
|
||||
if (tp->tty_outcaller == KERNEL) {
|
||||
/* 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 {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -265,22 +266,20 @@ static int rs_write(register tty_t *tp, int try)
|
|||
rs_ostart(rs);
|
||||
if ((rs->ohead += ocount) >= bufend(rs->obuf))
|
||||
rs->ohead -= buflen(rs->obuf);
|
||||
tp->tty_outoffset += count;
|
||||
tp->tty_outcum += count;
|
||||
if ((tp->tty_outleft -= count) == 0) {
|
||||
/* Output is finished, reply to the writer. */
|
||||
tty_reply(DEV_REVIVE, tp->tty_outcaller, tp->tty_outproc,
|
||||
tp->tty_outgrant, tp->tty_outcum);
|
||||
chardriver_reply_task(tp->tty_outcaller, tp->tty_outid,
|
||||
tp->tty_outcum);
|
||||
tp->tty_outcum = 0;
|
||||
tp->tty_outgrant = GRANT_INVALID;
|
||||
tp->tty_outcaller = NONE;
|
||||
}
|
||||
}
|
||||
if (tp->tty_outleft > 0 && tp->tty_termios.c_ospeed == B0) {
|
||||
/* Oops, the line has hung up. */
|
||||
tty_reply(DEV_REVIVE, tp->tty_outcaller, tp->tty_outproc,
|
||||
tp->tty_outgrant, EIO);
|
||||
chardriver_reply_task(tp->tty_outcaller, tp->tty_outid, EIO);
|
||||
tp->tty_outleft = tp->tty_outcum = 0;
|
||||
tp->tty_outgrant = GRANT_INVALID;
|
||||
tp->tty_outcaller = NONE;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
|
|
@ -9,20 +9,16 @@
|
|||
* 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
|
||||
* 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
|
||||
* "screen" functions of the ttypX devices.
|
||||
* etc.) using the pty_slave_read() and pty_slave_write() functions as the
|
||||
* "keyboard" and "screen" functions of the ttypX devices.
|
||||
* 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
|
||||
* end are to be read at the other end and vice-versa.
|
||||
* used both for the tty (slave) and the pty (master) end of the pseudo tty.
|
||||
* Writes to one end are to be read at the other end and vice-versa.
|
||||
*/
|
||||
|
||||
#include <minix/drivers.h>
|
||||
#include <assert.h>
|
||||
#include <termios.h>
|
||||
#include <signal.h>
|
||||
#include <minix/com.h>
|
||||
#include <minix/callnr.h>
|
||||
#include <sys/select.h>
|
||||
#include "tty.h"
|
||||
|
||||
#if NR_PTYS > 0
|
||||
|
@ -32,21 +28,19 @@ typedef struct pty {
|
|||
tty_t *tty; /* associated TTY structure */
|
||||
char state; /* flags: busy, closed, ... */
|
||||
|
||||
/* Read call on /dev/ptypX. */
|
||||
int rdcaller; /* process making the call (usually FS) */
|
||||
int rdproc; /* process that wants to read from the pty */
|
||||
cp_grant_id_t rdgrant; /* grant for readers address space */
|
||||
vir_bytes rdoffset; /* offset in above grant */
|
||||
int rdleft; /* # bytes yet to be read */
|
||||
int rdcum; /* # bytes written so far */
|
||||
/* Read call on master (/dev/ptypX). */
|
||||
endpoint_t rdcaller; /* process making the call, or NONE if none */
|
||||
cdev_id_t rdid; /* ID of suspended read request */
|
||||
cp_grant_id_t rdgrant; /* grant for reader's address space */
|
||||
size_t rdleft; /* # bytes yet to be read */
|
||||
size_t rdcum; /* # bytes written so far */
|
||||
|
||||
/* Write call to /dev/ptypX. */
|
||||
int wrcaller; /* process making the call (usually FS) */
|
||||
int wrproc; /* process that wants to write to the pty */
|
||||
cp_grant_id_t wrgrant; /* grant for writers address space */
|
||||
vir_bytes wroffset; /* offset in above grant */
|
||||
int wrleft; /* # bytes yet to be written */
|
||||
int wrcum; /* # bytes written so far */
|
||||
/* Write call to master (/dev/ptypX). */
|
||||
endpoint_t wrcaller; /* process making the call, or NONE if none*/
|
||||
cdev_id_t wrid; /* ID of suspended write request */
|
||||
cp_grant_id_t wrgrant; /* grant for writer's address space */
|
||||
size_t wrleft; /* # bytes yet to be written */
|
||||
size_t wrcum; /* # bytes written so far */
|
||||
|
||||
/* Output 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 */
|
||||
|
||||
/* select() data. */
|
||||
int select_ops; /* Which operations do we want to know about? */
|
||||
int select_proc; /* Who wants to know about it? */
|
||||
dev_t select_minor; /* sanity check only, can be removed */
|
||||
unsigned int select_ops; /* Which operations do we want to know about? */
|
||||
endpoint_t select_proc; /* Who wants to know about it? */
|
||||
} pty_t;
|
||||
|
||||
#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 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_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_icancel(tty_t *tp, int try);
|
||||
static int pty_ocancel(tty_t *tp, int try);
|
||||
static void pty_select(tty_t *tp, message *m);
|
||||
|
||||
static int pty_master_open(devminor_t minor, int access,
|
||||
endpoint_t user_endpt);
|
||||
static int pty_master_close(devminor_t minor);
|
||||
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
|
||||
};
|
||||
|
||||
/*===========================================================================*
|
||||
* do_pty *
|
||||
* pty_master_open *
|
||||
*===========================================================================*/
|
||||
void do_pty(tty_t *tp, message *m_ptr)
|
||||
static int pty_master_open(devminor_t minor, int UNUSED(access),
|
||||
endpoint_t UNUSED(user_endpt))
|
||||
{
|
||||
/* Perform an open/close/read/write call on a /dev/ptypX device. */
|
||||
pty_t *pp = tp->tty_priv;
|
||||
int r;
|
||||
tty_t *tp;
|
||||
pty_t *pp;
|
||||
|
||||
switch (m_ptr->m_type) {
|
||||
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 ((tp = line2tty(minor)) == NULL)
|
||||
return ENXIO;
|
||||
pp = tp->tty_priv;
|
||||
|
||||
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;
|
||||
if (pp->state & PTY_ACTIVE)
|
||||
return EIO;
|
||||
|
||||
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:
|
||||
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);
|
||||
}
|
||||
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);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* pty_write *
|
||||
* pty_master_read *
|
||||
*===========================================================================*/
|
||||
static int pty_write(tty_t *tp, int try)
|
||||
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 *
|
||||
*===========================================================================*/
|
||||
void do_pty(message *m_ptr, int ipc_status)
|
||||
{
|
||||
/* Process a request for a PTY master (/dev/ptypX) device. */
|
||||
|
||||
chardriver_process(&pty_master_tab, m_ptr, ipc_status);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* pty_slave_write *
|
||||
*===========================================================================*/
|
||||
static int pty_slave_write(tty_t *tp, int try)
|
||||
{
|
||||
/* (*dev_write)() routine for PTYs. Transfer bytes from the writer on
|
||||
* /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;
|
||||
int count, ocount, s;
|
||||
|
||||
|
||||
/* PTY closed down? */
|
||||
if (pp->state & PTY_CLOSED) {
|
||||
if (try) return 1;
|
||||
if (tp->tty_outleft > 0) {
|
||||
tty_reply(DEV_REVIVE, tp->tty_outcaller, tp->tty_outproc,
|
||||
tp->tty_outgrant, EIO);
|
||||
chardriver_reply_task(tp->tty_outcaller, tp->tty_outid, EIO);
|
||||
tp->tty_outleft = tp->tty_outcum = 0;
|
||||
tp->tty_outgrant = GRANT_INVALID;
|
||||
tp->tty_outcaller = NONE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -252,11 +372,11 @@ static int pty_write(tty_t *tp, int try)
|
|||
/* Copy from user space to the PTY output buffer. */
|
||||
if (tp->tty_outcaller == KERNEL) {
|
||||
/* 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);
|
||||
} else {
|
||||
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) {
|
||||
break;
|
||||
}
|
||||
|
@ -275,15 +395,13 @@ static int pty_write(tty_t *tp, int try)
|
|||
pp->ohead -= buflen(pp->obuf);
|
||||
pty_start(pp);
|
||||
|
||||
tp->tty_outoffset += count;
|
||||
|
||||
tp->tty_outcum += count;
|
||||
if ((tp->tty_outleft -= count) == 0) {
|
||||
/* Output is finished, reply to the writer. */
|
||||
tty_reply(DEV_REVIVE, tp->tty_outcaller, tp->tty_outproc,
|
||||
tp->tty_outgrant, tp->tty_outcum);
|
||||
chardriver_reply_task(tp->tty_outcaller, tp->tty_outid,
|
||||
tp->tty_outcum);
|
||||
tp->tty_outcum = 0;
|
||||
tp->tty_outgrant = GRANT_INVALID;
|
||||
tp->tty_outcaller = NONE;
|
||||
}
|
||||
}
|
||||
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.) */
|
||||
|
||||
|
@ -330,11 +448,10 @@ static void pty_start(pty_t *pp)
|
|||
if (count == 0) break;
|
||||
|
||||
/* Copy from the output buffer to the readers address space. */
|
||||
if((s = sys_safecopyto(pp->rdcaller, pp->rdgrant,
|
||||
pp->rdoffset, (vir_bytes) pp->otail, count)) != OK) {
|
||||
if((s = sys_safecopyto(pp->rdcaller, pp->rdgrant, pp->rdcum,
|
||||
(vir_bytes) pp->otail, count)) != OK) {
|
||||
break;
|
||||
}
|
||||
pp->rdoffset += count;
|
||||
|
||||
/* Bookkeeping. */
|
||||
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
|
||||
* 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
|
||||
* 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 (try) return 1;
|
||||
if (tp->tty_inleft > 0) {
|
||||
tty_reply(DEV_REVIVE, tp->tty_incaller, tp->tty_inproc,
|
||||
tp->tty_ingrant, tp->tty_incum);
|
||||
chardriver_reply_task(tp->tty_incaller, tp->tty_inid,
|
||||
tp->tty_incum);
|
||||
tp->tty_inleft = tp->tty_incum = 0;
|
||||
tp->tty_ingrant = GRANT_INVALID;
|
||||
tp->tty_incaller = NONE;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -393,12 +509,11 @@ static int pty_read(tty_t *tp, int try)
|
|||
int s;
|
||||
|
||||
/* 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) {
|
||||
printf("pty: safecopy failed (error %d)\n", s);
|
||||
break;
|
||||
}
|
||||
pp->wroffset++;
|
||||
|
||||
/* Input processing. */
|
||||
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. */
|
||||
pp->wrcum++;
|
||||
if (--pp->wrleft == 0) {
|
||||
tty_reply(DEV_REVIVE, pp->wrcaller, pp->wrproc, pp->wrgrant,
|
||||
pp->wrcum);
|
||||
chardriver_reply_task(pp->wrcaller, pp->wrid, pp->wrcum);
|
||||
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. */
|
||||
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. */
|
||||
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->rdleft > 0) {
|
||||
tty_reply(DEV_REVIVE, pp->rdcaller, pp->rdproc, pp->rdgrant,
|
||||
pp->rdcum);
|
||||
chardriver_reply_task(pp->rdcaller, pp->rdid, pp->rdcum);
|
||||
pp->rdleft = pp->rdcum = 0;
|
||||
pp->rdgrant = GRANT_INVALID;
|
||||
pp->rdcaller = NONE;
|
||||
}
|
||||
|
||||
if (pp->wrleft > 0) {
|
||||
tty_reply(DEV_REVIVE, pp->wrcaller, pp->wrproc, pp->wrgrant,
|
||||
pp->wrcum);
|
||||
pp->wrcum = 0;
|
||||
pp->wrgrant = GRANT_INVALID;
|
||||
chardriver_reply_task(pp->wrcaller, pp->wrid, pp->wrcum);
|
||||
pp->wrleft = pp->wrcum = 0;
|
||||
pp->wrcaller = NONE;
|
||||
}
|
||||
|
||||
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. */
|
||||
pty_t *pp = tp->tty_priv;
|
||||
|
||||
if (pp->wrleft > 0) {
|
||||
tty_reply(DEV_REVIVE, pp->wrcaller, pp->wrproc, pp->wrgrant,
|
||||
pp->wrcum + pp->wrleft);
|
||||
chardriver_reply_task(pp->wrcaller, pp->wrid, pp->wrcum + pp->wrleft);
|
||||
pp->wrcum = pp->wrleft = 0;
|
||||
pp->wrgrant = GRANT_INVALID;
|
||||
pp->wrcaller = NONE;
|
||||
}
|
||||
|
||||
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. */
|
||||
pty_t *pp = tp->tty_priv;
|
||||
|
@ -509,86 +620,21 @@ void pty_init(tty_t *tp)
|
|||
pp = tp->tty_priv = &pty_table[line];
|
||||
pp->tty = tp;
|
||||
pp->select_ops = 0;
|
||||
pp->rdgrant = GRANT_INVALID;
|
||||
pp->wrgrant = GRANT_INVALID;
|
||||
pp->rdcaller = NONE;
|
||||
pp->wrcaller = NONE;
|
||||
|
||||
/* Set up output queue. */
|
||||
pp->ohead = pp->otail = pp->obuf;
|
||||
|
||||
/* Fill in TTY function hooks. */
|
||||
tp->tty_devread = pty_read;
|
||||
tp->tty_devwrite = pty_write;
|
||||
tp->tty_echo = pty_echo;
|
||||
tp->tty_icancel = pty_icancel;
|
||||
tp->tty_ocancel = pty_ocancel;
|
||||
tp->tty_open = pty_open;
|
||||
tp->tty_close = pty_close;
|
||||
tp->tty_devread = pty_slave_read;
|
||||
tp->tty_devwrite = pty_slave_write;
|
||||
tp->tty_echo = pty_slave_echo;
|
||||
tp->tty_icancel = pty_slave_icancel;
|
||||
tp->tty_ocancel = pty_slave_ocancel;
|
||||
tp->tty_open = pty_slave_open;
|
||||
tp->tty_close = pty_slave_close;
|
||||
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 */
|
||||
|
|
|
@ -60,11 +60,7 @@
|
|||
#include <termios.h>
|
||||
#include <sys/ioc_tty.h>
|
||||
#include <signal.h>
|
||||
#include <minix/callnr.h>
|
||||
#include <minix/sys_config.h>
|
||||
#include <minix/tty.h>
|
||||
#include <minix/keymap.h>
|
||||
#include <minix/endpoint.h>
|
||||
#include "tty.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
|
@ -101,13 +97,6 @@ struct kmessages kmess;
|
|||
|
||||
static void tty_timed_out(timer_t *tp);
|
||||
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 int tty_echo(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_init(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_kernel_color(char color[CONS_ARG]);
|
||||
static void set_color(tty_t *tp, int color);
|
||||
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. */
|
||||
static struct termios termios_defaults = {
|
||||
TINPUT_DEF, TOUTPUT_DEF, TCTRL_DEF, TLOCAL_DEF,
|
||||
|
@ -160,7 +169,7 @@ int main(void)
|
|||
message tty_mess; /* buffer for all incoming messages */
|
||||
int ipc_status;
|
||||
unsigned line;
|
||||
int r, code;
|
||||
int r;
|
||||
register tty_t *tp;
|
||||
|
||||
/* SEF local startup. */
|
||||
|
@ -217,7 +226,6 @@ int main(void)
|
|||
|
||||
switch (tty_mess.m_type) {
|
||||
case TTY_FKEY_CONTROL: /* (un)register a fkey observer */
|
||||
case OLD_FKEY_CONTROL: /* old number */
|
||||
do_fkey_ctl(&tty_mess);
|
||||
continue;
|
||||
case INPUT_EVENT:
|
||||
|
@ -227,76 +235,34 @@ int main(void)
|
|||
; /* 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.
|
||||
* All requests have a minor device number.
|
||||
*/
|
||||
line = tty_mess.DEVICE;
|
||||
if (line == CONS_MINOR || line == LOG_MINOR) {
|
||||
/* /dev/log output goes to /dev/console */
|
||||
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);
|
||||
if (line == KBD_MINOR || line == KBDAUX_MINOR) {
|
||||
do_kbd(&tty_mess, ipc_status);
|
||||
continue;
|
||||
} else if (line == VIDEO_MINOR) {
|
||||
do_video(&tty_mess);
|
||||
do_video(&tty_mess, ipc_status);
|
||||
continue;
|
||||
} else {
|
||||
tp = line2tty(line);
|
||||
|
||||
} else if (line - PTYPX_MINOR < NR_PTYS &&
|
||||
tty_mess.m_type != DEV_IOCTL_S) {
|
||||
/* Terminals and pseudo terminals belong together. We can only
|
||||
* make a distinction between the two based on position in the
|
||||
* tty_table and not on minor number (i.e., use ispty macro).
|
||||
* Hence this special case.
|
||||
*/
|
||||
if (line - PTYPX_MINOR < NR_PTYS &&
|
||||
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);
|
||||
do_pty(&tty_mess, ipc_status);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Execute the requested device driver function. */
|
||||
switch (tty_mess.m_type) {
|
||||
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);
|
||||
}
|
||||
chardriver_process(&tty_tab, &tty_mess, ipc_status);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -305,47 +271,41 @@ int main(void)
|
|||
static void
|
||||
set_color(tty_t *tp, int color)
|
||||
{
|
||||
message msg;
|
||||
char buf[8];
|
||||
|
||||
buf[0] = '\033';
|
||||
snprintf(&buf[1], sizeof(buf) - 1, "[1;%dm", color);
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.m_source = KERNEL;
|
||||
msg.IO_GRANT = buf;
|
||||
msg.COUNT = sizeof(buf);
|
||||
do_write(tp, &msg);
|
||||
do_write(tp->tty_minor, 0, KERNEL, (cp_grant_id_t) buf, sizeof(buf),
|
||||
FLG_OP_NONBLOCK, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
reset_color(tty_t *tp)
|
||||
{
|
||||
message msg;
|
||||
char buf[8];
|
||||
|
||||
#define SGR_COLOR_RESET 39
|
||||
buf[0] = '\033';
|
||||
snprintf(&buf[1], sizeof(buf) - 1, "[0;%dm", SGR_COLOR_RESET);
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.m_source = KERNEL;
|
||||
msg.IO_GRANT = buf;
|
||||
msg.COUNT = sizeof(buf);
|
||||
do_write(tp, &msg);
|
||||
do_write(tp->tty_minor, 0, KERNEL, (cp_grant_id_t) buf, sizeof(buf),
|
||||
FLG_OP_NONBLOCK, 0);
|
||||
}
|
||||
|
||||
static tty_t *
|
||||
line2tty(int line)
|
||||
tty_t *
|
||||
line2tty(devminor_t line)
|
||||
{
|
||||
/* Convert a terminal line to tty_table pointer */
|
||||
|
||||
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) {
|
||||
return(NULL);
|
||||
} else if ((line - CONS_MINOR) < NR_CONS) {
|
||||
tp = tty_addr(line - CONS_MINOR);
|
||||
} else if (line == LOG_MINOR) {
|
||||
tp = tty_addr(consoleline);
|
||||
} else if ((line - RS232_MINOR) < NR_RS_LINES) {
|
||||
tp = tty_addr(line - RS232_MINOR + NR_CONS);
|
||||
} else if ((line - TTYPX_MINOR) < NR_PTYS) {
|
||||
|
@ -356,6 +316,9 @@ line2tty(int line)
|
|||
tp = NULL;
|
||||
}
|
||||
|
||||
if (tp != NULL && !tty_active(tp))
|
||||
tp = NULL;
|
||||
|
||||
return(tp);
|
||||
}
|
||||
|
||||
|
@ -430,7 +393,7 @@ set_console_line(char term[CONS_ARG])
|
|||
}
|
||||
|
||||
/* 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++) {
|
||||
char sercons[6];
|
||||
strlcpy(sercons, "tty00", sizeof(sercons));
|
||||
|
@ -465,7 +428,6 @@ do_new_kmess(void)
|
|||
static int prev_next = 0;
|
||||
int next, bytes, copy, restore = 0;
|
||||
tty_t *tp, rtp;
|
||||
message print_kmsg;
|
||||
|
||||
assert(_minix_kerninfo);
|
||||
kmess_ptr = _minix_kerninfo->kmessages;
|
||||
|
@ -491,7 +453,7 @@ do_new_kmess(void)
|
|||
}
|
||||
|
||||
tp = line2tty(consoleline);
|
||||
if (tp == NULL || !tty_active(tp))
|
||||
if (tp == NULL)
|
||||
panic("Don't know where to send kernel messages");
|
||||
if (tp->tty_outleft > 0) {
|
||||
/* Terminal is already printing */
|
||||
|
@ -502,11 +464,9 @@ do_new_kmess(void)
|
|||
|
||||
if (kernel_msg_color != 0)
|
||||
set_color(tp, kernel_msg_color);
|
||||
memset(&print_kmsg, 0, sizeof(print_kmsg));
|
||||
print_kmsg.m_source = KERNEL;
|
||||
print_kmsg.IO_GRANT = kernel_buf_copy;
|
||||
print_kmsg.COUNT = bytes;
|
||||
do_write(tp, &print_kmsg);
|
||||
do_write(tp->tty_minor, 0, KERNEL,
|
||||
(cp_grant_id_t) kernel_buf_copy, bytes,
|
||||
FLG_OP_NONBLOCK, 0);
|
||||
if (kernel_msg_color != 0)
|
||||
reset_color(tp);
|
||||
if (restore) {
|
||||
|
@ -541,37 +501,33 @@ static void sef_cb_signal_handler(int signo)
|
|||
/*===========================================================================*
|
||||
* do_read *
|
||||
*===========================================================================*/
|
||||
static void do_read(tp, m_ptr)
|
||||
register tty_t *tp; /* pointer to tty struct */
|
||||
register message *m_ptr; /* pointer to message sent to the task */
|
||||
static ssize_t do_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)
|
||||
{
|
||||
/* A process wants to read from a terminal. */
|
||||
tty_t *tp;
|
||||
int r;
|
||||
|
||||
if ((tp = line2tty(minor)) == NULL)
|
||||
return ENXIO;
|
||||
|
||||
/* Check if there is already a process hanging in a read, check if the
|
||||
* parameters are correct, do I/O.
|
||||
*/
|
||||
if (tp->tty_inleft > 0) {
|
||||
r = EIO;
|
||||
} else
|
||||
if (m_ptr->COUNT <= 0) {
|
||||
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_incaller != NONE || tp->tty_inleft > 0)
|
||||
return EIO;
|
||||
if (size <= 0)
|
||||
return EINVAL;
|
||||
|
||||
if (!(tp->tty_termios.c_lflag & ICANON)
|
||||
&& tp->tty_termios.c_cc[VTIME] > 0) {
|
||||
/* Copy information from the message to the tty struct. */
|
||||
tp->tty_incaller = endpt;
|
||||
tp->tty_inid = id;
|
||||
tp->tty_ingrant = grant;
|
||||
assert(tp->tty_incum == 0);
|
||||
tp->tty_inleft = size;
|
||||
|
||||
if (!(tp->tty_termios.c_lflag & ICANON) && tp->tty_termios.c_cc[VTIME] > 0) {
|
||||
if (tp->tty_termios.c_cc[VMIN] == 0) {
|
||||
/* MIN & TIME specify a read timer that finishes the
|
||||
* read in TIME/10 seconds if no bytes are available.
|
||||
|
@ -593,89 +549,90 @@ register message *m_ptr; /* pointer to message sent to the task */
|
|||
in_transfer(tp);
|
||||
/* ...then go back for more. */
|
||||
handle_events(tp);
|
||||
if (tp->tty_inleft == 0) {
|
||||
return; /* already done */
|
||||
}
|
||||
if (tp->tty_inleft == 0)
|
||||
return EDONTREPLY; /* already done */
|
||||
|
||||
/* There were no bytes in the input queue available. */
|
||||
if (m_ptr->FLAGS & FLG_OP_NONBLOCK) {
|
||||
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_ingrant = GRANT_INVALID;
|
||||
} else {
|
||||
return; /* suspend the caller */
|
||||
tp->tty_incaller = 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_write *
|
||||
*===========================================================================*/
|
||||
static void do_write(tp, m_ptr)
|
||||
register tty_t *tp;
|
||||
register message *m_ptr; /* pointer to message sent to the task */
|
||||
static ssize_t do_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)
|
||||
{
|
||||
/* A process wants to write on a terminal. */
|
||||
tty_t *tp;
|
||||
int r;
|
||||
|
||||
if ((tp = line2tty(minor)) == NULL)
|
||||
return ENXIO;
|
||||
|
||||
/* Check if there is already a process hanging in a write, check if the
|
||||
* parameters are correct, do I/O.
|
||||
*/
|
||||
if (tp->tty_outleft > 0) {
|
||||
r = EIO;
|
||||
} else
|
||||
if (m_ptr->COUNT <= 0) {
|
||||
r = EINVAL;
|
||||
} else {
|
||||
if (tp->tty_outcaller != NONE || tp->tty_outleft > 0)
|
||||
return EIO;
|
||||
if (size <= 0)
|
||||
return EINVAL;
|
||||
|
||||
/* 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;
|
||||
tp->tty_outcaller = endpt;
|
||||
tp->tty_outid = id;
|
||||
tp->tty_outgrant = grant;
|
||||
assert(tp->tty_outcum == 0);
|
||||
tp->tty_outleft = size;
|
||||
|
||||
/* Try to write. */
|
||||
handle_events(tp);
|
||||
if (tp->tty_outleft == 0)
|
||||
return; /* already done */
|
||||
return EDONTREPLY; /* already done */
|
||||
|
||||
/* None or not all the bytes could be written. */
|
||||
if (m_ptr->FLAGS & FLG_OP_NONBLOCK) {
|
||||
if (flags & FLG_OP_NONBLOCK) {
|
||||
r = tp->tty_outcum > 0 ? tp->tty_outcum : EAGAIN;
|
||||
tp->tty_outleft = tp->tty_outcum = 0;
|
||||
tp->tty_outgrant = GRANT_INVALID;
|
||||
} else {
|
||||
return; /* suspend the caller */
|
||||
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 *
|
||||
*===========================================================================*/
|
||||
static void do_ioctl(tp, m_ptr)
|
||||
register tty_t *tp;
|
||||
message *m_ptr; /* pointer to message sent to task */
|
||||
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)
|
||||
{
|
||||
/* Perform an IOCTL on this terminal. Posix termios calls are handled
|
||||
* by the IOCTL system call
|
||||
/* Perform an IOCTL on this terminal. POSIX termios calls are handled
|
||||
* by the IOCTL system call.
|
||||
*/
|
||||
|
||||
int r;
|
||||
union {
|
||||
int i;
|
||||
} param;
|
||||
tty_t *tp;
|
||||
int i, r;
|
||||
size_t size;
|
||||
|
||||
if ((tp = line2tty(minor)) == NULL)
|
||||
return ENXIO;
|
||||
|
||||
/* Size of the ioctl parameter. */
|
||||
switch (m_ptr->REQUEST) {
|
||||
switch (request) {
|
||||
case TCGETS: /* Posix tcgetattr function */
|
||||
case TCSETS: /* Posix tcsetattr function, TCSANOW option */
|
||||
case TCSETSW: /* Posix tcsetattr function, TCSADRAIN option */
|
||||
|
@ -709,45 +666,41 @@ message *m_ptr; /* pointer to message sent to task */
|
|||
}
|
||||
|
||||
r = OK;
|
||||
switch (m_ptr->REQUEST) {
|
||||
switch (request) {
|
||||
case TCGETS:
|
||||
/* Get the termios attributes. */
|
||||
r = sys_safecopyto(m_ptr->m_source, (cp_grant_id_t) m_ptr->IO_GRANT, 0,
|
||||
(vir_bytes) &tp->tty_termios, (vir_bytes) size);
|
||||
r = sys_safecopyto(endpt, grant, 0, (vir_bytes) &tp->tty_termios,
|
||||
size);
|
||||
break;
|
||||
|
||||
case TCSETSW:
|
||||
case TCSETSF:
|
||||
case TCDRAIN:
|
||||
if (tp->tty_outleft > 0) {
|
||||
if (m_ptr->FLAGS & FLG_OP_NONBLOCK) {
|
||||
r = EAGAIN;
|
||||
} else {
|
||||
if (flags & FLG_OP_NONBLOCK)
|
||||
return EAGAIN;
|
||||
/* Wait for all ongoing output processing to finish. */
|
||||
tp->tty_iocaller = m_ptr->m_source;
|
||||
tp->tty_ioproc = m_ptr->USER_ENDPT;
|
||||
tp->tty_ioreq = m_ptr->REQUEST;
|
||||
tp->tty_iogrant = (cp_grant_id_t) m_ptr->IO_GRANT;
|
||||
return;
|
||||
tp->tty_iocaller = endpt;
|
||||
tp->tty_ioid = id;
|
||||
tp->tty_ioreq = request;
|
||||
tp->tty_iogrant = grant;
|
||||
return EDONTREPLY; /* suspend the caller */
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (m_ptr->REQUEST == TCDRAIN) break;
|
||||
if (m_ptr->REQUEST == TCSETSF) tty_icancel(tp);
|
||||
if (request == TCDRAIN) break;
|
||||
if (request == TCSETSF) tty_icancel(tp);
|
||||
/*FALL THROUGH*/
|
||||
case TCSETS:
|
||||
/* Set the termios attributes. */
|
||||
r = sys_safecopyfrom(m_ptr->m_source, (cp_grant_id_t) m_ptr->IO_GRANT,
|
||||
0, (vir_bytes) &tp->tty_termios, (vir_bytes) size);
|
||||
r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &tp->tty_termios,
|
||||
size);
|
||||
if (r != OK) break;
|
||||
setattr(tp);
|
||||
break;
|
||||
|
||||
case TCFLSH:
|
||||
r = sys_safecopyfrom(m_ptr->m_source, (cp_grant_id_t) m_ptr->IO_GRANT,
|
||||
0, (vir_bytes) ¶m.i, (vir_bytes) size);
|
||||
r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &i, size);
|
||||
if (r != OK) break;
|
||||
switch (param.i) {
|
||||
switch (i) {
|
||||
case TCIFLUSH: tty_icancel(tp); break;
|
||||
case TCOFLUSH: (*tp->tty_ocancel)(tp, 0); break;
|
||||
case TCIOFLUSH: tty_icancel(tp); (*tp->tty_ocancel)(tp, 0); break;
|
||||
|
@ -756,13 +709,12 @@ message *m_ptr; /* pointer to message sent to task */
|
|||
break;
|
||||
|
||||
case TCFLOW:
|
||||
r = sys_safecopyfrom(m_ptr->m_source, (cp_grant_id_t) m_ptr->IO_GRANT,
|
||||
0, (vir_bytes) ¶m.i, (vir_bytes) size);
|
||||
r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &i, size);
|
||||
if (r != OK) break;
|
||||
switch (param.i) {
|
||||
switch (i) {
|
||||
case TCOOFF:
|
||||
case TCOON:
|
||||
tp->tty_inhibited = (param.i == TCOOFF);
|
||||
tp->tty_inhibited = (i == TCOOFF);
|
||||
tp->tty_events = 1;
|
||||
break;
|
||||
case TCIOFF:
|
||||
|
@ -781,27 +733,24 @@ message *m_ptr; /* pointer to message sent to task */
|
|||
break;
|
||||
|
||||
case TIOCGWINSZ:
|
||||
r = sys_safecopyto(m_ptr->m_source, (cp_grant_id_t) m_ptr->IO_GRANT, 0,
|
||||
(vir_bytes) &tp->tty_winsize, (vir_bytes) size);
|
||||
r = sys_safecopyto(endpt, grant, 0, (vir_bytes) &tp->tty_winsize,
|
||||
size);
|
||||
break;
|
||||
|
||||
case TIOCSWINSZ:
|
||||
r = sys_safecopyfrom(m_ptr->m_source, (cp_grant_id_t) m_ptr->IO_GRANT,
|
||||
0, (vir_bytes) &tp->tty_winsize, (vir_bytes) size);
|
||||
r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &tp->tty_winsize,
|
||||
size);
|
||||
sigchar(tp, SIGWINCH, 0);
|
||||
break;
|
||||
|
||||
case KIOCSMAP:
|
||||
/* Load a new keymap (only /dev/console). */
|
||||
if (isconsole(tp)) r = kbd_loadmap(m_ptr);
|
||||
if (isconsole(tp)) r = kbd_loadmap(endpt, grant);
|
||||
break;
|
||||
|
||||
case TIOCSFON_OLD:
|
||||
printf("TTY: old TIOCSFON ignored.\n");
|
||||
break;
|
||||
case TIOCSFON:
|
||||
/* 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;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Send the reply. */
|
||||
tty_reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT,
|
||||
(cp_grant_id_t) m_ptr->IO_GRANT, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* do_open *
|
||||
*===========================================================================*/
|
||||
static void do_open(tp, m_ptr)
|
||||
register tty_t *tp;
|
||||
message *m_ptr; /* pointer to message sent to task */
|
||||
static int do_open(devminor_t minor, int access, endpoint_t user_endpt)
|
||||
{
|
||||
/* 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
|
||||
* the tty is made the controlling tty, otherwise OK or an error code.
|
||||
*/
|
||||
tty_t *tp;
|
||||
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. */
|
||||
if (m_ptr->COUNT & R_BIT) r = EACCES;
|
||||
if (access & R_BIT) return EACCES;
|
||||
} else {
|
||||
if (!(m_ptr->COUNT & O_NOCTTY)) {
|
||||
tp->tty_pgrp = m_ptr->USER_ENDPT;
|
||||
if (!(access & O_NOCTTY)) {
|
||||
tp->tty_pgrp = user_endpt;
|
||||
r = 1;
|
||||
}
|
||||
tp->tty_openct++;
|
||||
|
@ -845,20 +794,22 @@ message *m_ptr; /* pointer to message sent to task */
|
|||
(*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 *
|
||||
*===========================================================================*/
|
||||
static void do_close(tp, m_ptr)
|
||||
register tty_t *tp;
|
||||
message *m_ptr; /* pointer to message sent to task */
|
||||
static int do_close(devminor_t minor)
|
||||
{
|
||||
/* 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;
|
||||
tty_icancel(tp);
|
||||
(*tp->tty_ocancel)(tp, 0);
|
||||
|
@ -867,53 +818,49 @@ message *m_ptr; /* pointer to message sent to task */
|
|||
tp->tty_winsize = winsize_defaults;
|
||||
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 *
|
||||
*===========================================================================*/
|
||||
static void do_cancel(tp, m_ptr)
|
||||
register tty_t *tp;
|
||||
message *m_ptr; /* pointer to message sent to task */
|
||||
static int do_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id)
|
||||
{
|
||||
/* 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.
|
||||
*/
|
||||
endpoint_t proc_nr;
|
||||
cp_grant_id_t grant;
|
||||
int mode;
|
||||
int r = EDONTREPLY;
|
||||
tty_t *tp;
|
||||
int r;
|
||||
|
||||
if ((tp = line2tty(minor)) == NULL)
|
||||
return ENXIO;
|
||||
|
||||
/* Check the parameters carefully, to avoid cancelling twice. */
|
||||
proc_nr = m_ptr->USER_ENDPT;
|
||||
grant = (cp_grant_id_t) m_ptr->IO_GRANT;
|
||||
mode = m_ptr->COUNT;
|
||||
if ((mode & R_BIT) && tp->tty_inleft != 0 && proc_nr == tp->tty_inproc &&
|
||||
tp->tty_ingrant == grant) {
|
||||
r = EDONTREPLY;
|
||||
if (tp->tty_inleft != 0 && endpt == tp->tty_incaller && id == tp->tty_inid) {
|
||||
/* Process was reading when killed. Clean up input. */
|
||||
tty_icancel(tp);
|
||||
r = tp->tty_incum > 0 ? tp->tty_incum : EAGAIN;
|
||||
tp->tty_inleft = tp->tty_incum = 0;
|
||||
tp->tty_ingrant = GRANT_INVALID;
|
||||
}
|
||||
if ((mode & W_BIT) && tp->tty_outleft != 0 && proc_nr == tp->tty_outproc &&
|
||||
tp->tty_outgrant == grant) {
|
||||
tp->tty_incaller = NONE;
|
||||
} else if (tp->tty_outleft != 0 && endpt == tp->tty_outcaller &&
|
||||
id == tp->tty_outid) {
|
||||
/* Process was writing when killed. Clean up output. */
|
||||
r = tp->tty_outcum > 0 ? tp->tty_outcum : EAGAIN;
|
||||
tp->tty_outleft = tp->tty_outcum = 0;
|
||||
tp->tty_outgrant = GRANT_INVALID;
|
||||
}
|
||||
if (tp->tty_ioreq != 0 && proc_nr == tp->tty_ioproc) {
|
||||
tp->tty_outcaller = NONE;
|
||||
} else if (tp->tty_ioreq != 0 && endpt == tp->tty_iocaller &&
|
||||
id == tp->tty_ioid) {
|
||||
/* Process was waiting for output to drain. */
|
||||
tp->tty_ioreq = 0;
|
||||
r = EINTR;
|
||||
tp->tty_ioreq = 0;
|
||||
tp->tty_iocaller = NONE;
|
||||
}
|
||||
if (r != EDONTREPLY)
|
||||
tp->tty_events = 1;
|
||||
/* Only reply if we found a matching request. */
|
||||
if (r != EDONTREPLY)
|
||||
tty_reply(DEV_REVIVE, m_ptr->m_source, proc_nr, grant, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
int select_try(struct tty *tp, int ops)
|
||||
|
@ -955,14 +902,43 @@ int select_retry(struct tty *tp)
|
|||
int ops;
|
||||
|
||||
if (tp->tty_select_ops && (ops = select_try(tp, tp->tty_select_ops))) {
|
||||
assert(tp->tty_select_minor == tp->tty_minor);
|
||||
select_reply(DEV_SEL_REPL2, tp->tty_select_proc, tp->tty_minor,
|
||||
chardriver_reply_select(tp->tty_select_proc, tp->tty_minor,
|
||||
ops);
|
||||
tp->tty_select_ops &= ~ops;
|
||||
}
|
||||
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 *
|
||||
*===========================================================================*/
|
||||
|
@ -979,8 +955,8 @@ tty_t *tp; /* TTY to check for events. */
|
|||
* to avoid swamping the TTY task. Messages may be overwritten when the
|
||||
* lines are fast or when there are races between different lines, input
|
||||
* and output, because MINIX only provides single buffering for interrupt
|
||||
* messages (in proc.c). This is handled by explicitly checking each line
|
||||
* for fresh input and completed output on each interrupt.
|
||||
* messages. This is handled by explicitly checking each line for fresh input
|
||||
* and completed output on each interrupt.
|
||||
*/
|
||||
|
||||
do {
|
||||
|
@ -1001,10 +977,9 @@ tty_t *tp; /* TTY to check for events. */
|
|||
|
||||
/* Reply if enough bytes are available. */
|
||||
if (tp->tty_incum >= tp->tty_min && tp->tty_inleft > 0) {
|
||||
tty_reply(DEV_REVIVE, tp->tty_incaller, tp->tty_inproc,
|
||||
tp->tty_ingrant, tp->tty_incum);
|
||||
chardriver_reply_task(tp->tty_incaller, tp->tty_inid, tp->tty_incum);
|
||||
tp->tty_inleft = tp->tty_incum = 0;
|
||||
tp->tty_ingrant = GRANT_INVALID;
|
||||
tp->tty_incaller = NONE;
|
||||
}
|
||||
if (tp->tty_select_ops)
|
||||
{
|
||||
|
@ -1045,10 +1020,8 @@ register tty_t *tp; /* pointer to terminal to read from */
|
|||
if (++bp == bufend(buf)) {
|
||||
/* Temp buffer full, copy to user space. */
|
||||
sys_safecopyto(tp->tty_incaller,
|
||||
tp->tty_ingrant, tp->tty_inoffset,
|
||||
(vir_bytes) buf,
|
||||
(vir_bytes) buflen(buf));
|
||||
tp->tty_inoffset += buflen(buf);
|
||||
tp->tty_ingrant, tp->tty_incum,
|
||||
(vir_bytes) buf, (vir_bytes) buflen(buf));
|
||||
tp->tty_incum += buflen(buf);
|
||||
bp = buf;
|
||||
}
|
||||
|
@ -1068,19 +1041,16 @@ register tty_t *tp; /* pointer to terminal to read from */
|
|||
if (bp > buf) {
|
||||
/* Leftover characters in the buffer. */
|
||||
count = bp - buf;
|
||||
sys_safecopyto(tp->tty_incaller,
|
||||
tp->tty_ingrant, tp->tty_inoffset,
|
||||
sys_safecopyto(tp->tty_incaller, tp->tty_ingrant, tp->tty_incum,
|
||||
(vir_bytes) buf, (vir_bytes) count);
|
||||
tp->tty_inoffset += count;
|
||||
tp->tty_incum += count;
|
||||
}
|
||||
|
||||
/* Usually reply to the reader, possibly even if incum == 0 (EOF). */
|
||||
if (tp->tty_inleft == 0) {
|
||||
tty_reply(DEV_REVIVE, tp->tty_incaller, tp->tty_inproc,
|
||||
tp->tty_ingrant, tp->tty_incum);
|
||||
chardriver_reply_task(tp->tty_incaller, tp->tty_inid, tp->tty_incum);
|
||||
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);
|
||||
}
|
||||
tp->tty_ioreq = 0;
|
||||
tty_reply(DEV_REVIVE, tp->tty_iocaller, tp->tty_ioproc, tp->tty_iogrant,
|
||||
result);
|
||||
tp->tty_iogrant = GRANT_INVALID;
|
||||
chardriver_reply_task(tp->tty_iocaller, tp->tty_ioid, result);
|
||||
tp->tty_iocaller = NONE;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
@ -1571,57 +1540,6 @@ tty_t *tp;
|
|||
(*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 *
|
||||
*===========================================================================*/
|
||||
|
@ -1696,7 +1614,7 @@ static void tty_init()
|
|||
|
||||
tp->tty_intail = tp->tty_inhead = tp->tty_inbuf;
|
||||
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_icancel = tp->tty_ocancel = tp->tty_ioctl = tp->tty_close =
|
||||
tp->tty_open = tty_devnop;
|
||||
|
@ -1750,27 +1668,3 @@ int enable; /* set timer if true, otherwise unset */
|
|||
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 */
|
||||
|
||||
#include <minix/chardriver.h>
|
||||
#include <timers.h>
|
||||
|
||||
#undef lock
|
||||
|
@ -34,7 +35,7 @@ typedef void(*devfunarg_t) (struct tty *tp, int c);
|
|||
typedef struct tty {
|
||||
int tty_events; /* set when TTY should inspect this line */
|
||||
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. */
|
||||
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 */
|
||||
|
||||
/* Information about incomplete I/O requests is stored here. */
|
||||
endpoint_t tty_incaller; /* process that made the call (usually VFS) */
|
||||
endpoint_t tty_inproc; /* process that wants to read from tty */
|
||||
endpoint_t tty_incaller; /* process that made the call, or NONE */
|
||||
cdev_id_t tty_inid; /* ID of suspended read request */
|
||||
cp_grant_id_t tty_ingrant; /* grant where data is to go */
|
||||
vir_bytes tty_inoffset; /* offset into grant */
|
||||
int tty_inleft; /* how many chars are still needed */
|
||||
int tty_incum; /* # chars input so far */
|
||||
endpoint_t tty_outcaller; /* process that made the call (usually VFS) */
|
||||
endpoint_t tty_outproc; /* process that wants to write to tty */
|
||||
size_t tty_inleft; /* how many chars are still needed */
|
||||
size_t tty_incum; /* # chars input so far */
|
||||
endpoint_t tty_outcaller; /* process that made the call, or NONE */
|
||||
cdev_id_t tty_outid; /* ID of suspended write request */
|
||||
cp_grant_id_t tty_outgrant; /* grant where data comes from */
|
||||
vir_bytes tty_outoffset; /* offset into grant */
|
||||
int tty_outleft; /* # chars yet to be output */
|
||||
int tty_outcum; /* # chars output so far */
|
||||
endpoint_t tty_iocaller; /* process that made the call (usually VFS) */
|
||||
endpoint_t tty_ioproc; /* process that wants to do an ioctl */
|
||||
int tty_ioreq; /* ioctl request code */
|
||||
size_t tty_outleft; /* # chars yet to be output */
|
||||
size_t tty_outcum; /* # chars output so far */
|
||||
endpoint_t tty_iocaller; /* process that made the call, or NONE */
|
||||
cdev_id_t tty_ioid; /* ID of suspended ioctl request */
|
||||
unsigned int tty_ioreq; /* ioctl request code */
|
||||
cp_grant_id_t tty_iogrant; /* virtual address of ioctl buffer or grant */
|
||||
|
||||
/* select() data */
|
||||
int tty_select_ops; /* which operations are interesting */
|
||||
endpoint_t tty_select_proc; /* which process wants notification */
|
||||
dev_t tty_select_minor; /* sanity check only, can be removed */
|
||||
|
||||
/* Miscellaneous. */
|
||||
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 sigchar(struct tty *tp, int sig, int mayflush);
|
||||
void tty_task(void);
|
||||
tty_t *line2tty(devminor_t minor);
|
||||
int in_process(struct tty *tp, char *buf, int count, int scode);
|
||||
void out_process(struct tty *tp, char *bstart, char *bpos, char *bend,
|
||||
int *icount, int *ocount);
|
||||
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_retry(struct tty *tp);
|
||||
|
||||
|
@ -155,22 +150,21 @@ void kputc(int c);
|
|||
void cons_stop(void);
|
||||
void scr_init(struct tty *tp);
|
||||
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 beep_x( unsigned freq, clock_t dur);
|
||||
void do_video(message *m);
|
||||
void do_video(message *m, int ipc_status);
|
||||
|
||||
/* keyboard.c */
|
||||
void kb_init(struct tty *tp);
|
||||
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 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_kbdaux(message *m);
|
||||
|
||||
/* 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 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 \
|
||||
sound.h spin.h sys_config.h sysinfo.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 \
|
||||
vfsif.h vtreefs.h libminixfs.h netsock.h \
|
||||
virtio.h
|
||||
|
|
|
@ -1275,7 +1275,6 @@
|
|||
|
||||
|
||||
#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_MAP 10 /* observe 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 TIOCGPGRP _IOW('T', 18, int)
|
||||
#define TIOCSPGRP _IOW('T', 19, int)
|
||||
#define TIOCSFON_OLD _IOW('T', 20, u8_t [8192])
|
||||
#define TIOCSFON _IOW_BIG(1, u8_t [8192])
|
||||
|
||||
/* Keyboard ioctls. */
|
||||
|
|
Loading…
Reference in a new issue