Coherent4.2.10/i386/tioc.c
/* $Header: /ker/i386/RCS/tioc.c,v 2.5 93/10/29 00:57:26 nigel Exp Locker: nigel $ */
/*
* Convert COH286 tty ioctl's to Sys 5 compatible calls.
*
* $Log: tioc.c,v $
* Revision 2.5 93/10/29 00:57:26 nigel
* R98 (aka 4.2 Beta) prior to removing System Global memory
*
* Revision 2.4 93/08/19 10:38:10 nigel
* r83 ioctl (), corefile, new headers
*
* Revision 2.3 93/08/19 03:40:16 nigel
* Nigel's R83
*/
#include <sys/types.h>
#include <sys/errno.h>
#include <sgtty.h>
#define _KERNEL 1
#include <sys/mmu.h>
#define OIOC_LOW 0100
#define OIOC_HIGH 0110
/*
* Bits from COH286 sgttyb sg_flags field.
*/
#define O_EVENP 0x0001 /* Allow even parity */
#define O_ODDP 0x0002 /* Allow odd parity */
#define O_CRMOD 0x0004 /* Map '\r' to '\n' */
#define O_ECHO 0x0008 /* Echo input characters */
#define O_LCASE 0x0010 /* Lowercase mapping on input */
#define O_CBREAK 0x0020 /* Each input character causes wakeup */
#define O_RAWIN 0x0040 /* 8-bit input raw */
#define O_RAWOUT 0x0080 /* 8-bit output raw */
#define O_TANDEM 0x0100 /* flow control protocol */
#define O_XTABS 0x0200 /* Expand tabs to spaces */
#define O_CRT 0x0400 /* CRT character erase */
#define O_RAW (O_RAWIN|O_RAWOUT) /* Raw mode */
/*
* Names for terminal speeds.
*/
#define O_B0 0 /* Hangup if modem control enabled */
#define O_B50 1 /* 50 bps */
#define O_B75 2 /* 75 bps */
#define O_B110 3 /* 110 bps */
#define O_B134 4 /* 134.5 bps (IBM 2741) */
#define O_B150 5 /* 150 bps */
#define O_B200 6 /* 200 bps */
#define O_B300 7 /* 300 bps */
#define O_B600 8 /* 600 bps */
#define O_B1200 9 /* 1200 bps */
#define O_B1800 10 /* 1800 bps */
#define O_B2000 11 /* 2000 bps */
#define O_B2400 12 /* 2400 bps */
#define O_B3600 13 /* 3600 bps */
#define O_B4800 14 /* 4800 bps */
#define O_B7200 15 /* 7200 bps */
#define O_B9600 16 /* 9600 bps */
#define O_B19200 17 /* 19200 bps */
#define O_EXTA 18 /* External A (DH-11) */
#define O_EXTB 19 /* External B (DH-11) */
static void to_s5_sgfld();
static void to_s5speed();
static void to_coh_sgfld();
static void to_cohspeed();
/*
* Here are the COH286 values for tty ioctl's.
* In cvtsgtty[] below, subtract 0100 from the 286 COH ioctl value to
* index to the equivalent Sys V ioctl.
*
* OIOCSETP 0100 Terminal set modes (old stty)
* OIOCGETP 0101 Terminal get modes (old gtty)
* OIOCSETC 0102 Set characters
* OIOCGETC 0103 Get characters
* OIOCSETN 0104 Set modes w/o delay or out flush
* OIOCEXCL 0105 Set exclusive use
* OIOCNXCL 0106 Set non-exclusive use
* OIOCHPCL 0107 Hang up on last close
* OIOCFLUSH 0110 Flush characters in I/O queues
*/
static unsigned short cvtsgtty[] = {
TIOCSETP,
TIOCGETP,
TIOCSETC,
TIOCGETC,
TIOCSETN,
TIOCEXCL,
TIOCNXCL,
TIOCHPCL,
TIOCFLUSH
};
/*
* tioc()
*
* This function is called by dioctl() whenever a 286 binary does an ioctl().
* Its arguments are the arguments for to the ioctl, plus the local driver's
* ioctl function, which should support S5 sgtty and termio commands.
*
* 1. If com is COH 286 TIOC, translate it to S5 TIOC.
* 2. If translated com is TIOCSET[NP], convert sgttyb struct *vec to S5.
* 3. If translated com is TIOCGETP, point vec to a full S5 struct (COH 286
* sgttyb struct is 2 bytes shorter than S5 format).
* 4. Call driver's ioctl().
* 5. If just finished a converted TIOCGETP, convert back to COH 286 sgttyb.
*/
int
tioc (dev, com, vec, mode, credp, rvalp, iocfn)
int dev, com, mode, credp, rvalp, (*iocfn)();
caddr_t vec;
{
struct sgttyb sg;
int my_com = com, old_getp = 0;
caddr_t my_vec = vec;
int space;
if (com >= OIOC_LOW && com <= OIOC_HIGH && get_user_error () == 0) {
my_com = cvtsgtty [com - OIOC_LOW];
if (my_com == TIOCSETP || my_com == TIOCSETN) {
ukcopy (vec, & sg, sizeof (struct sgttyb));
sg.sg_flags &= 0xffff;
to_s5_sgfld (& sg);
my_vec = (caddr_t) & sg;
}
if (my_com == TIOCGETP) {
old_getp = 1;
my_vec = (caddr_t) & sg;
}
}
/*
* NIGEL: I have tightened up the segment limits so that kucopy ()
* and ukcopy () no longer accept kernel addresses as user addresses;
* in this case, we really do want this to happen, so we use
* setspace () to allow access to kernel data space as user space.
*/
if (my_vec != vec)
space = setspace (SEL_386_KD);
(* iocfn) (dev, my_com, my_vec, mode, credp, rvalp);
if (my_vec != vec)
(void) setspace (space);
if (old_getp && get_user_error () == 0) {
to_coh_sgfld (my_vec);
kucopy (my_vec, vec, sizeof (struct sgttyb) - 2);
}
return 0;
}
/*
* to_s5_sgfld()
*
* Convert fields in a sgttyb struct from COH 286 format to Sys 5.
*/
static void to_s5_sgfld(sgp)
struct sgttyb * sgp;
{
unsigned int f = sgp->sg_flags, g = 0;
/*
* Convert sg_ispeed and sg_ospeed.
*/
to_s5speed (& sgp->sg_ispeed);
to_s5speed (& sgp->sg_ospeed);
/*
* Convert sg_flags.
* f is old COH 286 flags.
* g is new Sys V flags.
*/
if (f & O_EVENP)
g |= EVENP;
if (f & O_ODDP)
g |= ODDP;
if (f & O_CRMOD)
g |= CRMOD;
if (f & O_ECHO)
g |= ECHO;
if (f & O_LCASE)
g |= LCASE;
if (f & O_CBREAK)
g |= CBREAK; /* No CBREAK in Sys 5 sgtty. */
/* Only one RAW bit in Sys 5 sgtty. */
if ((f & O_RAWIN) != 0 && (f & O_RAWOUT) != 0)
g |= RAW;
if (f & O_RAWIN)
g |= RAWIN;
if (f & O_RAWOUT)
g |= RAWOUT;
if (f & O_TANDEM)
g |= TANDEM; /* No TANDEM in Sys 5 sgtty. */
if (f & O_XTABS)
g |= XTABS;
if (f & O_CRT)
g |= CRT; /* No CRT in Sys 5 sgtty. */
sgp->sg_flags = g;
}
/*
* to_s5speed()
*
* Convert speed from COH286 to Sys5.
* Here are the numbers:
* const. COH286 Sys5
* B0 0 0
* B50 1 1
* B75 2 2
* B110 3 3
* B134 4 4
* B150 5 5
* B200 6 6
* B300 7 7
* B600 8 8
* B1200 9 9
* B1800 10 10
* B2000 11 -
* B2400 12 11
* B3600 13 -
* B4800 14 12
* B7200 15 -
* B9600 16 13
* B19200 17 14
* EXTA 18 14
* EXTB 19 15
*/
#define BADSPD 99
static void to_s5speed(speed)
unsigned char *speed;
{
static char s5sp[]={B0,B50,B75,B110,B134,B150,B200,B300,B600,B1200,
B1800,BADSPD,B2400,BADSPD,B4800,BADSPD,B9600,EXTA,EXTA,EXTB};
if (* speed >= sizeof (s5sp))
set_user_error (EINVAL);
else if (s5sp [* speed] == BADSPD)
set_user_error (EINVAL);
else
* speed = s5sp [* speed];
}
/*
* to_coh_sgfld()
*
* Convert fields in a sgttyb struct from Sys V format to COH 286.
*/
static void to_coh_sgfld(sgp)
struct sgttyb * sgp;
{
unsigned int f = sgp->sg_flags, g = 0;
/*
* Convert sg_ispeed and sg_ospeed.
*/
to_cohspeed (& sgp->sg_ispeed);
to_cohspeed (& sgp->sg_ospeed);
/*
* Convert sg_flags.
* f is old Sys V flags.
* g is new COH 286 flags.
*/
if (f & EVENP)
g |= O_EVENP;
if (f & ODDP)
g |= O_ODDP;
if (f & CRMOD)
g |= O_CRMOD;
if (f & ECHO)
g |= O_ECHO;
if (f & LCASE)
g |= O_LCASE;
if (f & CBREAK)
g |= O_CBREAK; /* No CBREAK in Sys 5 sgtty. */
if (f & RAWIN) /* Only one RAW bit in Sys 5 sgtty. */
g |= O_RAWIN;
if (f & RAWOUT)
g |= O_RAWOUT;
if (f & TANDEM)
g |= O_TANDEM; /* No TANDEM in Sys 5 sgtty. */
if (f & XTABS)
g |= O_XTABS;
if (f & CRT)
g |= O_CRT; /* No CRT in Sys 5 sgtty. */
sgp->sg_flags = g;
}
static void to_cohspeed(speed)
unsigned char *speed;
{
static char cohsp[]={
O_B0, O_B50, O_B75, O_B110, O_B134, O_B150, O_B200,
O_B300, O_B600, O_B1200, O_B1800, O_B2400, O_B4800,
O_B9600, O_EXTA, O_EXTB
};
if (* speed >= sizeof (cohsp))
set_user_error (EINVAL);
else
* speed = cohsp [* speed];
}