Integrate the new MPSAFE TTY layer to the FreeBSD operating system.
The last half year I've been working on a replacement TTY layer for the FreeBSD kernel. The new TTY layer was designed to improve the following: - Improved driver model: The old TTY layer has a driver model that is not abstract enough to make it friendly to use. A good example is the output path, where the device drivers directly access the output buffers. This means that an in-kernel PPP implementation must always convert network buffers into TTY buffers. If a PPP implementation would be built on top of the new TTY layer (still needs a hooks layer, though), it would allow the PPP implementation to directly hand the data to the TTY driver. - Improved hotplugging: With the old TTY layer, it isn't entirely safe to destroy TTY's from the system. This implementation has a two-step destructing design, where the driver first abandons the TTY. After all threads have left the TTY, the TTY layer calls a routine in the driver, which can be used to free resources (unit numbers, etc). The pts(4) driver also implements this feature, which means posix_openpt() will now return PTY's that are created on the fly. - Improved performance: One of the major improvements is the per-TTY mutex, which is expected to improve scalability when compared to the old Giant locking. Another change is the unbuffered copying to userspace, which is both used on TTY device nodes and PTY masters. Upgrading should be quite straightforward. Unlike previous versions, existing kernel configuration files do not need to be changed, except when they reference device drivers that are listed in UPDATING. Obtained from: //depot/projects/mpsafetty/... Approved by: philip (ex-mentor) Discussed: on the lists, at BSDCan, at the DevSummit Sponsored by: Snow B.V., the Netherlands dcons(4) fixed by: kan
This commit is contained in:
parent
b49301b5cd
commit
cc3116a938
@ -14,6 +14,9 @@
|
||||
# The file is partitioned: OLD_FILES first, then OLD_LIBS and OLD_DIRS last.
|
||||
#
|
||||
|
||||
# 20080820: MPSAFE TTY layer integrated
|
||||
OLD_FILES+=usr/include/sys/linedisc.h
|
||||
OLD_FILES+=usr/share/man/man3/posix_openpt.3.gz
|
||||
# 20080725: sgtty.h removed
|
||||
OLD_FILES+=usr/include/sgtty.h
|
||||
# 20080719: sade(8) removed on all but amd64, i386 and sparc64
|
||||
|
19
UPDATING
19
UPDATING
@ -22,6 +22,25 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 8.x IS SLOW:
|
||||
to maximize performance. (To disable malloc debugging, run
|
||||
ln -s aj /etc/malloc.conf.)
|
||||
|
||||
20080820:
|
||||
The TTY subsystem of the kernel has been replaced by a new
|
||||
implementation, which provides better scalability and an
|
||||
improved driver model. Most common drivers have been migrated to
|
||||
the new TTY subsystem, while others have not. The following
|
||||
drivers have not yet been ported to the new TTY layer:
|
||||
|
||||
PCI/ISA:
|
||||
cy, digi, rc, rp, si, sio
|
||||
|
||||
USB:
|
||||
ubser, ucycom, ufoma
|
||||
|
||||
Line disciplines:
|
||||
ng_h4, ng_tty, ppp, sl, snp
|
||||
|
||||
Adding these drivers to your kernel configuration file shall
|
||||
cause compilation to fail.
|
||||
|
||||
20080713:
|
||||
The sio(4) driver has been removed from the i386 and amd64
|
||||
kernel configuration files. This means uart(4) is now the
|
||||
|
@ -341,6 +341,9 @@ static const struct limits limits[] = {
|
||||
#endif
|
||||
#ifdef RLIMIT_SBSIZE
|
||||
{ "sbsize", "bytes", RLIMIT_SBSIZE, 1, 'b' },
|
||||
#endif
|
||||
#ifdef RLIMIT_NPTS
|
||||
{ "pseudo-terminals", (char *)0, RLIMIT_NPTS, 1, 'p' },
|
||||
#endif
|
||||
{ (char *) 0, (char *)0, 0, 0, '\0' }
|
||||
};
|
||||
@ -358,7 +361,7 @@ ulimitcmd(int argc __unused, char **argv __unused)
|
||||
struct rlimit limit;
|
||||
|
||||
what = 'f';
|
||||
while ((optc = nextopt("HSatfdsmcnuvlb")) != '\0')
|
||||
while ((optc = nextopt("HSatfdsmcnuvlbp")) != '\0')
|
||||
switch (optc) {
|
||||
case 'H':
|
||||
how = HARD;
|
||||
|
@ -52,8 +52,9 @@ add path 'ttyP*' unhide
|
||||
add path 'ttyQ*' unhide
|
||||
add path 'ttyR*' unhide
|
||||
add path 'ttyS*' unhide
|
||||
add path ptmx unhide
|
||||
add path pts unhide
|
||||
add path 'pts/*' unhide
|
||||
add path 'pty/*' unhide
|
||||
add path fd unhide
|
||||
add path 'fd/*' unhide
|
||||
add path stdin unhide
|
||||
|
@ -40,6 +40,7 @@ default:\
|
||||
:maxproc=unlimited:\
|
||||
:sbsize=unlimited:\
|
||||
:vmemoryuse=unlimited:\
|
||||
:pseudoterminals=unlimited:\
|
||||
:priority=0:\
|
||||
:ignoretime@:\
|
||||
:umask=022:
|
||||
|
@ -6,9 +6,9 @@
|
||||
|
||||
MISRCS+=_Exit.c a64l.c abort.c abs.c atexit.c atof.c atoi.c atol.c atoll.c \
|
||||
bsearch.c div.c exit.c getenv.c getopt.c getopt_long.c \
|
||||
getsubopt.c grantpt.c hcreate.c heapsort.c imaxabs.c imaxdiv.c \
|
||||
getsubopt.c hcreate.c heapsort.c imaxabs.c imaxdiv.c \
|
||||
insque.c l64a.c labs.c ldiv.c llabs.c lldiv.c lsearch.c malloc.c \
|
||||
merge.c qsort.c qsort_r.c radixsort.c rand.c random.c \
|
||||
merge.c ptsname.c qsort.c qsort_r.c radixsort.c rand.c random.c \
|
||||
reallocf.c realpath.c remque.c strfmon.c strtoimax.c \
|
||||
strtol.c strtoll.c strtoq.c strtoul.c strtonum.c strtoull.c \
|
||||
strtoumax.c strtouq.c system.c tdelete.c tfind.c tsearch.c twalk.c
|
||||
@ -21,10 +21,10 @@ SYM_MAPS+= ${.CURDIR}/stdlib/Symbol.map
|
||||
.endif
|
||||
|
||||
MAN+= a64l.3 abort.3 abs.3 alloca.3 atexit.3 atof.3 atoi.3 atol.3 bsearch.3 \
|
||||
div.3 exit.3 getenv.3 getopt.3 getopt_long.3 getsubopt.3 grantpt.3 \
|
||||
div.3 exit.3 getenv.3 getopt.3 getopt_long.3 getsubopt.3 \
|
||||
hcreate.3 imaxabs.3 imaxdiv.3 insque.3 labs.3 ldiv.3 llabs.3 lldiv.3 \
|
||||
lsearch.3 malloc.3 memory.3 posix_memalign.3 qsort.3 radixsort.3 \
|
||||
rand.3 random.3 \
|
||||
lsearch.3 malloc.3 memory.3 posix_memalign.3 ptsname.3 qsort.3 \
|
||||
radixsort.3 rand.3 random.3 \
|
||||
realpath.3 strfmon.3 strtod.3 strtol.3 strtonum.3 strtoul.3 system.3 \
|
||||
tsearch.3
|
||||
|
||||
@ -33,10 +33,10 @@ MLINKS+=atol.3 atoll.3
|
||||
MLINKS+=exit.3 _Exit.3
|
||||
MLINKS+=getenv.3 putenv.3 getenv.3 setenv.3 getenv.3 unsetenv.3
|
||||
MLINKS+=getopt_long.3 getopt_long_only.3
|
||||
MLINKS+=grantpt.3 posix_openpt.3 grantpt.3 ptsname.3 grantpt.3 unlockpt.3
|
||||
MLINKS+=hcreate.3 hdestroy.3 hcreate.3 hsearch.3
|
||||
MLINKS+=insque.3 remque.3
|
||||
MLINKS+=lsearch.3 lfind.3
|
||||
MLINKS+=ptsname.3 grantpt.3 ptsname.3 unlockpt.3
|
||||
MLINKS+=qsort.3 heapsort.3 qsort.3 mergesort.3 qsort.3 qsort_r.3
|
||||
MLINKS+=rand.3 rand_r.3 rand.3 srand.3 rand.3 sranddev.3
|
||||
MLINKS+=random.3 initstate.3 random.3 setstate.3 random.3 srandom.3 \
|
||||
|
@ -30,7 +30,6 @@ FBSD_1.0 {
|
||||
suboptarg;
|
||||
getsubopt;
|
||||
grantpt;
|
||||
posix_openpt;
|
||||
ptsname;
|
||||
unlockpt;
|
||||
hcreate;
|
||||
|
@ -31,14 +31,13 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd December 23, 2002
|
||||
.Dd August 20, 2008
|
||||
.Os
|
||||
.Dt GRANTPT 3
|
||||
.Dt PTSNAME 3
|
||||
.Sh NAME
|
||||
.Nm grantpt ,
|
||||
.Nm ptsname ,
|
||||
.Nm unlockpt ,
|
||||
.Nm posix_openpt
|
||||
.Nm unlockpt
|
||||
.Nd pseudo-terminal access functions
|
||||
.Sh LIBRARY
|
||||
.Lb libc
|
||||
@ -50,21 +49,17 @@
|
||||
.Fn ptsname "int fildes"
|
||||
.Ft int
|
||||
.Fn unlockpt "int fildes"
|
||||
.In fcntl.h
|
||||
.Ft int
|
||||
.Fn posix_openpt "int mode"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Fn grantpt ,
|
||||
.Fn ptsname ,
|
||||
.Fn unlockpt ,
|
||||
and
|
||||
.Fn posix_openpt
|
||||
.Fn unlockpt
|
||||
functions allow access to pseudo-terminal devices.
|
||||
The first three functions accept a file descriptor
|
||||
that references the master half of a pseudo-terminal pair.
|
||||
These three functions accept a file descriptor that references the
|
||||
master half of a pseudo-terminal pair.
|
||||
This file descriptor is created with
|
||||
.Fn posix_openpt .
|
||||
.Xr posix_openpt 2 .
|
||||
.Pp
|
||||
The
|
||||
.Fn grantpt
|
||||
@ -77,9 +72,7 @@ of the calling process, and the permissions are set to
|
||||
user readable-writable and group writable.
|
||||
The group owner of the slave device is also set to the
|
||||
group
|
||||
.Dq Li tty
|
||||
if it exists on the system; otherwise, it
|
||||
is left untouched.
|
||||
.Dq Li tty .
|
||||
.Pp
|
||||
The
|
||||
.Fn ptsname
|
||||
@ -88,7 +81,7 @@ counterpart to the master device specified with
|
||||
.Fa fildes .
|
||||
This value can be used
|
||||
to subsequently open the appropriate slave after
|
||||
.Fn posix_openpt
|
||||
.Xr posix_openpt 2
|
||||
and
|
||||
.Fn grantpt
|
||||
have been called.
|
||||
@ -98,22 +91,6 @@ The
|
||||
function clears the lock held on the pseudo-terminal pair
|
||||
for the master device specified with
|
||||
.Fa fildes .
|
||||
.Pp
|
||||
The
|
||||
.Fn posix_openpt
|
||||
function opens the first available master pseudo-terminal
|
||||
device and returns a descriptor to it.
|
||||
The
|
||||
.Fa mode
|
||||
argument
|
||||
specifies the flags used for opening the device:
|
||||
.Bl -tag -width ".Dv O_NOCTTY"
|
||||
.It Dv O_RDWR
|
||||
Open for reading and writing.
|
||||
.It Dv O_NOCTTY
|
||||
If set, do not allow the terminal to become
|
||||
the controlling terminal for the calling process.
|
||||
.El
|
||||
.Sh RETURN VALUES
|
||||
.Rv -std grantpt unlockpt
|
||||
.Pp
|
||||
@ -122,27 +99,19 @@ The
|
||||
function returns a pointer to the name
|
||||
of the slave device on success; otherwise a
|
||||
.Dv NULL
|
||||
pointer is returned and the global variable
|
||||
.Va errno
|
||||
is set to indicate the error.
|
||||
.Pp
|
||||
The
|
||||
.Fn posix_openpt
|
||||
function returns a file descriptor to the first
|
||||
available master pseudo-terminal device on success;
|
||||
otherwise \-1 is returned and the global variable
|
||||
.Va errno
|
||||
is set to indicate the error.
|
||||
pointer is returned.
|
||||
.Sh ERRORS
|
||||
The
|
||||
.Fn grantpt ,
|
||||
.Fn ptsname ,
|
||||
.Fn grantpt
|
||||
and
|
||||
.Fn unlockpt
|
||||
functions may fail and set
|
||||
.Va errno
|
||||
to:
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er EBADF
|
||||
.Fa fildes
|
||||
is not a valid open file descriptor.
|
||||
.It Bq Er EINVAL
|
||||
.Fa fildes
|
||||
is not a master pseudo-terminal device.
|
||||
@ -157,69 +126,35 @@ to:
|
||||
.It Bq Er EACCES
|
||||
The slave pseudo-terminal device could not be accessed.
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Fn posix_openpt
|
||||
function may fail and set
|
||||
.Va errno
|
||||
to:
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er EINVAL
|
||||
.Fa mode
|
||||
consists of an invalid mode bit.
|
||||
.It Bq Er EAGAIN
|
||||
The system has no available pseudo-terminal devices.
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Fn grantpt ,
|
||||
.Fn ptsname ,
|
||||
and
|
||||
.Fn unlockpt
|
||||
functions may also fail and set
|
||||
.Va errno
|
||||
for any of the errors specified for the
|
||||
.Xr fstat 2
|
||||
system call.
|
||||
.Pp
|
||||
The
|
||||
.Fn posix_openpt
|
||||
function may also fail and set
|
||||
.Va errno
|
||||
for any of the errors specified for the
|
||||
.Xr open 2
|
||||
system call.
|
||||
.Sh SEE ALSO
|
||||
.Xr open 2 ,
|
||||
.Xr pty 4 ,
|
||||
.Xr posix_openpt 2 ,
|
||||
.Xr pts 4 ,
|
||||
.Xr tty 4
|
||||
.Sh STANDARDS
|
||||
The
|
||||
.Fn grantpt ,
|
||||
.Fn ptsname ,
|
||||
.Fn unlockpt ,
|
||||
.Fn ptsname
|
||||
and
|
||||
.Fn posix_openpt
|
||||
.Fn unlockpt
|
||||
functions conform to
|
||||
.St -p1003.1-2001 .
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Fn grantpt ,
|
||||
.Fn ptsname ,
|
||||
.Fn unlockpt ,
|
||||
.Fn ptsname
|
||||
and
|
||||
.Fn posix_openpt
|
||||
.Fn unlockpt
|
||||
functions appeared in
|
||||
.Fx 5.0 .
|
||||
.Sh NOTES
|
||||
The purpose of the
|
||||
.Fn grantpt
|
||||
and
|
||||
.Fn unlockpt
|
||||
function has no meaning in
|
||||
.Fx .
|
||||
.Pp
|
||||
The flag
|
||||
.Dv O_NOCTTY
|
||||
is included for compatibility; in
|
||||
functions has no meaning in
|
||||
.Fx ,
|
||||
opening a terminal does not cause it to become
|
||||
a process's controlling terminal.
|
||||
because pseudo-terminals obtained by
|
||||
.Xr posix_openpt 2
|
||||
are created on demand.
|
||||
Because these devices are created with proper permissions in place, they
|
||||
are guaranteed to be unused by unprivileged processes.
|
95
lib/libc/stdlib/ptsname.c
Normal file
95
lib/libc/stdlib/ptsname.c
Normal file
@ -0,0 +1,95 @@
|
||||
/*-
|
||||
* Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions of this software were developed under sponsorship from Snow
|
||||
* B.V., the Netherlands.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__FBSDID("$FreeBSD$");
|
||||
#endif /* not lint */
|
||||
|
||||
#include "namespace.h"
|
||||
#include <sys/param.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <paths.h>
|
||||
#include "un-namespace.h"
|
||||
|
||||
/*
|
||||
* __isptmaster(): return whether the file descriptor refers to a
|
||||
* pseudo-terminal master device.
|
||||
*/
|
||||
static int
|
||||
__isptmaster(int fildes)
|
||||
{
|
||||
|
||||
if (_ioctl(fildes, TIOCPTMASTER) == 0)
|
||||
return (0);
|
||||
|
||||
if (errno != EBADF)
|
||||
errno = EINVAL;
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* In our implementation, grantpt() and unlockpt() don't actually have
|
||||
* any use, because PTY's are created on the fly and already have proper
|
||||
* permissions upon creation.
|
||||
*
|
||||
* Just make sure `fildes' actually points to a real PTY master device.
|
||||
*/
|
||||
__strong_reference(__isptmaster, grantpt);
|
||||
__strong_reference(__isptmaster, unlockpt);
|
||||
|
||||
/*
|
||||
* ptsname(): return the pathname of the slave pseudo-terminal device
|
||||
* associated with the specified master.
|
||||
*/
|
||||
char *
|
||||
ptsname(int fildes)
|
||||
{
|
||||
static char pt_slave[sizeof _PATH_DEV + SPECNAMELEN] = _PATH_DEV;
|
||||
struct fiodgname_arg fgn;
|
||||
char *ret = NULL;
|
||||
int sverrno = errno;
|
||||
|
||||
/* Make sure fildes points to a master device. */
|
||||
if (__isptmaster(fildes) != 0)
|
||||
goto done;
|
||||
|
||||
/* Obtain the device name through FIODGNAME. */
|
||||
fgn.len = sizeof pt_slave - (sizeof _PATH_DEV - 1);
|
||||
fgn.buf = pt_slave + (sizeof _PATH_DEV - 1);
|
||||
if (_ioctl(fildes, FIODGNAME, &fgn) == 0)
|
||||
ret = pt_slave;
|
||||
|
||||
done: /* Make sure ptsname() does not overwrite errno. */
|
||||
errno = sverrno;
|
||||
return (ret);
|
||||
}
|
@ -79,8 +79,8 @@ MAN+= abort2.2 accept.2 access.2 acct.2 adjtime.2 \
|
||||
mlockall.2 mmap.2 modfind.2 modnext.2 modstat.2 mount.2 mprotect.2 \
|
||||
mq_close.2 mq_getattr.2 mq_notify.2 mq_open.2 mq_receive.2 mq_send.2 \
|
||||
mq_setattr.2 \
|
||||
msync.2 munmap.2 nanosleep.2 nfssvc.2 ntp_adjtime.2 \
|
||||
open.2 pathconf.2 pipe.2 poll.2 profil.2 ptrace.2 quotactl.2 \
|
||||
msync.2 munmap.2 nanosleep.2 nfssvc.2 ntp_adjtime.2 open.2 \
|
||||
pathconf.2 pipe.2 poll.2 posix_openpt.2 profil.2 ptrace.2 quotactl.2 \
|
||||
read.2 readlink.2 reboot.2 recv.2 rename.2 revoke.2 rfork.2 rmdir.2 \
|
||||
rtprio.2
|
||||
.if !defined(NO_P1003_1B)
|
||||
|
@ -211,6 +211,7 @@ FBSD_1.0 {
|
||||
pathconf;
|
||||
pipe;
|
||||
poll;
|
||||
posix_openpt;
|
||||
preadv;
|
||||
profil;
|
||||
ptrace;
|
||||
|
@ -28,7 +28,7 @@
|
||||
.\" @(#)getrlimit.2 8.1 (Berkeley) 6/4/93
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd June 13, 2004
|
||||
.Dd August 20, 2008
|
||||
.Dt GETRLIMIT 2
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -97,6 +97,8 @@ mbufs, that this user may hold at any time.
|
||||
The maximum size (in bytes) of the stack segment for a process;
|
||||
this defines how far a program's stack segment may be extended.
|
||||
Stack extension is performed automatically by the system.
|
||||
.It Dv RLIMIT_NPTS
|
||||
The maximum number of pseudo-terminals created by this user id.
|
||||
.El
|
||||
.Pp
|
||||
A resource limit is specified as a soft limit and a hard limit.
|
||||
|
135
lib/libc/sys/posix_openpt.2
Normal file
135
lib/libc/sys/posix_openpt.2
Normal file
@ -0,0 +1,135 @@
|
||||
.\" Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Portions of this software were developed under sponsorship from Snow
|
||||
.\" B.V., the Netherlands.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" Portions of this text are reprinted and reproduced in electronic form
|
||||
.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
|
||||
.\" Portable Operating System Interface (POSIX), The Open Group Base
|
||||
.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
|
||||
.\" Electrical and Electronics Engineers, Inc and The Open Group. In the
|
||||
.\" event of any discrepancy between this version and the original IEEE and
|
||||
.\" The Open Group Standard, the original IEEE and The Open Group Standard is
|
||||
.\" the referee document. The original Standard can be obtained online at
|
||||
.\" http://www.opengroup.org/unix/online.html.
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd August 20, 2008
|
||||
.Dt POSIX_OPENPT 2
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm posix_openpt
|
||||
.Nd "open a pseudo-terminal device"
|
||||
.Sh LIBRARY
|
||||
.Lb libc
|
||||
.Sh SYNOPSIS
|
||||
.In stdlib.h
|
||||
.In fcntl.h
|
||||
.Ft int
|
||||
.Fn posix_openpt "int oflag"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Fn posix_openpt
|
||||
function allocates a new pseudo-terminal and establishes a connection
|
||||
with its master device.
|
||||
A slave device shall be created in
|
||||
.Pa /dev/pts .
|
||||
After the pseudo-terminal has been allocated, the slave device should
|
||||
have the proper permissions before it can be used (see
|
||||
.Xr grantpt 3 ) .
|
||||
The name of the slave device can be determined by calling
|
||||
.Xr ptsname 3 .
|
||||
.Pp
|
||||
The file status flags and file access modes of the open file description
|
||||
shall be set according to the value of
|
||||
.Fa oflag .
|
||||
Values for
|
||||
.Fa oflag
|
||||
are constructed by a bitwise-inclusive OR of flags from the following
|
||||
list, defined in
|
||||
.In fcntl.h :
|
||||
.Bl -tag -width ".Dv O_NOCTTY"
|
||||
.It Dv O_RDWR
|
||||
Open for reading and writing.
|
||||
.It Dv O_NOCTTY
|
||||
If set
|
||||
.Fn posix_openpt
|
||||
shall not cause the terminal device to become the controlling terminal
|
||||
for the process.
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Fn posix_openpt
|
||||
function shall fail when
|
||||
.Fa oflag
|
||||
contains other values.
|
||||
.Sh RETURN VALUES
|
||||
Upon successful completion, the
|
||||
.Fn posix_openpt
|
||||
function shall allocate a new pseudo-terminal device and return a
|
||||
non-negative integer representing a file descriptor, which is connected
|
||||
to its master device.
|
||||
Otherwise, -1 shall be returned and errno set to indicate the error.
|
||||
.Sh ERRORS
|
||||
The
|
||||
.Fn posix_openpt
|
||||
function shall fail if:
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er ENFILE
|
||||
The system file table is full.
|
||||
.It Bq Er EINVAL
|
||||
The value of
|
||||
.Fa oflag
|
||||
is not valid.
|
||||
.It Bq Er EAGAIN
|
||||
Out of pseudo-terminal resources.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr pts 4 ,
|
||||
.Xr ptsname 3 ,
|
||||
.Xr tty 4
|
||||
.Sh STANDARDS
|
||||
The
|
||||
.Fn posix_openpt
|
||||
function conforms to
|
||||
.St -p1003.1-2001 .
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Fn posix_openpt
|
||||
function appeared in
|
||||
.Fx 5.0 .
|
||||
In
|
||||
.Fx 8.0 ,
|
||||
this function was changed to a system call.
|
||||
.Sh NOTES
|
||||
The flag
|
||||
.Dv O_NOCTTY
|
||||
is included for compatibility; in
|
||||
.Fx ,
|
||||
opening a terminal does not cause it to become a process's controlling
|
||||
terminal.
|
||||
.Sh AUTHORS
|
||||
.An Ed Schouten Aq ed@FreeBSD.org
|
@ -19,7 +19,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd October 9, 2006
|
||||
.Dd August 20, 2008
|
||||
.Dt LOGIN.CONF 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -176,7 +176,7 @@ The usual convention to interpolate capability entries using the special
|
||||
.Em tc=value
|
||||
notation may be used.
|
||||
.Sh RESOURCE LIMITS
|
||||
.Bl -column coredumpsize indent indent
|
||||
.Bl -column pseudoterminals indent indent
|
||||
.It Sy "Name Type Notes Description
|
||||
.It "coredumpsize size Maximum coredump size limit.
|
||||
.It "cputime time CPU usage limit.
|
||||
@ -189,6 +189,7 @@ notation may be used.
|
||||
.It "sbsize size Maximum permitted socketbuffer size.
|
||||
.It "vmemoryuse size Maximum permitted total VM usage per process.
|
||||
.It "stacksize size Maximum stack size limit.
|
||||
.It "pseudoterminals number Maximum number of pseudo-terminals.
|
||||
.El
|
||||
.Pp
|
||||
These resource limit entries actually specify both the maximum
|
||||
|
@ -50,18 +50,19 @@ static struct login_res {
|
||||
rlim_t (*who)(login_cap_t *, const char *, rlim_t, rlim_t);
|
||||
int why;
|
||||
} resources[] = {
|
||||
{ "cputime", login_getcaptime, RLIMIT_CPU },
|
||||
{ "filesize", login_getcapsize, RLIMIT_FSIZE },
|
||||
{ "datasize", login_getcapsize, RLIMIT_DATA },
|
||||
{ "stacksize", login_getcapsize, RLIMIT_STACK },
|
||||
{ "memoryuse", login_getcapsize, RLIMIT_RSS },
|
||||
{ "memorylocked", login_getcapsize, RLIMIT_MEMLOCK },
|
||||
{ "maxproc", login_getcapnum, RLIMIT_NPROC },
|
||||
{ "openfiles", login_getcapnum, RLIMIT_NOFILE },
|
||||
{ "coredumpsize", login_getcapsize, RLIMIT_CORE },
|
||||
{ "sbsize", login_getcapsize, RLIMIT_SBSIZE },
|
||||
{ "vmemoryuse", login_getcapsize, RLIMIT_VMEM },
|
||||
{ NULL, 0, 0 }
|
||||
{ "cputime", login_getcaptime, RLIMIT_CPU },
|
||||
{ "filesize", login_getcapsize, RLIMIT_FSIZE },
|
||||
{ "datasize", login_getcapsize, RLIMIT_DATA },
|
||||
{ "stacksize", login_getcapsize, RLIMIT_STACK },
|
||||
{ "memoryuse", login_getcapsize, RLIMIT_RSS },
|
||||
{ "memorylocked", login_getcapsize, RLIMIT_MEMLOCK },
|
||||
{ "maxproc", login_getcapnum, RLIMIT_NPROC },
|
||||
{ "openfiles", login_getcapnum, RLIMIT_NOFILE },
|
||||
{ "coredumpsize", login_getcapsize, RLIMIT_CORE },
|
||||
{ "sbsize", login_getcapsize, RLIMIT_SBSIZE },
|
||||
{ "vmemoryuse", login_getcapsize, RLIMIT_VMEM },
|
||||
{ "pseudoterminals", login_getcapnum, RLIMIT_NPTS },
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
|
@ -279,6 +279,7 @@ MAN= aac.4 \
|
||||
psm.4 \
|
||||
pst.4 \
|
||||
pt.4 \
|
||||
pts.4 \
|
||||
pty.4 \
|
||||
puc.4 \
|
||||
ral.4 \
|
||||
|
@ -60,7 +60,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd July 21, 2008
|
||||
.Dd August 20, 2008
|
||||
.Dt DDB 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -942,6 +942,12 @@ Backtrace.
|
||||
.El
|
||||
.\"
|
||||
.Pp
|
||||
.It Ic show Cm ttys
|
||||
Show all TTY's within the system.
|
||||
Output is similar to
|
||||
.Xr pstat 8 .
|
||||
.\"
|
||||
.Pp
|
||||
.It Ic show Cm turnstile Ar addr
|
||||
Show turnstile
|
||||
.Vt struct turnstile
|
||||
|
181
share/man/man4/pts.4
Normal file
181
share/man/man4/pts.4
Normal file
@ -0,0 +1,181 @@
|
||||
.\" Copyright (c) 1983, 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. Neither the name of the University nor the names of its contributors
|
||||
.\" may be used to endorse or promote products derived from this software
|
||||
.\" without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)pty.4 8.2 (Berkeley) 11/30/93
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd August 20, 2008
|
||||
.Dt PTS 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm pts
|
||||
.Nd pseudo-terminal driver
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
driver provides support for a device-pair termed a
|
||||
.Em pseudo-terminal .
|
||||
A pseudo-terminal is a pair of character devices, a
|
||||
.Em master
|
||||
device and a
|
||||
.Em slave
|
||||
device.
|
||||
The slave device provides to a process an interface identical
|
||||
to that described in
|
||||
.Xr tty 4 .
|
||||
However, whereas all other devices which provide the
|
||||
interface described in
|
||||
.Xr tty 4
|
||||
have a hardware device of some sort behind them, the slave
|
||||
device has, instead, another process manipulating
|
||||
it through the master half of the pseudo-terminal.
|
||||
That is, anything written on the master device is
|
||||
given to the slave device as input and anything written
|
||||
on the slave device is presented as input on the master
|
||||
device.
|
||||
.Pp
|
||||
The following
|
||||
.Xr ioctl 2
|
||||
calls apply only to pseudo-terminals:
|
||||
.Bl -tag -width TIOCPTMASTER
|
||||
.It Dv TIOCPKT
|
||||
Enable/disable
|
||||
.Em packet
|
||||
mode.
|
||||
Packet mode is enabled by specifying (by reference)
|
||||
a nonzero parameter and disabled by specifying (by reference)
|
||||
a zero parameter.
|
||||
When applied to the master side of a pseudo-terminal, each subsequent
|
||||
.Xr read 2
|
||||
from the terminal will return data written on the slave part of
|
||||
the pseudo-terminal preceded by a zero byte (symbolically
|
||||
defined as
|
||||
.Dv TIOCPKT_DATA ) ,
|
||||
or a single byte reflecting control
|
||||
status information.
|
||||
In the latter case, the byte is an inclusive-or
|
||||
of zero or more of the bits:
|
||||
.Bl -tag -width TIOCPKT_FLUSHWRITE
|
||||
.It Dv TIOCPKT_FLUSHREAD
|
||||
whenever the read queue for the terminal is flushed.
|
||||
.It Dv TIOCPKT_FLUSHWRITE
|
||||
whenever the write queue for the terminal is flushed.
|
||||
.It Dv TIOCPKT_STOP
|
||||
whenever output to the terminal is stopped a la
|
||||
.Ql ^S .
|
||||
.It Dv TIOCPKT_START
|
||||
whenever output to the terminal is restarted.
|
||||
.It Dv TIOCPKT_DOSTOP
|
||||
whenever
|
||||
.Dv VSTOP
|
||||
is
|
||||
.Ql ^S
|
||||
and
|
||||
.Dv VSTART
|
||||
is
|
||||
.Ql ^Q .
|
||||
.It Dv TIOCPKT_NOSTOP
|
||||
whenever the start and stop characters are not
|
||||
.Ql ^S/^Q .
|
||||
.El
|
||||
.Pp
|
||||
While this mode is in use, the presence of control status information
|
||||
to be read from the master side may be detected by a
|
||||
.Xr select 2
|
||||
for exceptional conditions.
|
||||
.Pp
|
||||
This mode is used by
|
||||
.Xr rlogin 1
|
||||
and
|
||||
.Xr rlogind 8
|
||||
to implement a remote-echoed, locally
|
||||
.Ql ^S/^Q
|
||||
flow-controlled
|
||||
remote login with proper back-flushing of output; it can be
|
||||
used by other similar programs.
|
||||
.It Dv TIOCGPTN
|
||||
Obtain device unit number, which can be used to generate the filename of
|
||||
the pseudo-terminal slave device. This
|
||||
.Xr ioctl 2
|
||||
should not be used directly. Instead, the
|
||||
.Xr ptsname 3
|
||||
function should be used.
|
||||
.It Dv TIOCPTMASTER
|
||||
Determine whether the file descriptor is pointing to a pseudo-terminal
|
||||
master device.
|
||||
This
|
||||
.Xr ioctl 2
|
||||
should not be used directly. It is used to implement routines like
|
||||
.Xr grantpt 3 .
|
||||
.El
|
||||
.Pp
|
||||
The maximum number of pseudo-terminals is limited to 1000.
|
||||
It is not possible to use more than 1000 pseudo-terminals, as all software
|
||||
which use
|
||||
.Xr utmp 5
|
||||
will not be able to handle pseudo-terminals with number superior to 999.
|
||||
.Sh FILES
|
||||
The files used by this
|
||||
pseudo-terminals implementation are:
|
||||
.Pp
|
||||
.Bl -tag -width ".Pa /dev/pts/[num]"
|
||||
.It Pa /dev/ptmx
|
||||
Control device, returns a file descriptor to a new master pseudo-terminal
|
||||
when opened. This device should not be opened directly. It's only
|
||||
available for binary compatibility. New devices should only be created
|
||||
though
|
||||
.Xr posix_openpt 2 .
|
||||
.It Pa /dev/pts/[num]
|
||||
Pseudo-terminal slave devices.
|
||||
.El
|
||||
.Sh DIAGNOSTICS
|
||||
None.
|
||||
.Sh SEE ALSO
|
||||
.Xr grantpt 3 ,
|
||||
.Xr posix_openpt 2 ,
|
||||
.Xr ptsname 3 ,
|
||||
.Xr pty 4 ,
|
||||
.Xr tty 4
|
||||
.Sh HISTORY
|
||||
A
|
||||
pseudo-terminal driver appeared in
|
||||
.Bx 4.2 .
|
||||
In
|
||||
.Fx 8.0 ,
|
||||
it was replaced with the
|
||||
.Nm
|
||||
driver.
|
||||
.Sh BUGS
|
||||
Packet mode has not been properly implemented in this version of
|
||||
.Fx .
|
||||
When enabled, it will always prepend
|
||||
.Dv TIOCPKT_DATA ,
|
||||
even if other events have been triggered.
|
@ -1,5 +1,8 @@
|
||||
.\" Copyright (c) 1983, 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\" Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Portions of this software were developed under sponsorship from Snow
|
||||
.\" B.V., the Netherlands.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
@ -9,18 +12,11 @@
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. Neither the name of the University nor the names of its contributors
|
||||
.\" may be used to endorse or promote products derived from this software
|
||||
.\" without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
@ -29,214 +25,65 @@
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)pty.4 8.2 (Berkeley) 11/30/93
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd November 30, 1993
|
||||
.Dd August 20, 2008
|
||||
.Dt PTY 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm pty
|
||||
.Nd pseudo terminal driver
|
||||
.Nd BSD-style compatibility pseudo-terminal driver
|
||||
.Sh SYNOPSIS
|
||||
.Cd "device pty"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
driver provides support for a device-pair termed a
|
||||
.Em pseudo terminal .
|
||||
A pseudo terminal is a pair of character devices, a
|
||||
.Em master
|
||||
device and a
|
||||
.Em slave
|
||||
device.
|
||||
The slave device provides to a process an interface identical
|
||||
to that described in
|
||||
.Xr tty 4 .
|
||||
However, whereas all other devices which provide the
|
||||
interface described in
|
||||
.Xr tty 4
|
||||
have a hardware device of some sort behind them, the slave
|
||||
device has, instead, another process manipulating
|
||||
it through the master half of the pseudo terminal.
|
||||
That is, anything written on the master device is
|
||||
given to the slave device as input and anything written
|
||||
on the slave device is presented as input on the master
|
||||
device.
|
||||
driver provides support for the traditional BSD naming scheme that was
|
||||
used for accessing pseudo-terminals.
|
||||
When the device
|
||||
.Pa /dev/ptyXX
|
||||
is being opened, a new terminal shall be created with the
|
||||
.Xr pts 4
|
||||
driver.
|
||||
A device node for this terminal shall be created, which has the name
|
||||
.Pa /dev/ttyXX .
|
||||
.Pp
|
||||
The following
|
||||
.Xr ioctl 2
|
||||
calls apply only to pseudo terminals:
|
||||
.Bl -tag -width TIOCREMOTE
|
||||
.It Dv TIOCSTOP
|
||||
Stops output to a terminal (e.g.\& like typing
|
||||
.Ql ^S ) .
|
||||
Takes
|
||||
no parameter.
|
||||
.It Dv TIOCSTART
|
||||
Restarts output (stopped by
|
||||
.Dv TIOCSTOP
|
||||
or by typing
|
||||
.Ql ^S ) .
|
||||
Takes no parameter.
|
||||
.It Dv TIOCPKT
|
||||
Enable/disable
|
||||
.Em packet
|
||||
mode.
|
||||
Packet mode is enabled by specifying (by reference)
|
||||
a nonzero parameter and disabled by specifying (by reference)
|
||||
a zero parameter.
|
||||
When applied to the master side of a pseudo terminal, each subsequent
|
||||
.Xr read 2
|
||||
from the terminal will return data written on the slave part of
|
||||
the pseudo terminal preceded by a zero byte (symbolically
|
||||
defined as
|
||||
.Dv TIOCPKT_DATA ) ,
|
||||
or a single byte reflecting control
|
||||
status information.
|
||||
In the latter case, the byte is an inclusive-or
|
||||
of zero or more of the bits:
|
||||
.Bl -tag -width TIOCPKT_FLUSHWRITE
|
||||
.It Dv TIOCPKT_FLUSHREAD
|
||||
whenever the read queue for the terminal is flushed.
|
||||
.It Dv TIOCPKT_FLUSHWRITE
|
||||
whenever the write queue for the terminal is flushed.
|
||||
.It Dv TIOCPKT_STOP
|
||||
whenever output to the terminal is stopped a la
|
||||
.Ql ^S .
|
||||
.It Dv TIOCPKT_START
|
||||
whenever output to the terminal is restarted.
|
||||
.It Dv TIOCPKT_DOSTOP
|
||||
whenever
|
||||
.Em t_stopc
|
||||
is
|
||||
.Ql ^S
|
||||
and
|
||||
.Em t_startc
|
||||
is
|
||||
.Ql ^Q .
|
||||
.It Dv TIOCPKT_NOSTOP
|
||||
whenever the start and stop characters are not
|
||||
.Ql ^S/^Q .
|
||||
.El
|
||||
.Pp
|
||||
While this mode is in use, the presence of control status information
|
||||
to be read from the master side may be detected by a
|
||||
.Xr select 2
|
||||
for exceptional conditions.
|
||||
.Pp
|
||||
This mode is used by
|
||||
.Xr rlogin 1
|
||||
and
|
||||
.Xr rlogind 8
|
||||
to implement a remote-echoed, locally
|
||||
.Ql ^S/^Q
|
||||
flow-controlled
|
||||
remote login with proper back-flushing of output; it can be
|
||||
used by other similar programs.
|
||||
.It Dv TIOCUCNTL
|
||||
Enable/disable a mode that allows a small number of simple user
|
||||
.Xr ioctl 2
|
||||
commands to be passed through the pseudo-terminal,
|
||||
using a protocol similar to that of
|
||||
.Dv TIOCPKT .
|
||||
The
|
||||
.Dv TIOCUCNTL
|
||||
and
|
||||
.Dv TIOCPKT
|
||||
modes are mutually exclusive.
|
||||
This mode is enabled from the master side of a pseudo terminal
|
||||
by specifying (by reference)
|
||||
a nonzero parameter and disabled by specifying (by reference)
|
||||
a zero parameter.
|
||||
Each subsequent
|
||||
.Xr read 2
|
||||
from the master side will return data written on the slave part of
|
||||
the pseudo terminal preceded by a zero byte,
|
||||
or a single byte reflecting a user control operation on the slave side.
|
||||
A user control command consists of a special
|
||||
.Xr ioctl 2
|
||||
operation with no data; the command is given as
|
||||
.Dv UIOCCMD Ns (n) ,
|
||||
where
|
||||
.Ar n
|
||||
is a number in the range 1-255.
|
||||
The operation value
|
||||
.Ar n
|
||||
will be received as a single byte on the next
|
||||
.Xr read 2
|
||||
from the master side.
|
||||
The
|
||||
.Xr ioctl 2
|
||||
.Dv UIOCCMD Ns (0)
|
||||
is a no-op that may be used to probe for
|
||||
the existence of this facility.
|
||||
As with
|
||||
.Dv TIOCPKT
|
||||
mode, command operations may be detected with a
|
||||
.Xr select 2
|
||||
for exceptional conditions.
|
||||
.El
|
||||
.Pp
|
||||
There is currently two
|
||||
.Nm
|
||||
systems available: the original
|
||||
.Bx Nm ,
|
||||
and a
|
||||
SysVR4 pts-like implementation.
|
||||
It is possible to switch between the two implementations by setting the
|
||||
.Va kern.pts.enable
|
||||
sysctl.
|
||||
Setting it to 0 will use the
|
||||
.Bx Nm ,
|
||||
to non-zero the pts implementation.
|
||||
It defaults to 0.
|
||||
It is possible to set the maximum number of ptys
|
||||
which can be allocated at the same time with the
|
||||
.Va kern.pts.max
|
||||
sysctl.
|
||||
It defaults to 1000.
|
||||
It is not recommended to use more than 1000 pseudo-terminals, as all software
|
||||
which use
|
||||
.Xr utmp 5
|
||||
will not be able to handle pseudo-terminals with number superior to 999.
|
||||
.Pp
|
||||
The pts implementation also supports the
|
||||
.Dv TIOCGPTN
|
||||
.Xr ioctl 2
|
||||
call, which takes a pointer to an
|
||||
.Vt "unsigned int"
|
||||
as a parameter and provides the
|
||||
number of the pty.
|
||||
New code should not try to allocate pseudo-terminals using this
|
||||
interface.
|
||||
It is only provided for compatibility with older C libraries
|
||||
that tried to open such devices when
|
||||
.Xr posix_openpt 2
|
||||
was being called.
|
||||
.Sh FILES
|
||||
The files used by the
|
||||
.Bx
|
||||
pseudo terminals implementation are:
|
||||
The BSD-style compatibility pseudo-terminal driver uses the following
|
||||
device names:
|
||||
.Pp
|
||||
.Bl -tag -width ".Pa /dev/tty[p-sP-S][0-9a-v]" -compact
|
||||
.It Pa /dev/pty[p-sP-S][0-9a-v]
|
||||
master pseudo terminals
|
||||
.It Pa /dev/tty[p-sP-S][0-9a-v]
|
||||
slave pseudo terminals
|
||||
.El
|
||||
.Pp
|
||||
The files used by the pts implementation are:
|
||||
.Pp
|
||||
.Bl -tag -width ".Pa /dev/pts/[num]" -compact
|
||||
.It Pa /dev/ptmx
|
||||
control device, returns a file descriptor to a new master pseudo terminal
|
||||
when opened.
|
||||
.It Pa /dev/pty[num]
|
||||
master pseudo terminals
|
||||
.It Pa /dev/pts/[num]
|
||||
slave pseudo terminals
|
||||
.Bl -tag -width ".Pa /dev/pty[l-sL-S][0-9a-v]"
|
||||
.It Pa /dev/pty[l-sL-S][0-9a-v]
|
||||
Pseudo-terminal master devices.
|
||||
.It Pa /dev/tty[l-sL-S][0-9a-v]
|
||||
Pseudo-terminal slave devices.
|
||||
.El
|
||||
.Sh DIAGNOSTICS
|
||||
None.
|
||||
.Sh SEE ALSO
|
||||
.Xr posix_openpt 2 ,
|
||||
.Xr pts 4 ,
|
||||
.Xr tty 4
|
||||
.Sh HISTORY
|
||||
A
|
||||
pseudo-terminal driver appeared in
|
||||
.Bx 4.2 .
|
||||
.Sh BUGS
|
||||
Unlike previous implementations, the master slave device nodes are
|
||||
destroyed when the PTY becomes unused.
|
||||
A call to
|
||||
.Xr stat 2
|
||||
on a nonexistent master device will already cause a new master device
|
||||
node to be created.
|
||||
The master device can only be destroyed by opening and closing it.
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
driver appeared in
|
||||
.Bx 4.2 .
|
||||
driver cannot be unloaded, because it cannot determine if it is being
|
||||
used.
|
||||
|
@ -32,7 +32,7 @@
|
||||
.\" @(#)termios.4 8.4 (Berkeley) 4/19/94
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd May 13, 2008
|
||||
.Dd August 20, 2008
|
||||
.Dt TERMIOS 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -1073,7 +1073,7 @@ Values of the
|
||||
field describe the basic terminal output control,
|
||||
and are composed of the following masks:
|
||||
.Pp
|
||||
.Bl -tag -width OXTABS -offset indent -compact
|
||||
.Bl -tag -width ONOEOT -offset indent -compact
|
||||
.It Dv OPOST
|
||||
/* enable following output processing */
|
||||
.It Dv ONLCR
|
||||
@ -1082,7 +1082,11 @@ and are composed of the following masks:
|
||||
*/
|
||||
.It Dv OCRNL
|
||||
/* map CR to NL */
|
||||
.It Dv OXTABS
|
||||
.It Dv TABDLY
|
||||
/* tab delay mask */
|
||||
.It Dv TAB0
|
||||
/* no tab delay and expansion */
|
||||
.It Dv TAB3
|
||||
/* expand tabs to spaces */
|
||||
.It Dv ONOEOT
|
||||
/* discard
|
||||
@ -1108,8 +1112,20 @@ If
|
||||
.Dv OCRNL
|
||||
is set, carriage returns are translated to newlines.
|
||||
.Pp
|
||||
The
|
||||
.Dv TABDLY
|
||||
bits specify the tab delay.
|
||||
The
|
||||
.Fa c_oflag
|
||||
is masked with
|
||||
.Dv TABDLY
|
||||
and compared with the
|
||||
values
|
||||
.Dv TAB0
|
||||
or
|
||||
.Dv TAB3 .
|
||||
If
|
||||
.Dv OXTABS
|
||||
.Dv TAB3
|
||||
is set, tabs are expanded to the appropriate number of
|
||||
spaces (assuming 8 column tab stops).
|
||||
.Pp
|
||||
|
@ -257,7 +257,7 @@ device loop # Network loopback
|
||||
device random # Entropy device
|
||||
device ether # Ethernet support
|
||||
device tun # Packet tunnel.
|
||||
device pty # Pseudo-ttys (telnet etc)
|
||||
device pty # BSD-style compatibility pseudo ttys
|
||||
device md # Memory "disks"
|
||||
device gif # IPv6 and IPv4 tunneling
|
||||
device faith # IPv6-to-IPv4 relaying (translation)
|
||||
|
@ -548,6 +548,7 @@
|
||||
#define AUE_MKNODAT 43150 /* FreeBSD. */
|
||||
#define AUE_READLINKAT 43151 /* FreeBSD. */
|
||||
#define AUE_SYMLINKAT 43152 /* FreeBSD. */
|
||||
#define AUE_POSIXOPENPT 43153 /* FreeBSD. */
|
||||
|
||||
/*
|
||||
* Darwin BSM uses a number of AUE_O_* definitions, which are aliased to the
|
||||
|
@ -355,4 +355,5 @@
|
||||
#define FREEBSD32_SYS_renameat 501
|
||||
#define FREEBSD32_SYS_symlinkat 502
|
||||
#define FREEBSD32_SYS_unlinkat 503
|
||||
#define FREEBSD32_SYS_MAXSYSCALL 504
|
||||
#define FREEBSD32_SYS_posix_openpt 504
|
||||
#define FREEBSD32_SYS_MAXSYSCALL 505
|
||||
|
@ -511,4 +511,5 @@ const char *freebsd32_syscallnames[] = {
|
||||
"renameat", /* 501 = renameat */
|
||||
"symlinkat", /* 502 = symlinkat */
|
||||
"unlinkat", /* 503 = unlinkat */
|
||||
"posix_openpt", /* 504 = posix_openpt */
|
||||
};
|
||||
|
@ -542,4 +542,5 @@ struct sysent freebsd32_sysent[] = {
|
||||
{ AS(renameat_args), (sy_call_t *)renameat, AUE_RENAMEAT, NULL, 0, 0 }, /* 501 = renameat */
|
||||
{ AS(symlinkat_args), (sy_call_t *)symlinkat, AUE_SYMLINKAT, NULL, 0, 0 }, /* 502 = symlinkat */
|
||||
{ AS(unlinkat_args), (sy_call_t *)unlinkat, AUE_UNLINKAT, NULL, 0, 0 }, /* 503 = unlinkat */
|
||||
{ AS(posix_openpt_args), (sy_call_t *)posix_openpt, AUE_POSIXOPENPT, NULL, 0, 0 }, /* 504 = posix_openpt */
|
||||
};
|
||||
|
@ -846,3 +846,4 @@
|
||||
char *path2); }
|
||||
503 AUE_UNLINKAT NOPROTO { int unlinkat(int fd, char *path, \
|
||||
int flag); }
|
||||
504 AUE_POSIXOPENPT NOPROTO { int posix_openpt(int flags); }
|
||||
|
@ -296,6 +296,11 @@ struct linux_winsize {
|
||||
unsigned short ws_xpixel, ws_ypixel;
|
||||
};
|
||||
|
||||
struct speedtab {
|
||||
int sp_speed; /* Speed. */
|
||||
int sp_code; /* Code. */
|
||||
};
|
||||
|
||||
static struct speedtab sptab[] = {
|
||||
{ B0, LINUX_B0 }, { B50, LINUX_B50 },
|
||||
{ B75, LINUX_B75 }, { B110, LINUX_B110 },
|
||||
@ -395,7 +400,7 @@ bsd_to_linux_termios(struct termios *bios, struct linux_termios *lios)
|
||||
lios->c_oflag |= LINUX_OPOST;
|
||||
if (bios->c_oflag & ONLCR)
|
||||
lios->c_oflag |= LINUX_ONLCR;
|
||||
if (bios->c_oflag & OXTABS)
|
||||
if (bios->c_oflag & TAB3)
|
||||
lios->c_oflag |= LINUX_XTABS;
|
||||
|
||||
lios->c_cflag = bsd_to_linux_speed(bios->c_ispeed, sptab);
|
||||
@ -537,7 +542,7 @@ linux_to_bsd_termios(struct linux_termios *lios, struct termios *bios)
|
||||
if (lios->c_oflag & LINUX_ONLCR)
|
||||
bios->c_oflag |= ONLCR;
|
||||
if (lios->c_oflag & LINUX_XTABS)
|
||||
bios->c_oflag |= OXTABS;
|
||||
bios->c_oflag |= TAB3;
|
||||
|
||||
bios->c_cflag = (lios->c_cflag & LINUX_CSIZE) << 4;
|
||||
if (lios->c_cflag & LINUX_CSTOPB)
|
||||
|
@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscallsubr.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/tty.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/fcntl.h>
|
||||
@ -109,8 +110,17 @@ translate_fd_major_minor(struct thread *td, int fd, struct stat *buf)
|
||||
if (fp->f_vnode != NULL &&
|
||||
fp->f_vnode->v_un.vu_cdev != NULL &&
|
||||
linux_driver_get_major_minor(fp->f_vnode->v_un.vu_cdev->si_name,
|
||||
&major, &minor) == 0)
|
||||
&major, &minor) == 0) {
|
||||
buf->st_rdev = (major << 8 | minor);
|
||||
} else if (fp->f_type == DTYPE_PTS) {
|
||||
struct tty *tp = fp->f_data;
|
||||
|
||||
/* Convert the numbers for the slave device. */
|
||||
if (linux_driver_get_major_minor(tp->t_dev->si_name,
|
||||
&major, &minor) == 0) {
|
||||
buf->st_rdev = (major << 8 | minor);
|
||||
}
|
||||
}
|
||||
fdrop(fp, td);
|
||||
}
|
||||
|
||||
|
@ -1275,11 +1275,7 @@ options SES_ENABLE_PASSTHROUGH
|
||||
#####################################################################
|
||||
# MISCELLANEOUS DEVICES AND OPTIONS
|
||||
|
||||
# The `pty' device usually turns out to be ``effectively mandatory'',
|
||||
# as it is required for `telnetd', `rlogind', `screen', `emacs', and
|
||||
# `xterm', among others.
|
||||
|
||||
device pty #Pseudo ttys
|
||||
device pty #BSD-style compatibility pseudo ttys
|
||||
device nmdm #back-to-back tty devices
|
||||
device md #Memory/malloc disk
|
||||
device ccd #Concatenated disk driver
|
||||
@ -1291,9 +1287,6 @@ options LIBICONV
|
||||
# Size of the kernel message buffer. Should be N * pagesize.
|
||||
options MSGBUF_SIZE=40960
|
||||
|
||||
# Maximum size of a tty or pty input buffer.
|
||||
options TTYHOG=8193
|
||||
|
||||
|
||||
#####################################################################
|
||||
# HARDWARE DEVICE CONFIGURATION
|
||||
|
@ -1661,12 +1661,14 @@ kern/sysv_sem.c optional sysvsem
|
||||
kern/sysv_shm.c optional sysvshm
|
||||
kern/tty.c standard
|
||||
kern/tty_compat.c optional compat_43tty
|
||||
kern/tty_conf.c standard
|
||||
kern/tty_cons.c standard
|
||||
kern/tty_info.c standard
|
||||
kern/tty_pts.c optional pty
|
||||
kern/tty_inq.c standard
|
||||
kern/tty_outq.c standard
|
||||
kern/tty_pts.c standard
|
||||
kern/tty_pty.c optional pty
|
||||
kern/tty_tty.c standard
|
||||
kern/tty_ttydisc.c standard
|
||||
kern/uipc_accf.c optional inet
|
||||
kern/uipc_cow.c optional zero_copy_sockets
|
||||
kern/uipc_debug.c optional ddb
|
||||
@ -2354,4 +2356,4 @@ xen/xenbus/xenbus_xs.c optional xen
|
||||
dev/xen/console/console.c optional xen
|
||||
dev/xen/console/xencons_ring.c optional xen
|
||||
dev/xen/blkfront/blkfront.c optional xen
|
||||
dev/xen/netfront/netfront.c optional xen
|
||||
dev/xen/netfront/netfront.c optional xen
|
||||
|
@ -175,7 +175,6 @@ SYSVSEM opt_sysvipc.h
|
||||
SYSVSHM opt_sysvipc.h
|
||||
SW_WATCHDOG opt_watchdog.h
|
||||
TURNSTILE_PROFILING
|
||||
TTYHOG opt_tty.h
|
||||
VFS_AIO
|
||||
VERBOSE_SYSINIT opt_global.h
|
||||
WLCACHE opt_wavelan.h
|
||||
@ -658,6 +657,7 @@ ISAPNP opt_isa.h
|
||||
DEV_BPF opt_bpf.h
|
||||
DEV_MCA opt_mca.h
|
||||
DEV_CARP opt_carp.h
|
||||
DEV_PTY opt_tty.h
|
||||
DEV_SPLASH opt_splash.h
|
||||
|
||||
# EISA support
|
||||
|
@ -98,7 +98,7 @@ struct dcons_softc {
|
||||
int brk_state;
|
||||
#define DC_GDB 1
|
||||
int flags;
|
||||
void *dev;
|
||||
void *tty;
|
||||
};
|
||||
|
||||
int dcons_checkc(struct dcons_softc *);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*-
|
||||
* Copyright (C) 2003,2004
|
||||
* Hidetoshi Shimokawa. All rights reserved.
|
||||
*
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
@ -18,7 +18,7 @@
|
||||
* 4. Neither the name of the author nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
@ -30,15 +30,13 @@
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#if __FreeBSD_version >= 502122
|
||||
#include <sys/kdb.h>
|
||||
#include <gdb/gdb.h>
|
||||
#endif
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/systm.h>
|
||||
@ -54,13 +52,8 @@
|
||||
|
||||
#include <machine/bus.h>
|
||||
|
||||
#ifdef __DragonFly__
|
||||
#include "dcons.h"
|
||||
#include "dcons_os.h"
|
||||
#else
|
||||
#include <dev/dcons/dcons.h>
|
||||
#include <dev/dcons/dcons_os.h>
|
||||
#endif
|
||||
|
||||
#include <ddb/ddb.h>
|
||||
#include <sys/reboot.h>
|
||||
@ -90,53 +83,6 @@
|
||||
#define DCONS_FORCE_CONSOLE 0 /* Mostly for FreeBSD-4/DragonFly */
|
||||
#endif
|
||||
|
||||
#ifndef DCONS_FORCE_GDB
|
||||
#define DCONS_FORCE_GDB 1
|
||||
#endif
|
||||
|
||||
#if __FreeBSD_version >= 500101
|
||||
#define CONS_NODEV 1
|
||||
#if __FreeBSD_version < 502122
|
||||
static struct consdev gdbconsdev;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static d_open_t dcons_open;
|
||||
static d_close_t dcons_close;
|
||||
#if defined(__DragonFly__) || __FreeBSD_version < 500104
|
||||
static d_ioctl_t dcons_ioctl;
|
||||
#endif
|
||||
|
||||
static struct cdevsw dcons_cdevsw = {
|
||||
#ifdef __DragonFly__
|
||||
#define CDEV_MAJOR 184
|
||||
"dcons", CDEV_MAJOR, D_TTY, NULL, 0,
|
||||
dcons_open, dcons_close, ttyread, ttywrite, dcons_ioctl,
|
||||
ttypoll, nommap, nostrategy, nodump, nopsize,
|
||||
#elif __FreeBSD_version >= 500104
|
||||
.d_version = D_VERSION,
|
||||
.d_open = dcons_open,
|
||||
.d_close = dcons_close,
|
||||
.d_name = "dcons",
|
||||
.d_flags = D_TTY | D_NEEDGIANT,
|
||||
#else
|
||||
#define CDEV_MAJOR 184
|
||||
/* open */ dcons_open,
|
||||
/* close */ dcons_close,
|
||||
/* read */ ttyread,
|
||||
/* write */ ttywrite,
|
||||
/* ioctl */ dcons_ioctl,
|
||||
/* poll */ ttypoll,
|
||||
/* mmap */ nommap,
|
||||
/* strategy */ nostrategy,
|
||||
/* name */ "dcons",
|
||||
/* major */ CDEV_MAJOR,
|
||||
/* dump */ nodump,
|
||||
/* psize */ nopsize,
|
||||
/* flags */ D_TTY,
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef KLD_MODULE
|
||||
static char bssbuf[DCONS_BUF_SIZE]; /* buf in bss */
|
||||
#endif
|
||||
@ -156,20 +102,6 @@ static int drv_init = 0;
|
||||
static struct callout dcons_callout;
|
||||
struct dcons_buf *dcons_buf; /* for local dconschat */
|
||||
|
||||
#ifdef __DragonFly__
|
||||
#define DEV dev_t
|
||||
#define THREAD d_thread_t
|
||||
#elif __FreeBSD_version < 500000
|
||||
#define DEV dev_t
|
||||
#define THREAD struct proc
|
||||
#else
|
||||
#define DEV struct cdev *
|
||||
#define THREAD struct thread
|
||||
#endif
|
||||
|
||||
|
||||
static void dcons_tty_start(struct tty *);
|
||||
static int dcons_tty_param(struct tty *, struct termios *);
|
||||
static void dcons_timeout(void *);
|
||||
static int dcons_drv_init(int);
|
||||
|
||||
@ -181,12 +113,12 @@ static cn_putc_t dcons_cnputc;
|
||||
|
||||
CONSOLE_DRIVER(dcons);
|
||||
|
||||
#if defined(GDB) && (__FreeBSD_version >= 502122)
|
||||
static gdb_probe_f dcons_dbg_probe;
|
||||
static gdb_init_f dcons_dbg_init;
|
||||
static gdb_term_f dcons_dbg_term;
|
||||
static gdb_getc_f dcons_dbg_getc;
|
||||
static gdb_putc_f dcons_dbg_putc;
|
||||
#if defined(GDB)
|
||||
static gdb_probe_f dcons_dbg_probe;
|
||||
static gdb_init_f dcons_dbg_init;
|
||||
static gdb_term_f dcons_dbg_term;
|
||||
static gdb_getc_f dcons_dbg_getc;
|
||||
static gdb_putc_f dcons_dbg_putc;
|
||||
|
||||
GDB_DBGPORT(dcons, dcons_dbg_probe, dcons_dbg_init, dcons_dbg_term,
|
||||
dcons_dbg_getc, dcons_dbg_putc);
|
||||
@ -194,21 +126,25 @@ GDB_DBGPORT(dcons, dcons_dbg_probe, dcons_dbg_init, dcons_dbg_term,
|
||||
extern struct gdb_dbgport *gdb_cur;
|
||||
#endif
|
||||
|
||||
static tsw_outwakeup_t dcons_outwakeup;
|
||||
|
||||
static struct ttydevsw dcons_ttydevsw = {
|
||||
.tsw_flags = TF_NOPREFIX,
|
||||
.tsw_outwakeup = dcons_outwakeup,
|
||||
};
|
||||
|
||||
#if (defined(GDB) || defined(DDB)) && defined(ALT_BREAK_TO_DEBUGGER)
|
||||
static int
|
||||
dcons_check_break(struct dcons_softc *dc, int c)
|
||||
{
|
||||
#if __FreeBSD_version >= 502122
|
||||
int kdb_brk;
|
||||
#endif
|
||||
|
||||
if (c < 0)
|
||||
return (c);
|
||||
|
||||
#if __FreeBSD_version >= 502122
|
||||
if ((kdb_brk = kdb_alt_break(c, &dc->brk_state)) != 0) {
|
||||
switch (kdb_brk) {
|
||||
case KDB_REQ_DEBUGGER:
|
||||
|
||||
if ((dc->flags & DC_GDB) != 0) {
|
||||
#ifdef GDB
|
||||
if (gdb_cur == &dcons_gdb_dbgport) {
|
||||
@ -229,27 +165,6 @@ dcons_check_break(struct dcons_softc *dc, int c)
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
switch (dc->brk_state) {
|
||||
case STATE1:
|
||||
if (c == KEY_TILDE)
|
||||
dc->brk_state = STATE2;
|
||||
else
|
||||
dc->brk_state = STATE0;
|
||||
break;
|
||||
case STATE2:
|
||||
dc->brk_state = STATE0;
|
||||
if (c == KEY_CTRLB) {
|
||||
#if DCONS_FORCE_GDB
|
||||
if (dc->flags & DC_GDB)
|
||||
boothowto |= RB_GDB;
|
||||
#endif
|
||||
breakpoint();
|
||||
}
|
||||
}
|
||||
if (c == KEY_CR)
|
||||
dc->brk_state = STATE1;
|
||||
#endif
|
||||
return (c);
|
||||
}
|
||||
#else
|
||||
@ -263,7 +178,7 @@ dcons_os_checkc_nopoll(struct dcons_softc *dc)
|
||||
|
||||
if (dg.dma_tag != NULL)
|
||||
bus_dmamap_sync(dg.dma_tag, dg.dma_map, BUS_DMASYNC_POSTREAD);
|
||||
|
||||
|
||||
c = dcons_check_break(dc, dcons_checkc(dc));
|
||||
|
||||
if (dg.dma_tag != NULL)
|
||||
@ -279,18 +194,6 @@ dcons_os_checkc(struct dcons_softc *dc)
|
||||
return (dcons_os_checkc_nopoll(dc));
|
||||
}
|
||||
|
||||
#if defined(GDB) || !defined(CONS_NODEV)
|
||||
static int
|
||||
dcons_os_getc(struct dcons_softc *dc)
|
||||
{
|
||||
int c;
|
||||
|
||||
while ((c = dcons_os_checkc(dc)) == -1);
|
||||
|
||||
return (c & 0xff);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
dcons_os_putc(struct dcons_softc *dc, int c)
|
||||
{
|
||||
@ -302,122 +205,17 @@ dcons_os_putc(struct dcons_softc *dc, int c)
|
||||
if (dg.dma_tag != NULL)
|
||||
bus_dmamap_sync(dg.dma_tag, dg.dma_map, BUS_DMASYNC_PREWRITE);
|
||||
}
|
||||
static int
|
||||
dcons_open(DEV dev, int flag, int mode, THREAD *td)
|
||||
{
|
||||
struct tty *tp;
|
||||
int unit, error, s;
|
||||
|
||||
unit = minor(dev);
|
||||
if (unit != 0)
|
||||
return (ENXIO);
|
||||
|
||||
tp = dev->si_tty;
|
||||
tp->t_oproc = dcons_tty_start;
|
||||
tp->t_param = dcons_tty_param;
|
||||
tp->t_stop = nottystop;
|
||||
tp->t_dev = dev;
|
||||
|
||||
error = 0;
|
||||
|
||||
s = spltty();
|
||||
if ((tp->t_state & TS_ISOPEN) == 0) {
|
||||
tp->t_state |= TS_CARR_ON;
|
||||
ttyconsolemode(tp, 0);
|
||||
} else if ((tp->t_state & TS_XCLUDE) &&
|
||||
priv_check(td, PRIV_TTY_EXCLUSIVE)) {
|
||||
splx(s);
|
||||
return (EBUSY);
|
||||
}
|
||||
splx(s);
|
||||
|
||||
#if __FreeBSD_version < 502113
|
||||
error = (*linesw[tp->t_line].l_open)(dev, tp);
|
||||
#else
|
||||
error = ttyld_open(tp, dev);
|
||||
#endif
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
dcons_close(DEV dev, int flag, int mode, THREAD *td)
|
||||
{
|
||||
int unit;
|
||||
struct tty *tp;
|
||||
|
||||
unit = minor(dev);
|
||||
if (unit != 0)
|
||||
return (ENXIO);
|
||||
|
||||
tp = dev->si_tty;
|
||||
if (tp->t_state & TS_ISOPEN) {
|
||||
#if __FreeBSD_version < 502113
|
||||
(*linesw[tp->t_line].l_close)(tp, flag);
|
||||
ttyclose(tp);
|
||||
#else
|
||||
ttyld_close(tp, flag);
|
||||
tty_close(tp);
|
||||
#endif
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#if defined(__DragonFly__) || __FreeBSD_version < 500104
|
||||
static int
|
||||
dcons_ioctl(DEV dev, u_long cmd, caddr_t data, int flag, THREAD *td)
|
||||
{
|
||||
int unit;
|
||||
struct tty *tp;
|
||||
int error;
|
||||
|
||||
unit = minor(dev);
|
||||
if (unit != 0)
|
||||
return (ENXIO);
|
||||
|
||||
tp = dev->si_tty;
|
||||
error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, td);
|
||||
if (error != ENOIOCTL)
|
||||
return (error);
|
||||
|
||||
error = ttioctl(tp, cmd, data, flag);
|
||||
if (error != ENOIOCTL)
|
||||
return (error);
|
||||
|
||||
return (ENOTTY);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
dcons_tty_param(struct tty *tp, struct termios *t)
|
||||
{
|
||||
tp->t_ispeed = t->c_ispeed;
|
||||
tp->t_ospeed = t->c_ospeed;
|
||||
tp->t_cflag = t->c_cflag;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
dcons_tty_start(struct tty *tp)
|
||||
dcons_outwakeup(struct tty *tp)
|
||||
{
|
||||
struct dcons_softc *dc;
|
||||
int s;
|
||||
char ch;
|
||||
|
||||
dc = (struct dcons_softc *)tp->t_dev->si_drv1;
|
||||
s = spltty();
|
||||
if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
|
||||
ttwwakeup(tp);
|
||||
return;
|
||||
}
|
||||
dc = tty_softc(tp);
|
||||
|
||||
tp->t_state |= TS_BUSY;
|
||||
while (tp->t_outq.c_cc != 0)
|
||||
dcons_os_putc(dc, getc(&tp->t_outq));
|
||||
tp->t_state &= ~TS_BUSY;
|
||||
|
||||
ttwwakeup(tp);
|
||||
splx(s);
|
||||
while (ttydisc_getc(tp, &ch, sizeof ch) != 0)
|
||||
dcons_os_putc(dc, ch);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -429,14 +227,13 @@ dcons_timeout(void *v)
|
||||
|
||||
for (i = 0; i < DCONS_NPORT; i ++) {
|
||||
dc = &sc[i];
|
||||
tp = ((DEV)dc->dev)->si_tty;
|
||||
tp = dc->tty;
|
||||
|
||||
tty_lock(tp);
|
||||
while ((c = dcons_os_checkc_nopoll(dc)) != -1)
|
||||
if (tp->t_state & TS_ISOPEN)
|
||||
#if __FreeBSD_version < 502113
|
||||
(*linesw[tp->t_line].l_rint)(c, tp);
|
||||
#else
|
||||
ttyld_rint(tp, c);
|
||||
#endif
|
||||
ttydisc_rint(tp, c, 0);
|
||||
ttydisc_rint_done(tp);
|
||||
tty_unlock(tp);
|
||||
}
|
||||
polltime = hz / poll_hz;
|
||||
if (polltime < 1)
|
||||
@ -447,14 +244,7 @@ dcons_timeout(void *v)
|
||||
static void
|
||||
dcons_cnprobe(struct consdev *cp)
|
||||
{
|
||||
#ifdef __DragonFly__
|
||||
cp->cn_dev = make_dev(&dcons_cdevsw, DCONS_CON,
|
||||
UID_ROOT, GID_WHEEL, 0600, "dcons");
|
||||
#elif __FreeBSD_version >= 501109
|
||||
sprintf(cp->cn_name, "dcons");
|
||||
#else
|
||||
cp->cn_dev = makedev(CDEV_MAJOR, DCONS_CON);
|
||||
#endif
|
||||
#if DCONS_FORCE_CONSOLE
|
||||
cp->cn_pri = CN_REMOTE;
|
||||
#else
|
||||
@ -466,12 +256,7 @@ static void
|
||||
dcons_cninit(struct consdev *cp)
|
||||
{
|
||||
dcons_drv_init(0);
|
||||
#if CONS_NODEV
|
||||
cp->cn_arg
|
||||
#else
|
||||
cp->cn_dev->si_drv1
|
||||
#endif
|
||||
= (void *)&sc[DCONS_CON]; /* share port0 with unit0 */
|
||||
cp->cn_arg = (void *)&sc[DCONS_CON]; /* share port0 with unit0 */
|
||||
}
|
||||
|
||||
static void
|
||||
@ -479,39 +264,19 @@ dcons_cnterm(struct consdev *cp)
|
||||
{
|
||||
}
|
||||
|
||||
#if CONS_NODEV
|
||||
static int
|
||||
dcons_cngetc(struct consdev *cp)
|
||||
{
|
||||
struct dcons_softc *dc = (struct dcons_softc *)cp->cn_arg;
|
||||
return (dcons_os_checkc(dc));
|
||||
}
|
||||
|
||||
static void
|
||||
dcons_cnputc(struct consdev *cp, int c)
|
||||
{
|
||||
struct dcons_softc *dc = (struct dcons_softc *)cp->cn_arg;
|
||||
dcons_os_putc(dc, c);
|
||||
}
|
||||
#else
|
||||
static int
|
||||
dcons_cngetc(DEV dev)
|
||||
{
|
||||
struct dcons_softc *dc = (struct dcons_softc *)dev->si_drv1;
|
||||
return (dcons_os_getc(dc));
|
||||
}
|
||||
static int
|
||||
dcons_cncheckc(DEV dev)
|
||||
{
|
||||
struct dcons_softc *dc = (struct dcons_softc *)dev->si_drv1;
|
||||
return (dcons_os_checkc(dc));
|
||||
}
|
||||
static void
|
||||
dcons_cnputc(DEV dev, int c)
|
||||
{
|
||||
struct dcons_softc *dc = (struct dcons_softc *)dev->si_drv1;
|
||||
dcons_os_putc(dc, c);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
dcons_drv_init(int stage)
|
||||
@ -577,24 +342,6 @@ dcons_drv_init(int stage)
|
||||
ok:
|
||||
dcons_buf = dg.buf;
|
||||
|
||||
#if __FreeBSD_version < 502122
|
||||
#if defined(DDB) && DCONS_FORCE_GDB
|
||||
#if CONS_NODEV
|
||||
gdbconsdev.cn_arg = (void *)&sc[DCONS_GDB];
|
||||
#if __FreeBSD_version >= 501109
|
||||
sprintf(gdbconsdev.cn_name, "dgdb");
|
||||
#endif
|
||||
gdb_arg = &gdbconsdev;
|
||||
#elif defined(__DragonFly__)
|
||||
gdbdev = make_dev(&dcons_cdevsw, DCONS_GDB,
|
||||
UID_ROOT, GID_WHEEL, 0600, "dgdb");
|
||||
#else
|
||||
gdbdev = makedev(CDEV_MAJOR, DCONS_GDB);
|
||||
#endif
|
||||
gdb_getc = dcons_cngetc;
|
||||
gdb_putc = dcons_cnputc;
|
||||
#endif
|
||||
#endif
|
||||
drv_init = 1;
|
||||
|
||||
return 0;
|
||||
@ -606,23 +353,12 @@ dcons_attach_port(int port, char *name, int flags)
|
||||
{
|
||||
struct dcons_softc *dc;
|
||||
struct tty *tp;
|
||||
DEV dev;
|
||||
|
||||
dc = &sc[port];
|
||||
tp = tty_alloc(&dcons_ttydevsw, dc, NULL);
|
||||
dc->flags = flags;
|
||||
dev = make_dev(&dcons_cdevsw, port,
|
||||
UID_ROOT, GID_WHEEL, 0600, name);
|
||||
dc->dev = (void *)dev;
|
||||
tp = ttyalloc();
|
||||
|
||||
dev->si_drv1 = (void *)dc;
|
||||
dev->si_tty = tp;
|
||||
|
||||
tp->t_oproc = dcons_tty_start;
|
||||
tp->t_param = dcons_tty_param;
|
||||
tp->t_stop = nottystop;
|
||||
tp->t_dev = dc->dev;
|
||||
|
||||
dc->tty = tp;
|
||||
tty_makedev(tp, NULL, "%s", name);
|
||||
return(0);
|
||||
}
|
||||
|
||||
@ -631,16 +367,9 @@ dcons_attach(void)
|
||||
{
|
||||
int polltime;
|
||||
|
||||
#ifdef __DragonFly__
|
||||
cdevsw_add(&dcons_cdevsw, -1, 0);
|
||||
#endif
|
||||
dcons_attach_port(DCONS_CON, "dcons", 0);
|
||||
dcons_attach_port(DCONS_GDB, "dgdb", DC_GDB);
|
||||
#if __FreeBSD_version < 500000
|
||||
callout_init(&dcons_callout);
|
||||
#else
|
||||
callout_init(&dcons_callout, 0);
|
||||
#endif
|
||||
polltime = hz / poll_hz;
|
||||
if (polltime < 1)
|
||||
polltime = 1;
|
||||
@ -655,37 +384,14 @@ dcons_detach(int port)
|
||||
struct dcons_softc *dc;
|
||||
|
||||
dc = &sc[port];
|
||||
tp = dc->tty;
|
||||
|
||||
tp = ((DEV)dc->dev)->si_tty;
|
||||
|
||||
if (tp->t_state & TS_ISOPEN) {
|
||||
printf("dcons: still opened\n");
|
||||
#if __FreeBSD_version < 502113
|
||||
(*linesw[tp->t_line].l_close)(tp, 0);
|
||||
tp->t_gen++;
|
||||
ttyclose(tp);
|
||||
ttwakeup(tp);
|
||||
ttwwakeup(tp);
|
||||
#else
|
||||
ttyld_close(tp, 0);
|
||||
tty_close(tp);
|
||||
#endif
|
||||
}
|
||||
/* XXX
|
||||
* must wait until all device are closed.
|
||||
*/
|
||||
#ifdef __DragonFly__
|
||||
tsleep((void *)dc, 0, "dcodtc", hz/4);
|
||||
#else
|
||||
tsleep((void *)dc, PWAIT, "dcodtc", hz/4);
|
||||
#endif
|
||||
destroy_dev(dc->dev);
|
||||
tty_lock(tp);
|
||||
tty_rel_gone(tp);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/* cnXXX works only for FreeBSD-5 */
|
||||
static int
|
||||
dcons_modevent(module_t mode, int type, void *data)
|
||||
{
|
||||
@ -695,29 +401,16 @@ dcons_modevent(module_t mode, int type, void *data)
|
||||
case MOD_LOAD:
|
||||
ret = dcons_drv_init(1);
|
||||
dcons_attach();
|
||||
#if __FreeBSD_version >= 500000
|
||||
if (ret == 0) {
|
||||
dcons_cnprobe(&dcons_consdev);
|
||||
dcons_cninit(&dcons_consdev);
|
||||
cnadd(&dcons_consdev);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case MOD_UNLOAD:
|
||||
printf("dcons: unload\n");
|
||||
callout_stop(&dcons_callout);
|
||||
#if __FreeBSD_version < 502122
|
||||
#if defined(DDB) && DCONS_FORCE_GDB
|
||||
#if CONS_NODEV
|
||||
gdb_arg = NULL;
|
||||
#else
|
||||
gdbdev = NULL;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#if __FreeBSD_version >= 500000
|
||||
cnremove(&dcons_consdev);
|
||||
#endif
|
||||
dcons_detach(DCONS_CON);
|
||||
dcons_detach(DCONS_GDB);
|
||||
dg.buf->magic = 0;
|
||||
@ -737,9 +430,19 @@ dcons_modevent(module_t mode, int type, void *data)
|
||||
return(err);
|
||||
}
|
||||
|
||||
#if defined(GDB) && (__FreeBSD_version >= 502122)
|
||||
#if defined(GDB)
|
||||
/* Debugger interface */
|
||||
|
||||
static int
|
||||
dcons_os_getc(struct dcons_softc *dc)
|
||||
{
|
||||
int c;
|
||||
|
||||
while ((c = dcons_os_checkc(dc)) == -1);
|
||||
|
||||
return (c & 0xff);
|
||||
}
|
||||
|
||||
static int
|
||||
dcons_dbg_probe(void)
|
||||
{
|
||||
|
@ -36,9 +36,6 @@ __FBSDID("$FreeBSD$");
|
||||
* Mighty handy for use with serial console in Vmware
|
||||
*/
|
||||
|
||||
#include "opt_compat.h"
|
||||
#include "opt_tty.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/priv.h>
|
||||
@ -48,252 +45,176 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/limits.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/serial.h>
|
||||
#include <sys/signalvar.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/taskqueue.h>
|
||||
|
||||
MALLOC_DEFINE(M_NLMDM, "nullmodem", "nullmodem data structures");
|
||||
MALLOC_DEFINE(M_NMDM, "nullmodem", "nullmodem data structures");
|
||||
|
||||
static d_close_t nmdmclose;
|
||||
static t_modem_t nmdmmodem;
|
||||
static d_open_t nmdmopen;
|
||||
static t_oproc_t nmdmoproc;
|
||||
static t_param_t nmdmparam;
|
||||
static t_stop_t nmdmstop;
|
||||
static tsw_inwakeup_t nmdm_outwakeup;
|
||||
static tsw_outwakeup_t nmdm_inwakeup;
|
||||
static tsw_param_t nmdm_param;
|
||||
static tsw_modem_t nmdm_modem;
|
||||
|
||||
static struct cdevsw nmdm_cdevsw = {
|
||||
.d_version = D_VERSION,
|
||||
.d_open = nmdmopen,
|
||||
.d_close = nmdmclose,
|
||||
.d_name = "nmdn",
|
||||
.d_flags = D_TTY | D_PSEUDO | D_NEEDGIANT | D_NEEDMINOR,
|
||||
static struct ttydevsw nmdm_class = {
|
||||
.tsw_flags = TF_NOPREFIX,
|
||||
.tsw_inwakeup = nmdm_inwakeup,
|
||||
.tsw_outwakeup = nmdm_outwakeup,
|
||||
.tsw_param = nmdm_param,
|
||||
.tsw_modem = nmdm_modem,
|
||||
};
|
||||
|
||||
#define BUFSIZ 100 /* Chunk size iomoved to/from user */
|
||||
#define NMDM_MAX_NUM 128 /* Artificially limit # devices. */
|
||||
#define PF_STOPPED 0x10 /* user told stopped */
|
||||
#define BFLAG CLONE_FLAG0
|
||||
static void nmdm_task_tty(void *, int);
|
||||
|
||||
struct softpart {
|
||||
struct tty *nm_tty;
|
||||
struct cdev *dev;
|
||||
int nm_dcd;
|
||||
struct task pt_task;
|
||||
struct softpart *other;
|
||||
struct callout co;
|
||||
u_long quota;
|
||||
u_long accumulator;
|
||||
int rate;
|
||||
int credits;
|
||||
struct nmdmsoftc;
|
||||
|
||||
struct nmdmpart {
|
||||
struct tty *np_tty;
|
||||
int np_dcd;
|
||||
struct task np_task;
|
||||
struct nmdmpart *np_other;
|
||||
struct nmdmsoftc *np_pair;
|
||||
struct callout np_callout;
|
||||
u_long np_quota;
|
||||
u_long np_accumulator;
|
||||
int np_rate;
|
||||
int np_credits;
|
||||
|
||||
#define QS 8 /* Quota shift */
|
||||
};
|
||||
|
||||
struct nm_softc {
|
||||
TAILQ_ENTRY(nm_softc) pt_list;
|
||||
int pt_flags;
|
||||
struct softpart part1, part2;
|
||||
struct prison *pt_prison;
|
||||
struct nmdmsoftc {
|
||||
struct nmdmpart ns_part1;
|
||||
struct nmdmpart ns_part2;
|
||||
struct mtx ns_mtx;
|
||||
};
|
||||
|
||||
static struct clonedevs *nmdmclones;
|
||||
static TAILQ_HEAD(,nm_softc) nmdmhead = TAILQ_HEAD_INITIALIZER(nmdmhead);
|
||||
static int nmdm_count = 0;
|
||||
|
||||
static struct nmdmsoftc *
|
||||
nmdm_alloc(unsigned long unit)
|
||||
{
|
||||
struct nmdmsoftc *ns;
|
||||
struct tty *tp;
|
||||
|
||||
atomic_add_acq_int(&nmdm_count, 1);
|
||||
|
||||
ns = malloc(sizeof(*ns), M_NMDM, M_WAITOK|M_ZERO);
|
||||
mtx_init(&ns->ns_mtx, "nmdm", NULL, MTX_DEF);
|
||||
|
||||
/* Hook the pairs together. */
|
||||
ns->ns_part1.np_pair = ns;
|
||||
ns->ns_part1.np_other = &ns->ns_part2;
|
||||
TASK_INIT(&ns->ns_part1.np_task, 0, nmdm_task_tty, &ns->ns_part1);
|
||||
callout_init(&ns->ns_part1.np_callout, 0);
|
||||
|
||||
ns->ns_part2.np_pair = ns;
|
||||
ns->ns_part2.np_other = &ns->ns_part1;
|
||||
TASK_INIT(&ns->ns_part2.np_task, 0, nmdm_task_tty, &ns->ns_part2);
|
||||
callout_init(&ns->ns_part2.np_callout, 0);
|
||||
|
||||
/* Create device nodes. */
|
||||
tp = ns->ns_part1.np_tty = tty_alloc(&nmdm_class, &ns->ns_part1,
|
||||
&ns->ns_mtx);
|
||||
tty_makedev(tp, NULL, "nmdm%luA", unit);
|
||||
|
||||
tp = ns->ns_part2.np_tty = tty_alloc(&nmdm_class, &ns->ns_part2,
|
||||
&ns->ns_mtx);
|
||||
tty_makedev(tp, NULL, "nmdm%luB", unit);
|
||||
|
||||
return (ns);
|
||||
}
|
||||
|
||||
static void
|
||||
nmdm_clone(void *arg, struct ucred *cred, char *name, int nameen,
|
||||
struct cdev **dev)
|
||||
{
|
||||
int i, unit;
|
||||
char *p;
|
||||
struct cdev *d1, *d2;
|
||||
unsigned long unit;
|
||||
char *end;
|
||||
struct nmdmsoftc *ns;
|
||||
|
||||
if (*dev != NULL)
|
||||
return;
|
||||
if (strcmp(name, "nmdm") == 0) {
|
||||
p = NULL;
|
||||
unit = -1;
|
||||
} else {
|
||||
i = dev_stdclone(name, &p, "nmdm", &unit);
|
||||
if (i == 0)
|
||||
return;
|
||||
if (p[0] != '\0' && p[0] != 'A' && p[0] != 'B')
|
||||
return;
|
||||
else if (p[0] != '\0' && p[1] != '\0')
|
||||
return;
|
||||
}
|
||||
i = clone_create(&nmdmclones, &nmdm_cdevsw, &unit, &d1, 0);
|
||||
if (i) {
|
||||
d1 = make_dev(&nmdm_cdevsw, unit2minor(unit),
|
||||
0, 0, 0666, "nmdm%dA", unit);
|
||||
if (d1 == NULL)
|
||||
return;
|
||||
d2 = make_dev(&nmdm_cdevsw, unit2minor(unit) | BFLAG,
|
||||
0, 0, 0666, "nmdm%dB", unit);
|
||||
if (d2 == NULL) {
|
||||
destroy_dev(d1);
|
||||
return;
|
||||
}
|
||||
d2->si_drv2 = d1;
|
||||
d1->si_drv2 = d2;
|
||||
dev_depends(d1, d2);
|
||||
dev_depends(d2, d1);
|
||||
d1->si_flags |= SI_CHEAPCLONE;
|
||||
d2->si_flags |= SI_CHEAPCLONE;
|
||||
}
|
||||
if (p != NULL && p[0] == 'B')
|
||||
*dev = d1->si_drv2;
|
||||
if (strncmp(name, "nmdm", 4) != 0)
|
||||
return;
|
||||
|
||||
/* Device name must be "nmdm%lu%c", where %c is 'A' or 'B'. */
|
||||
name += 4;
|
||||
unit = strtoul(name, &end, 10);
|
||||
if (unit == ULONG_MAX || name == end)
|
||||
return;
|
||||
if ((end[0] != 'A' && end[0] != 'B') || end[1] != '\0')
|
||||
return;
|
||||
|
||||
/* XXX: pass privileges? */
|
||||
ns = nmdm_alloc(unit);
|
||||
|
||||
if (end[0] == 'A')
|
||||
*dev = ns->ns_part1.np_tty->t_dev;
|
||||
else
|
||||
*dev = d1;
|
||||
dev_ref(*dev);
|
||||
*dev = ns->ns_part2.np_tty->t_dev;
|
||||
}
|
||||
|
||||
static void
|
||||
nmdm_timeout(void *arg)
|
||||
{
|
||||
struct softpart *sp;
|
||||
struct nmdmpart *np = arg;
|
||||
|
||||
sp = arg;
|
||||
|
||||
if (sp->rate == 0)
|
||||
if (np->np_rate == 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Do a simple Floyd-Steinberg dither here to avoid FP math.
|
||||
* Wipe out unused quota from last tick.
|
||||
*/
|
||||
sp->accumulator += sp->credits;
|
||||
sp->quota = sp->accumulator >> QS;
|
||||
sp->accumulator &= ((1 << QS) - 1);
|
||||
np->np_accumulator += np->np_credits;
|
||||
np->np_quota = np->np_accumulator >> QS;
|
||||
np->np_accumulator &= ((1 << QS) - 1);
|
||||
|
||||
taskqueue_enqueue(taskqueue_swi_giant, &sp->pt_task);
|
||||
callout_reset(&sp->co, sp->rate, nmdm_timeout, arg);
|
||||
taskqueue_enqueue(taskqueue_swi, &np->np_task);
|
||||
callout_reset(&np->np_callout, np->np_rate, nmdm_timeout, np);
|
||||
}
|
||||
|
||||
static void
|
||||
nmdm_task_tty(void *arg, int pending __unused)
|
||||
{
|
||||
struct tty *tp, *otp;
|
||||
struct softpart *sp;
|
||||
int c;
|
||||
struct nmdmpart *np = arg;
|
||||
char c;
|
||||
|
||||
tp = arg;
|
||||
sp = tp->t_sc;
|
||||
otp = sp->other->nm_tty;
|
||||
tp = np->np_tty;
|
||||
tty_lock(tp);
|
||||
|
||||
otp = np->np_other->np_tty;
|
||||
KASSERT(otp != NULL, ("NULL otp in nmdmstart"));
|
||||
KASSERT(otp != tp, ("NULL otp == tp nmdmstart"));
|
||||
if (sp->other->nm_dcd) {
|
||||
if (!(tp->t_state & TS_ISOPEN)) {
|
||||
sp->other->nm_dcd = 0;
|
||||
(void)ttyld_modem(otp, 0);
|
||||
if (np->np_other->np_dcd) {
|
||||
if (!tty_opened(tp)) {
|
||||
np->np_other->np_dcd = 0;
|
||||
ttydisc_modem(otp, 0);
|
||||
}
|
||||
} else {
|
||||
if (tp->t_state & TS_ISOPEN) {
|
||||
sp->other->nm_dcd = 1;
|
||||
(void)ttyld_modem(otp, 1);
|
||||
if (tty_opened(tp)) {
|
||||
np->np_other->np_dcd = 1;
|
||||
ttydisc_modem(otp, 1);
|
||||
}
|
||||
}
|
||||
if (tp->t_state & TS_TTSTOP)
|
||||
return;
|
||||
while (tp->t_outq.c_cc != 0) {
|
||||
if (sp->rate && !sp->quota)
|
||||
return;
|
||||
if (otp->t_state & TS_TBLOCK)
|
||||
return;
|
||||
sp->quota--;
|
||||
c = getc(&tp->t_outq);
|
||||
if (otp->t_state & TS_ISOPEN)
|
||||
ttyld_rint(otp, c);
|
||||
}
|
||||
if (tp->t_outq.c_cc == 0)
|
||||
ttwwakeup(tp);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* This function creates and initializes a pair of ttys.
|
||||
*/
|
||||
static void
|
||||
nmdminit(struct cdev *dev1)
|
||||
{
|
||||
struct cdev *dev2;
|
||||
struct nm_softc *pt;
|
||||
|
||||
dev2 = dev1->si_drv2;
|
||||
|
||||
dev1->si_flags &= ~SI_CHEAPCLONE;
|
||||
dev2->si_flags &= ~SI_CHEAPCLONE;
|
||||
|
||||
pt = malloc(sizeof(*pt), M_NLMDM, M_WAITOK | M_ZERO);
|
||||
TAILQ_INSERT_TAIL(&nmdmhead, pt, pt_list);
|
||||
|
||||
dev1->si_drv1 = dev2->si_drv1 = pt;
|
||||
|
||||
pt->part1.dev = dev1;
|
||||
pt->part2.dev = dev2;
|
||||
|
||||
pt->part1.nm_tty = ttyalloc();
|
||||
pt->part1.nm_tty->t_oproc = nmdmoproc;
|
||||
pt->part1.nm_tty->t_stop = nmdmstop;
|
||||
pt->part1.nm_tty->t_modem = nmdmmodem;
|
||||
pt->part1.nm_tty->t_param = nmdmparam;
|
||||
pt->part1.nm_tty->t_dev = dev1;
|
||||
pt->part1.nm_tty->t_sc = &pt->part1;
|
||||
TASK_INIT(&pt->part1.pt_task, 0, nmdm_task_tty, pt->part1.nm_tty);
|
||||
callout_init(&pt->part1.co, 0);
|
||||
|
||||
pt->part2.nm_tty = ttyalloc();
|
||||
pt->part2.nm_tty->t_oproc = nmdmoproc;
|
||||
pt->part2.nm_tty->t_stop = nmdmstop;
|
||||
pt->part2.nm_tty->t_modem = nmdmmodem;
|
||||
pt->part2.nm_tty->t_param = nmdmparam;
|
||||
pt->part2.nm_tty->t_dev = dev2;
|
||||
pt->part2.nm_tty->t_sc = &pt->part2;
|
||||
TASK_INIT(&pt->part2.pt_task, 0, nmdm_task_tty, pt->part2.nm_tty);
|
||||
callout_init(&pt->part2.co, 0);
|
||||
|
||||
pt->part1.other = &pt->part2;
|
||||
pt->part2.other = &pt->part1;
|
||||
|
||||
dev1->si_tty = pt->part1.nm_tty;
|
||||
dev1->si_drv1 = pt;
|
||||
|
||||
dev2->si_tty = pt->part2.nm_tty;
|
||||
dev2->si_drv1 = pt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Device opened from userland
|
||||
*/
|
||||
static int
|
||||
nmdmopen(struct cdev *dev, int flag, int devtype, struct thread *td)
|
||||
{
|
||||
struct tty *tp, *tp2;
|
||||
int error;
|
||||
struct nm_softc *pti;
|
||||
struct softpart *sp;
|
||||
|
||||
if (dev->si_drv1 == NULL)
|
||||
nmdminit(dev);
|
||||
pti = dev->si_drv1;
|
||||
if (pti->pt_prison != td->td_ucred->cr_prison)
|
||||
return (EBUSY);
|
||||
|
||||
tp = dev->si_tty;
|
||||
sp = tp->t_sc;
|
||||
tp2 = sp->other->nm_tty;
|
||||
|
||||
if ((tp->t_state & TS_ISOPEN) == 0) {
|
||||
ttyinitmode(tp, 0, 0);
|
||||
ttsetwater(tp); /* XXX ? */
|
||||
} else if (tp->t_state & TS_XCLUDE &&
|
||||
priv_check(td, PRIV_TTY_EXCLUSIVE)) {
|
||||
return (EBUSY);
|
||||
while (ttydisc_rint_poll(otp) > 0) {
|
||||
if (np->np_rate && !np->np_quota)
|
||||
break;
|
||||
if (ttydisc_getc(tp, &c, 1) != 1)
|
||||
break;
|
||||
np->np_quota--;
|
||||
ttydisc_rint(otp, c, 0);
|
||||
}
|
||||
|
||||
error = ttyld_open(tp, dev);
|
||||
return (error);
|
||||
ttydisc_rint_done(otp);
|
||||
|
||||
tty_unlock(tp);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -317,18 +238,17 @@ bits_per_char(struct termios *t)
|
||||
}
|
||||
|
||||
static int
|
||||
nmdmparam(struct tty *tp, struct termios *t)
|
||||
nmdm_param(struct tty *tp, struct termios *t)
|
||||
{
|
||||
struct softpart *sp;
|
||||
struct nmdmpart *np = tty_softc(tp);
|
||||
struct tty *tp2;
|
||||
int bpc, rate, speed, i;
|
||||
|
||||
sp = tp->t_sc;
|
||||
tp2 = sp->other->nm_tty;
|
||||
tp2 = np->np_other->np_tty;
|
||||
|
||||
if (!((t->c_cflag | tp2->t_cflag) & CDSR_OFLOW)) {
|
||||
sp->rate = 0;
|
||||
sp->other->rate = 0;
|
||||
if (!((t->c_cflag | tp2->t_termios.c_cflag) & CDSR_OFLOW)) {
|
||||
np->np_rate = 0;
|
||||
np->np_other->np_rate = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -343,10 +263,10 @@ nmdmparam(struct tty *tp, struct termios *t)
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
/* Use the slower of our receive and their transmit rate */
|
||||
speed = imin(tp2->t_ospeed, t->c_ispeed);
|
||||
speed = imin(tp2->t_termios.c_ospeed, t->c_ispeed);
|
||||
if (speed == 0) {
|
||||
sp->rate = 0;
|
||||
sp->other->rate = 0;
|
||||
np->np_rate = 0;
|
||||
np->np_other->np_rate = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -359,73 +279,63 @@ nmdmparam(struct tty *tp, struct termios *t)
|
||||
speed *= rate;
|
||||
speed /= hz; /* [(char/sec)/tick, scaled */
|
||||
|
||||
sp->credits = speed;
|
||||
sp->rate = rate;
|
||||
callout_reset(&sp->co, rate, nmdm_timeout, sp);
|
||||
np->np_credits = speed;
|
||||
np->np_rate = rate;
|
||||
callout_reset(&np->np_callout, rate, nmdm_timeout, np);
|
||||
|
||||
/*
|
||||
* swap pointers for second pass so the other end gets
|
||||
* updated as well.
|
||||
*/
|
||||
sp = sp->other;
|
||||
np = np->np_other;
|
||||
t = &tp2->t_termios;
|
||||
tp2 = tp;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
nmdmmodem(struct tty *tp, int sigon, int sigoff)
|
||||
nmdm_modem(struct tty *tp, int sigon, int sigoff)
|
||||
{
|
||||
struct softpart *sp;
|
||||
int i;
|
||||
struct nmdmpart *np = tty_softc(tp);
|
||||
int i = 0;
|
||||
|
||||
sp = tp->t_sc;
|
||||
if (sigon || sigoff) {
|
||||
if (sigon & SER_DTR)
|
||||
sp->other->nm_dcd = 1;
|
||||
np->np_other->np_dcd = 1;
|
||||
if (sigoff & SER_DTR)
|
||||
sp->other->nm_dcd = 0;
|
||||
ttyld_modem(sp->other->nm_tty, sp->other->nm_dcd);
|
||||
np->np_other->np_dcd = 0;
|
||||
|
||||
ttydisc_modem(np->np_other->np_tty, np->np_other->np_dcd);
|
||||
|
||||
return (0);
|
||||
} else {
|
||||
i = 0;
|
||||
if (sp->nm_dcd)
|
||||
if (np->np_dcd)
|
||||
i |= SER_DCD;
|
||||
if (sp->other->nm_dcd)
|
||||
if (np->np_other->np_dcd)
|
||||
i |= SER_DTR;
|
||||
|
||||
return (i);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
nmdmclose(struct cdev *dev, int flag, int mode, struct thread *td)
|
||||
static void
|
||||
nmdm_inwakeup(struct tty *tp)
|
||||
{
|
||||
struct tty *tp = dev->si_tty;
|
||||
int error;
|
||||
struct nmdmpart *np = tty_softc(tp);
|
||||
|
||||
error = ttyld_close(tp, flag);
|
||||
(void) tty_close(dev->si_tty);
|
||||
|
||||
return (error);
|
||||
/* We can receive again, so wake up the other side. */
|
||||
taskqueue_enqueue(taskqueue_swi, &np->np_other->np_task);
|
||||
}
|
||||
|
||||
static void
|
||||
nmdmoproc(struct tty *tp)
|
||||
nmdm_outwakeup(struct tty *tp)
|
||||
{
|
||||
struct softpart *pt;
|
||||
struct nmdmpart *np = tty_softc(tp);
|
||||
|
||||
pt = tp->t_sc;
|
||||
taskqueue_enqueue(taskqueue_swi_giant, &pt->pt_task);
|
||||
}
|
||||
|
||||
static void
|
||||
nmdmstop(struct tty *tp, int flush)
|
||||
{
|
||||
struct softpart *pt;
|
||||
|
||||
pt = tp->t_sc;
|
||||
taskqueue_enqueue(taskqueue_swi_giant, &pt->pt_task);
|
||||
/* We can transmit again, so wake up our side. */
|
||||
taskqueue_enqueue(taskqueue_swi, &np->np_task);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -435,32 +345,28 @@ static int
|
||||
nmdm_modevent(module_t mod, int type, void *data)
|
||||
{
|
||||
static eventhandler_tag tag;
|
||||
struct nm_softc *pt, *tpt;
|
||||
int error = 0;
|
||||
|
||||
switch(type) {
|
||||
case MOD_LOAD:
|
||||
clone_setup(&nmdmclones);
|
||||
tag = EVENTHANDLER_REGISTER(dev_clone, nmdm_clone, 0, 1000);
|
||||
if (tag == NULL)
|
||||
return (ENOMEM);
|
||||
break;
|
||||
|
||||
case MOD_SHUTDOWN:
|
||||
/* FALLTHROUGH */
|
||||
case MOD_UNLOAD:
|
||||
EVENTHANDLER_DEREGISTER(dev_clone, tag);
|
||||
TAILQ_FOREACH_SAFE(pt, &nmdmhead, pt_list, tpt) {
|
||||
destroy_dev(pt->part1.dev);
|
||||
TAILQ_REMOVE(&nmdmhead, pt, pt_list);
|
||||
free(pt, M_NLMDM);
|
||||
}
|
||||
clone_cleanup(&nmdmclones);
|
||||
break;
|
||||
|
||||
case MOD_UNLOAD:
|
||||
if (nmdm_count != 0)
|
||||
return (EBUSY);
|
||||
EVENTHANDLER_DEREGISTER(dev_clone, tag);
|
||||
break;
|
||||
|
||||
default:
|
||||
error = EOPNOTSUPP;
|
||||
return (EOPNOTSUPP);
|
||||
}
|
||||
return (error);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
DEV_MODULE(nmdm, nmdm_modevent, NULL);
|
||||
|
@ -49,15 +49,15 @@ __FBSDID("$FreeBSD$");
|
||||
#endif
|
||||
#define OFBURSTLEN 128 /* max number of bytes to write in one chunk */
|
||||
|
||||
static d_open_t ofw_dev_open;
|
||||
static d_close_t ofw_dev_close;
|
||||
static tsw_open_t ofwtty_open;
|
||||
static tsw_close_t ofwtty_close;
|
||||
static tsw_outwakeup_t ofwtty_outwakeup;
|
||||
|
||||
static struct cdevsw ofw_cdevsw = {
|
||||
.d_version = D_VERSION,
|
||||
.d_open = ofw_dev_open,
|
||||
.d_close = ofw_dev_close,
|
||||
.d_name = "ofw",
|
||||
.d_flags = D_TTY | D_NEEDGIANT,
|
||||
static struct ttydevsw ofw_ttydevsw = {
|
||||
.tsw_flags = TF_NOPREFIX,
|
||||
.tsw_open = ofwtty_open,
|
||||
.tsw_close = ofwtty_close,
|
||||
.tsw_outwakeup = ofwtty_outwakeup,
|
||||
};
|
||||
|
||||
static struct tty *ofw_tp = NULL;
|
||||
@ -69,9 +69,6 @@ static struct callout_handle ofw_timeouthandle
|
||||
static int alt_break_state;
|
||||
#endif
|
||||
|
||||
static void ofw_tty_start(struct tty *);
|
||||
static int ofw_tty_param(struct tty *, struct termios *);
|
||||
static void ofw_tty_stop(struct tty *, int);
|
||||
static void ofw_timeout(void *);
|
||||
|
||||
static cn_probe_t ofw_cnprobe;
|
||||
@ -87,7 +84,7 @@ cn_drvinit(void *unused)
|
||||
{
|
||||
phandle_t options;
|
||||
char output[32];
|
||||
struct cdev *dev;
|
||||
struct tty *tp;
|
||||
|
||||
if (ofw_consdev.cn_pri != CN_DEAD &&
|
||||
ofw_consdev.cn_name[0] != '\0') {
|
||||
@ -99,9 +96,9 @@ cn_drvinit(void *unused)
|
||||
* XXX: This is a hack and it may result in two /dev/ttya
|
||||
* XXX: devices on platforms where the sab driver works.
|
||||
*/
|
||||
dev = make_dev(&ofw_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "%s",
|
||||
output);
|
||||
make_dev_alias(dev, "ofwcons");
|
||||
tp = tty_alloc(&ofw_ttydevsw, NULL, NULL);
|
||||
tty_makedev(tp, NULL, "%s", output);
|
||||
tty_makealias(tp, "ofwcons");
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,112 +108,36 @@ static int stdin;
|
||||
static int stdout;
|
||||
|
||||
static int
|
||||
ofw_dev_open(struct cdev *dev, int flag, int mode, struct thread *td)
|
||||
ofwtty_open(struct tty *tp)
|
||||
{
|
||||
struct tty *tp;
|
||||
int unit;
|
||||
int error, setuptimeout;
|
||||
polltime = hz / OFWCONS_POLL_HZ;
|
||||
if (polltime < 1)
|
||||
polltime = 1;
|
||||
|
||||
error = 0;
|
||||
setuptimeout = 0;
|
||||
unit = minor(dev);
|
||||
ofw_timeouthandle = timeout(ofw_timeout, tp, polltime);
|
||||
|
||||
/*
|
||||
* XXX: BAD, should happen at attach time
|
||||
*/
|
||||
if (dev->si_tty == NULL) {
|
||||
ofw_tp = ttyalloc();
|
||||
dev->si_tty = ofw_tp;
|
||||
ofw_tp->t_dev = dev;
|
||||
}
|
||||
tp = dev->si_tty;
|
||||
|
||||
tp->t_oproc = ofw_tty_start;
|
||||
tp->t_param = ofw_tty_param;
|
||||
tp->t_stop = ofw_tty_stop;
|
||||
tp->t_dev = dev;
|
||||
|
||||
if ((tp->t_state & TS_ISOPEN) == 0) {
|
||||
tp->t_state |= TS_CARR_ON;
|
||||
ttyconsolemode(tp, 0);
|
||||
|
||||
setuptimeout = 1;
|
||||
} else if ((tp->t_state & TS_XCLUDE) &&
|
||||
priv_check(td, PRIV_TTY_EXCLUSIVE)) {
|
||||
return (EBUSY);
|
||||
}
|
||||
|
||||
error = ttyld_open(tp, dev);
|
||||
|
||||
if (error == 0 && setuptimeout) {
|
||||
polltime = hz / OFWCONS_POLL_HZ;
|
||||
if (polltime < 1) {
|
||||
polltime = 1;
|
||||
}
|
||||
|
||||
ofw_timeouthandle = timeout(ofw_timeout, tp, polltime);
|
||||
}
|
||||
|
||||
return (error);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ofw_dev_close(struct cdev *dev, int flag, int mode, struct thread *td)
|
||||
static void
|
||||
ofwtty_close(struct tty *tp)
|
||||
{
|
||||
int unit;
|
||||
struct tty *tp;
|
||||
|
||||
unit = minor(dev);
|
||||
tp = dev->si_tty;
|
||||
|
||||
if (unit != 0) {
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* XXX Should be replaced with callout_stop(9) */
|
||||
untimeout(ofw_timeout, tp, ofw_timeouthandle);
|
||||
ttyld_close(tp, flag);
|
||||
tty_close(tp);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ofw_tty_param(struct tty *tp, struct termios *t)
|
||||
{
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
ofw_tty_start(struct tty *tp)
|
||||
ofwtty_outwakeup(struct tty *tp)
|
||||
{
|
||||
struct clist *cl;
|
||||
int len;
|
||||
u_char buf[OFBURSTLEN];
|
||||
|
||||
|
||||
if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
|
||||
return;
|
||||
|
||||
tp->t_state |= TS_BUSY;
|
||||
cl = &tp->t_outq;
|
||||
len = q_to_b(cl, buf, OFBURSTLEN);
|
||||
OF_write(stdout, buf, len);
|
||||
tp->t_state &= ~TS_BUSY;
|
||||
|
||||
ttwwakeup(tp);
|
||||
}
|
||||
|
||||
static void
|
||||
ofw_tty_stop(struct tty *tp, int flag)
|
||||
{
|
||||
|
||||
if (tp->t_state & TS_BUSY) {
|
||||
if ((tp->t_state & TS_TTSTOP) == 0) {
|
||||
tp->t_state |= TS_FLUSH;
|
||||
}
|
||||
for (;;) {
|
||||
len = ttydisc_getc(tp, buf, sizeof buf);
|
||||
if (len == 0)
|
||||
break;
|
||||
OF_write(stdout, buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,11 +149,11 @@ ofw_timeout(void *v)
|
||||
|
||||
tp = (struct tty *)v;
|
||||
|
||||
while ((c = ofw_cngetc(NULL)) != -1) {
|
||||
if (tp->t_state & TS_ISOPEN) {
|
||||
ttyld_rint(tp, c);
|
||||
}
|
||||
}
|
||||
tty_lock(tp);
|
||||
while ((c = ofw_cngetc(NULL)) != -1)
|
||||
ttydisc_rint(tp, c, 0);
|
||||
ttydisc_rint_done(tp);
|
||||
tty_unlock(tp);
|
||||
|
||||
ofw_timeouthandle = timeout(ofw_timeout, tp, polltime);
|
||||
}
|
||||
|
@ -291,8 +291,7 @@ sc_hist_down_line(scr_stat *scp)
|
||||
}
|
||||
|
||||
int
|
||||
sc_hist_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
|
||||
struct thread *td)
|
||||
sc_hist_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
|
||||
{
|
||||
scr_stat *scp;
|
||||
int error;
|
||||
@ -300,7 +299,7 @@ sc_hist_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
|
||||
switch (cmd) {
|
||||
|
||||
case CONS_HISTORY: /* set history size */
|
||||
scp = SC_STAT(tp->t_dev);
|
||||
scp = SC_STAT(tp);
|
||||
if (*(int *)data <= 0)
|
||||
return EINVAL;
|
||||
if (scp->status & BUFFER_SAVED)
|
||||
@ -315,7 +314,7 @@ sc_hist_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
|
||||
return error;
|
||||
|
||||
case CONS_CLRHIST:
|
||||
scp = SC_STAT(tp->t_dev);
|
||||
scp = SC_STAT(tp);
|
||||
sc_vtb_clear(scp->history, scp->sc->scr_map[0x20],
|
||||
SC_NORM_ATTR << 8);
|
||||
return 0;
|
||||
|
@ -605,8 +605,7 @@ sc_mouse_paste(scr_stat *scp)
|
||||
#endif /* SC_NO_CUTPASTE */
|
||||
|
||||
int
|
||||
sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
|
||||
struct thread *td)
|
||||
sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
|
||||
{
|
||||
mouse_info_t *mouse;
|
||||
mouse_info_t buf;
|
||||
@ -616,7 +615,7 @@ sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
|
||||
int s;
|
||||
int f;
|
||||
|
||||
scp = SC_STAT(tp->t_dev);
|
||||
scp = SC_STAT(tp);
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
|
@ -705,7 +705,7 @@ scterm_puts(scr_stat *scp, u_char *buf, int len)
|
||||
|
||||
static int
|
||||
scterm_ioctl(scr_stat *scp, struct tty *tp, u_long cmd, caddr_t data,
|
||||
int flag, struct thread *td)
|
||||
struct thread *td)
|
||||
{
|
||||
term_stat *tcp = scp->ts;
|
||||
vid_info_t *vi;
|
||||
|
@ -48,19 +48,15 @@ __FBSDID("$FreeBSD$");
|
||||
#include <dev/fb/fbreg.h>
|
||||
#include <dev/syscons/syscons.h>
|
||||
|
||||
static d_ioctl_t *prev_user_ioctl;
|
||||
static tsw_ioctl_t *prev_user_ioctl;
|
||||
|
||||
static int
|
||||
vesa_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
vesa_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
|
||||
{
|
||||
scr_stat *scp;
|
||||
struct tty *tp;
|
||||
int mode;
|
||||
|
||||
tp = dev->si_tty;
|
||||
if (!tp)
|
||||
return ENXIO;
|
||||
scp = SC_STAT(tp->t_dev);
|
||||
scp = SC_STAT(tp);
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
@ -123,7 +119,7 @@ vesa_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *
|
||||
}
|
||||
|
||||
if (prev_user_ioctl)
|
||||
return (*prev_user_ioctl)(dev, cmd, data, flag, td);
|
||||
return (*prev_user_ioctl)(tp, cmd, data, td);
|
||||
else
|
||||
return ENOIOCTL;
|
||||
}
|
||||
|
@ -241,11 +241,8 @@ sc_set_text_mode(scr_stat *scp, struct tty *tp, int mode, int xsize, int ysize,
|
||||
|| tp->t_winsize.ws_row != scp->ysize) {
|
||||
tp->t_winsize.ws_col = scp->xsize;
|
||||
tp->t_winsize.ws_row = scp->ysize;
|
||||
if (tp->t_pgrp != NULL) {
|
||||
PGRP_LOCK(tp->t_pgrp);
|
||||
pgsignal(tp->t_pgrp, SIGWINCH, 1);
|
||||
PGRP_UNLOCK(tp->t_pgrp);
|
||||
}
|
||||
|
||||
tty_signal_pgrp(tp, SIGWINCH);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -308,11 +305,8 @@ sc_set_graphics_mode(scr_stat *scp, struct tty *tp, int mode)
|
||||
|| tp->t_winsize.ws_ypixel != scp->ypixel) {
|
||||
tp->t_winsize.ws_xpixel = scp->xpixel;
|
||||
tp->t_winsize.ws_ypixel = scp->ypixel;
|
||||
if (tp->t_pgrp != NULL) {
|
||||
PGRP_LOCK(tp->t_pgrp);
|
||||
pgsignal(tp->t_pgrp, SIGWINCH, 1);
|
||||
PGRP_UNLOCK(tp->t_pgrp);
|
||||
}
|
||||
|
||||
tty_signal_pgrp(tp, SIGWINCH);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -475,7 +469,7 @@ sc_set_pixel_mode(scr_stat *scp, struct tty *tp, int xsize, int ysize,
|
||||
vidd_ioctl((a), (c), (caddr_t)(d)))
|
||||
|
||||
int
|
||||
sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
|
||||
{
|
||||
scr_stat *scp;
|
||||
video_adapter_t *adp;
|
||||
@ -488,7 +482,7 @@ sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct thread *
|
||||
int ival;
|
||||
#endif
|
||||
|
||||
scp = SC_STAT(tp->t_dev);
|
||||
scp = SC_STAT(tp);
|
||||
if (scp == NULL) /* tp == SC_MOUSE */
|
||||
return ENOIOCTL;
|
||||
adp = scp->sc->adp;
|
||||
|
@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/proc.h>
|
||||
#include <sys/random.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/serial.h>
|
||||
#include <sys/signalvar.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/tty.h>
|
||||
@ -69,6 +70,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <machine/psl.h>
|
||||
#include <machine/frame.h>
|
||||
#endif
|
||||
#include <machine/stdarg.h>
|
||||
|
||||
#include <dev/kbd/kbdreg.h>
|
||||
#include <dev/fb/fbreg.h>
|
||||
@ -105,7 +107,7 @@ static struct tty *sc_console_tty;
|
||||
static struct consdev *sc_consptr;
|
||||
static void *kernel_console_ts;
|
||||
static scr_stat main_console;
|
||||
static struct cdev *main_devs[MAXCONS];
|
||||
static struct tty *main_devs[MAXCONS];
|
||||
|
||||
static char init_done = COLD;
|
||||
static char shutdown_in_progress = FALSE;
|
||||
@ -150,7 +152,7 @@ SYSCTL_INT(_hw_syscons, OID_AUTO, kbd_debug, CTLFLAG_RW|CTLFLAG_SECURE, &enable_
|
||||
#include "font.h"
|
||||
#endif
|
||||
|
||||
d_ioctl_t *sc_user_ioctl;
|
||||
tsw_ioctl_t *sc_user_ioctl;
|
||||
|
||||
static bios_values_t bios_value;
|
||||
|
||||
@ -161,24 +163,18 @@ SYSCTL_INT(_machdep, OID_AUTO, enable_panic_key, CTLFLAG_RW, &enable_panic_key,
|
||||
#define SC_CONSOLECTL 255
|
||||
|
||||
#define VTY_WCHAN(sc, vty) (&SC_DEV(sc, vty))
|
||||
#define VIRTUAL_TTY(sc, x) (SC_DEV((sc), (x)) != NULL ? \
|
||||
SC_DEV((sc), (x))->si_tty : NULL)
|
||||
#define ISTTYOPEN(tp) ((tp) && ((tp)->t_state & TS_ISOPEN))
|
||||
|
||||
static int debugger;
|
||||
|
||||
/* prototypes */
|
||||
static int sc_allocate_keyboard(sc_softc_t *sc, int unit);
|
||||
static struct tty *sc_alloc_tty(struct cdev *dev);
|
||||
static int scvidprobe(int unit, int flags, int cons);
|
||||
static int sckbdprobe(int unit, int flags, int cons);
|
||||
static void scmeminit(void *arg);
|
||||
static int scdevtounit(struct cdev *dev);
|
||||
static int scdevtounit(struct tty *tp);
|
||||
static kbd_callback_func_t sckbdevent;
|
||||
static int scparam(struct tty *tp, struct termios *t);
|
||||
static void scstart(struct tty *tp);
|
||||
static void scinit(int unit, int flags);
|
||||
static scr_stat *sc_get_stat(struct cdev *devptr);
|
||||
static scr_stat *sc_get_stat(struct tty *tp);
|
||||
static void scterm(int unit, int flags);
|
||||
static void scshutdown(void *arg, int howto);
|
||||
static u_int scgetc(sc_softc_t *sc, u_int flags);
|
||||
@ -219,6 +215,7 @@ static int save_kbd_state(scr_stat *scp);
|
||||
static int update_kbd_state(scr_stat *scp, int state, int mask);
|
||||
static int update_kbd_leds(scr_stat *scp, int which);
|
||||
static timeout_t blink_screen;
|
||||
static struct tty *sc_alloc_tty(int, const char *, ...) __printflike(2, 3);
|
||||
|
||||
static cn_probe_t sc_cnprobe;
|
||||
static cn_init_t sc_cninit;
|
||||
@ -228,21 +225,23 @@ static cn_putc_t sc_cnputc;
|
||||
|
||||
CONSOLE_DRIVER(sc);
|
||||
|
||||
static d_open_t scopen;
|
||||
static d_close_t scclose;
|
||||
static d_read_t scread;
|
||||
static d_ioctl_t scioctl;
|
||||
static d_mmap_t scmmap;
|
||||
static tsw_open_t sctty_open;
|
||||
static tsw_close_t sctty_close;
|
||||
static tsw_outwakeup_t sctty_outwakeup;
|
||||
static tsw_ioctl_t sctty_ioctl;
|
||||
static tsw_mmap_t sctty_mmap;
|
||||
|
||||
static struct cdevsw sc_cdevsw = {
|
||||
.d_version = D_VERSION,
|
||||
.d_open = scopen,
|
||||
.d_close = scclose,
|
||||
.d_read = scread,
|
||||
.d_ioctl = scioctl,
|
||||
.d_mmap = scmmap,
|
||||
.d_name = "sc",
|
||||
.d_flags = D_TTY | D_NEEDGIANT,
|
||||
static struct ttydevsw sc_ttydevsw = {
|
||||
/*
|
||||
* XXX: we should use the prefix, but this doesn't work for
|
||||
* consolectl.
|
||||
*/
|
||||
.tsw_flags = TF_NOPREFIX,
|
||||
.tsw_open = sctty_open,
|
||||
.tsw_close = sctty_close,
|
||||
.tsw_outwakeup = sctty_outwakeup,
|
||||
.tsw_ioctl = sctty_ioctl,
|
||||
.tsw_mmap = sctty_mmap,
|
||||
};
|
||||
|
||||
int
|
||||
@ -310,17 +309,47 @@ static char
|
||||
return names[i].name[(adp->va_flags & V_ADP_COLOR) ? 0 : 1];
|
||||
}
|
||||
|
||||
static struct tty *
|
||||
sc_alloc_tty(struct cdev *dev)
|
||||
static void
|
||||
sctty_outwakeup(struct tty *tp)
|
||||
{
|
||||
struct tty *tp;
|
||||
size_t len;
|
||||
u_char buf[PCBURST];
|
||||
scr_stat *scp = sc_get_stat(tp);
|
||||
|
||||
if (scp->status & SLKED ||
|
||||
(scp == scp->sc->cur_scp && scp->sc->blink_in_progress))
|
||||
return;
|
||||
|
||||
for (;;) {
|
||||
len = ttydisc_getc(tp, buf, sizeof buf);
|
||||
if (len == 0)
|
||||
break;
|
||||
sc_puts(scp, buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
static struct tty *
|
||||
sc_alloc_tty(int index, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
struct sc_ttysoftc *stc;
|
||||
struct tty *tp;
|
||||
char name[11]; /* "consolectl" */
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
/* Allocate TTY object and softc to store unit number. */
|
||||
stc = malloc(sizeof(struct sc_ttysoftc), M_DEVBUF, M_WAITOK);
|
||||
stc->st_index = index;
|
||||
stc->st_stat = NULL;
|
||||
tp = tty_alloc(&sc_ttydevsw, stc, &Giant);
|
||||
|
||||
/* Create device node. */
|
||||
va_start(ap, fmt);
|
||||
vsnrprintf(name, sizeof name, 32, fmt, ap);
|
||||
va_end(ap);
|
||||
tty_makedev(tp, NULL, "%s", name);
|
||||
|
||||
tp = dev->si_tty = ttyalloc();
|
||||
ttyinitmode(tp, 1, 0);
|
||||
tp->t_oproc = scstart;
|
||||
tp->t_param = scparam;
|
||||
tp->t_stop = nottystop;
|
||||
tp->t_dev = dev;
|
||||
return (tp);
|
||||
}
|
||||
|
||||
@ -333,7 +362,6 @@ sc_attach_unit(int unit, int flags)
|
||||
video_info_t info;
|
||||
#endif
|
||||
int vc;
|
||||
struct cdev *dev;
|
||||
|
||||
flags &= ~SC_KERNEL_CONSOLE;
|
||||
|
||||
@ -418,9 +446,7 @@ sc_attach_unit(int unit, int flags)
|
||||
|
||||
for (vc = 0; vc < sc->vtys; vc++) {
|
||||
if (sc->dev[vc] == NULL) {
|
||||
sc->dev[vc] = make_dev(&sc_cdevsw, vc + unit * MAXCONS,
|
||||
UID_ROOT, GID_WHEEL, 0600, "ttyv%r", vc + unit * MAXCONS);
|
||||
sc_alloc_tty(sc->dev[vc]);
|
||||
sc->dev[vc] = sc_alloc_tty(vc, "ttyv%r", vc + unit * MAXCONS);
|
||||
if (vc == 0 && sc->dev == main_devs)
|
||||
SC_STAT(sc->dev[0]) = &main_console;
|
||||
}
|
||||
@ -431,11 +457,8 @@ sc_attach_unit(int unit, int flags)
|
||||
*/
|
||||
}
|
||||
|
||||
dev = make_dev(&sc_cdevsw, SC_CONSOLECTL,
|
||||
UID_ROOT, GID_WHEEL, 0600, "consolectl");
|
||||
sc_console_tty = sc_alloc_tty(dev);
|
||||
ttyconsolemode(sc_console_tty, 0);
|
||||
SC_STAT(dev) = sc_console;
|
||||
sc_console_tty = sc_alloc_tty(0, "consolectl");
|
||||
SC_STAT(sc_console_tty) = sc_console;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -472,9 +495,9 @@ scmeminit(void *arg)
|
||||
SYSINIT(sc_mem, SI_SUB_KMEM, SI_ORDER_ANY, scmeminit, NULL);
|
||||
|
||||
static int
|
||||
scdevtounit(struct cdev *dev)
|
||||
scdevtounit(struct tty *tp)
|
||||
{
|
||||
int vty = SC_VTY(dev);
|
||||
int vty = SC_VTY(tp);
|
||||
|
||||
if (vty == SC_CONSOLECTL)
|
||||
return ((sc_console != NULL) ? sc_console->sc->unit : -1);
|
||||
@ -485,48 +508,37 @@ scdevtounit(struct cdev *dev)
|
||||
}
|
||||
|
||||
static int
|
||||
scopen(struct cdev *dev, int flag, int mode, struct thread *td)
|
||||
sctty_open(struct tty *tp)
|
||||
{
|
||||
int unit = scdevtounit(dev);
|
||||
int unit = scdevtounit(tp);
|
||||
sc_softc_t *sc;
|
||||
struct tty *tp;
|
||||
scr_stat *scp;
|
||||
#ifndef __sparc64__
|
||||
keyarg_t key;
|
||||
#endif
|
||||
int error;
|
||||
|
||||
DPRINTF(5, ("scopen: dev:%s, unit:%d, vty:%d\n",
|
||||
devtoname(dev), unit, SC_VTY(dev)));
|
||||
devtoname(tp->t_dev), unit, SC_VTY(tp)));
|
||||
|
||||
tp = dev->si_tty;
|
||||
sc = sc_get_softc(unit, (sc_console_unit == unit) ? SC_KERNEL_CONSOLE : 0);
|
||||
if (sc == NULL)
|
||||
return ENXIO;
|
||||
|
||||
if (!ISTTYOPEN(tp)) {
|
||||
tp->t_termios = tp->t_init_in;
|
||||
if (!tty_opened(tp)) {
|
||||
/* Use the current setting of the <-- key as default VERASE. */
|
||||
/* If the Delete key is preferable, an stty is necessary */
|
||||
#ifndef __sparc64__
|
||||
if (sc->kbd != NULL) {
|
||||
key.keynum = KEYCODE_BS;
|
||||
kbdd_ioctl(sc->kbd, GIO_KEYMAPENT, (caddr_t)&key);
|
||||
tp->t_cc[VERASE] = key.key.map[0];
|
||||
tp->t_termios.c_cc[VERASE] = key.key.map[0];
|
||||
}
|
||||
#endif
|
||||
scparam(tp, &tp->t_termios);
|
||||
ttyld_modem(tp, 1);
|
||||
}
|
||||
else
|
||||
if (tp->t_state & TS_XCLUDE && priv_check(td, PRIV_TTY_EXCLUSIVE))
|
||||
return(EBUSY);
|
||||
|
||||
error = ttyld_open(tp, dev);
|
||||
|
||||
scp = sc_get_stat(dev);
|
||||
scp = sc_get_stat(tp);
|
||||
if (scp == NULL) {
|
||||
scp = SC_STAT(dev) = alloc_scp(sc, SC_VTY(dev));
|
||||
scp = SC_STAT(tp) = alloc_scp(sc, SC_VTY(tp));
|
||||
if (ISGRAPHSC(scp))
|
||||
sc_set_pixel_mode(scp, NULL, COL, ROW, 16, 8);
|
||||
}
|
||||
@ -535,18 +547,17 @@ scopen(struct cdev *dev, int flag, int mode, struct thread *td)
|
||||
tp->t_winsize.ws_row = scp->ysize;
|
||||
}
|
||||
|
||||
return error;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
scclose(struct cdev *dev, int flag, int mode, struct thread *td)
|
||||
static void
|
||||
sctty_close(struct tty *tp)
|
||||
{
|
||||
struct tty *tp = dev->si_tty;
|
||||
scr_stat *scp;
|
||||
int s;
|
||||
|
||||
if (SC_VTY(dev) != SC_CONSOLECTL) {
|
||||
scp = sc_get_stat(tp->t_dev);
|
||||
if (SC_VTY(tp) != SC_CONSOLECTL) {
|
||||
scp = sc_get_stat(tp);
|
||||
/* were we in the middle of the VT switching process? */
|
||||
DPRINTF(5, ("sc%d: scclose(), ", scp->sc->unit));
|
||||
s = spltty();
|
||||
@ -568,7 +579,7 @@ scclose(struct cdev *dev, int flag, int mode, struct thread *td)
|
||||
sc_vtb_destroy(&scp->scr);
|
||||
#endif
|
||||
sc_free_history_buffer(scp, scp->ysize);
|
||||
SC_STAT(dev) = NULL;
|
||||
SC_STAT(tp) = NULL;
|
||||
free(scp, M_DEVBUF);
|
||||
}
|
||||
#else
|
||||
@ -581,13 +592,9 @@ scclose(struct cdev *dev, int flag, int mode, struct thread *td)
|
||||
kbdd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
|
||||
DPRINTF(5, ("done.\n"));
|
||||
}
|
||||
spltty();
|
||||
ttyld_close(tp, flag);
|
||||
tty_close(tp);
|
||||
spl0();
|
||||
return(0);
|
||||
}
|
||||
|
||||
#if 0 /* XXX mpsafetty: fix screensaver. What about outwakeup? */
|
||||
static int
|
||||
scread(struct cdev *dev, struct uio *uio, int flag)
|
||||
{
|
||||
@ -595,19 +602,22 @@ scread(struct cdev *dev, struct uio *uio, int flag)
|
||||
sc_touch_scrn_saver();
|
||||
return ttyread(dev, uio, flag);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
sckbdevent(keyboard_t *thiskbd, int event, void *arg)
|
||||
{
|
||||
sc_softc_t *sc;
|
||||
struct tty *cur_tty;
|
||||
int c;
|
||||
int c, error = 0;
|
||||
size_t len;
|
||||
u_char *cp;
|
||||
|
||||
sc = (sc_softc_t *)arg;
|
||||
/* assert(thiskbd == sc->kbd) */
|
||||
|
||||
mtx_lock(&Giant);
|
||||
|
||||
switch (event) {
|
||||
case KBDIO_KEYINPUT:
|
||||
break;
|
||||
@ -615,9 +625,10 @@ sckbdevent(keyboard_t *thiskbd, int event, void *arg)
|
||||
sc->kbd = NULL;
|
||||
sc->keyboard = -1;
|
||||
kbd_release(thiskbd, (void *)&sc->keyboard);
|
||||
return 0;
|
||||
goto done;
|
||||
default:
|
||||
return EINVAL;
|
||||
error = EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -627,10 +638,12 @@ sckbdevent(keyboard_t *thiskbd, int event, void *arg)
|
||||
*/
|
||||
while ((c = scgetc(sc, SCGETC_NONBLOCK)) != NOKEY) {
|
||||
|
||||
cur_tty = VIRTUAL_TTY(sc, sc->cur_scp->index);
|
||||
if (!ISTTYOPEN(cur_tty)) {
|
||||
cur_tty = SC_DEV(sc, sc->cur_scp->index);
|
||||
if (!tty_opened(cur_tty)) {
|
||||
cur_tty = sc_console_tty;
|
||||
if (!ISTTYOPEN(cur_tty))
|
||||
if (cur_tty == NULL)
|
||||
continue;
|
||||
if (!tty_opened(cur_tty))
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -639,47 +652,45 @@ sckbdevent(keyboard_t *thiskbd, int event, void *arg)
|
||||
|
||||
switch (KEYFLAGS(c)) {
|
||||
case 0x0000: /* normal key */
|
||||
ttyld_rint(cur_tty, KEYCHAR(c));
|
||||
ttydisc_rint(cur_tty, KEYCHAR(c), 0);
|
||||
break;
|
||||
case FKEY: /* function key, return string */
|
||||
cp = kbdd_get_fkeystr(thiskbd, KEYCHAR(c), &len);
|
||||
if (cp != NULL) {
|
||||
while (len-- > 0)
|
||||
ttyld_rint(cur_tty, *cp++);
|
||||
if (ttydisc_can_bypass(cur_tty)) {
|
||||
ttydisc_rint_bypass(cur_tty, cp, len);
|
||||
} else {
|
||||
while (len-- > 0)
|
||||
ttydisc_rint(cur_tty, *cp++, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MKEY: /* meta is active, prepend ESC */
|
||||
ttyld_rint(cur_tty, 0x1b);
|
||||
ttyld_rint(cur_tty, KEYCHAR(c));
|
||||
ttydisc_rint(cur_tty, 0x1b, 0);
|
||||
ttydisc_rint(cur_tty, KEYCHAR(c), 0);
|
||||
break;
|
||||
case BKEY: /* backtab fixed sequence (esc [ Z) */
|
||||
ttyld_rint(cur_tty, 0x1b);
|
||||
ttyld_rint(cur_tty, '[');
|
||||
ttyld_rint(cur_tty, 'Z');
|
||||
ttydisc_rint(cur_tty, 0x1b, 0);
|
||||
ttydisc_rint(cur_tty, '[', 0);
|
||||
ttydisc_rint(cur_tty, 'Z', 0);
|
||||
break;
|
||||
}
|
||||
|
||||
ttydisc_rint_done(cur_tty);
|
||||
}
|
||||
|
||||
sc->cur_scp->status |= MOUSE_HIDDEN;
|
||||
|
||||
return 0;
|
||||
done:
|
||||
mtx_unlock(&Giant);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
scparam(struct tty *tp, struct termios *t)
|
||||
{
|
||||
tp->t_ispeed = t->c_ispeed;
|
||||
tp->t_ospeed = t->c_ospeed;
|
||||
tp->t_cflag = t->c_cflag;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
scioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
sctty_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
|
||||
{
|
||||
int error;
|
||||
int i;
|
||||
struct tty *tp;
|
||||
sc_softc_t *sc;
|
||||
scr_stat *scp;
|
||||
int s;
|
||||
@ -688,38 +699,36 @@ scioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
int ival;
|
||||
#endif
|
||||
|
||||
tp = dev->si_tty;
|
||||
|
||||
/* If there is a user_ioctl function call that first */
|
||||
if (sc_user_ioctl) {
|
||||
error = (*sc_user_ioctl)(dev, cmd, data, flag, td);
|
||||
error = (*sc_user_ioctl)(tp, cmd, data, td);
|
||||
if (error != ENOIOCTL)
|
||||
return error;
|
||||
}
|
||||
|
||||
error = sc_vid_ioctl(tp, cmd, data, flag, td);
|
||||
error = sc_vid_ioctl(tp, cmd, data, td);
|
||||
if (error != ENOIOCTL)
|
||||
return error;
|
||||
|
||||
#ifndef SC_NO_HISTORY
|
||||
error = sc_hist_ioctl(tp, cmd, data, flag, td);
|
||||
error = sc_hist_ioctl(tp, cmd, data, td);
|
||||
if (error != ENOIOCTL)
|
||||
return error;
|
||||
#endif
|
||||
|
||||
#ifndef SC_NO_SYSMOUSE
|
||||
error = sc_mouse_ioctl(tp, cmd, data, flag, td);
|
||||
error = sc_mouse_ioctl(tp, cmd, data, td);
|
||||
if (error != ENOIOCTL)
|
||||
return error;
|
||||
#endif
|
||||
|
||||
scp = sc_get_stat(tp->t_dev);
|
||||
scp = sc_get_stat(tp);
|
||||
/* assert(scp != NULL) */
|
||||
/* scp is sc_console, if SC_VTY(dev) == SC_CONSOLECTL. */
|
||||
sc = scp->sc;
|
||||
|
||||
if (scp->tsw) {
|
||||
error = (*scp->tsw->te_ioctl)(scp, tp, cmd, data, flag, td);
|
||||
error = (*scp->tsw->te_ioctl)(scp, tp, cmd, data, td);
|
||||
if (error != ENOIOCTL)
|
||||
return error;
|
||||
}
|
||||
@ -1031,8 +1040,8 @@ scioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
|
||||
case VT_OPENQRY: /* return free virtual console */
|
||||
for (i = sc->first_vty; i < sc->first_vty + sc->vtys; i++) {
|
||||
tp = VIRTUAL_TTY(sc, i);
|
||||
if (!ISTTYOPEN(tp)) {
|
||||
tp = SC_DEV(sc, i);
|
||||
if (!tty_opened(tp)) {
|
||||
*(int *)data = i + 1;
|
||||
return 0;
|
||||
}
|
||||
@ -1053,7 +1062,8 @@ scioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
splx(s);
|
||||
if (error)
|
||||
return error;
|
||||
return sc_switch_scr(sc, i);
|
||||
error = sc_switch_scr(sc, i);
|
||||
return (error);
|
||||
|
||||
#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
|
||||
defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
|
||||
@ -1441,34 +1451,7 @@ scioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
break;
|
||||
}
|
||||
|
||||
return (ttyioctl(dev, cmd, data, flag, td));
|
||||
}
|
||||
|
||||
static void
|
||||
scstart(struct tty *tp)
|
||||
{
|
||||
struct clist *rbp;
|
||||
int s, len;
|
||||
u_char buf[PCBURST];
|
||||
scr_stat *scp = sc_get_stat(tp->t_dev);
|
||||
|
||||
if (scp->status & SLKED ||
|
||||
(scp == scp->sc->cur_scp && scp->sc->blink_in_progress))
|
||||
return;
|
||||
s = spltty();
|
||||
if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
|
||||
tp->t_state |= TS_BUSY;
|
||||
rbp = &tp->t_outq;
|
||||
while (rbp->c_cc) {
|
||||
len = q_to_b(rbp, buf, PCBURST);
|
||||
splx(s);
|
||||
sc_puts(scp, buf, len);
|
||||
s = spltty();
|
||||
}
|
||||
tp->t_state &= ~TS_BUSY;
|
||||
ttwwakeup(tp);
|
||||
}
|
||||
splx(s);
|
||||
return (ENOIOCTL);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1548,9 +1531,11 @@ sc_cnputc(struct consdev *cd, int c)
|
||||
scp->status |= CURSOR_ENABLED;
|
||||
sc_draw_cursor_image(scp);
|
||||
}
|
||||
tp = VIRTUAL_TTY(scp->sc, scp->index);
|
||||
if (ISTTYOPEN(tp))
|
||||
scstart(tp);
|
||||
tp = SC_DEV(scp->sc, scp->index);
|
||||
tty_lock(tp);
|
||||
if (tty_opened(tp))
|
||||
sctty_outwakeup(tp);
|
||||
tty_unlock(tp);
|
||||
}
|
||||
#endif /* !SC_NO_HISTORY */
|
||||
|
||||
@ -2281,9 +2266,9 @@ sc_switch_scr(sc_softc_t *sc, u_int next_scr)
|
||||
* if the switch mode is VT_AUTO, unless the next vty is the same
|
||||
* as the current or the current vty has been closed (but showing).
|
||||
*/
|
||||
tp = VIRTUAL_TTY(sc, cur_scp->index);
|
||||
tp = SC_DEV(sc, cur_scp->index);
|
||||
if ((cur_scp->index != next_scr)
|
||||
&& ISTTYOPEN(tp)
|
||||
&& tty_opened(tp)
|
||||
&& (cur_scp->smode.mode == VT_AUTO)
|
||||
&& ISGRAPHSC(cur_scp)) {
|
||||
splx(s);
|
||||
@ -2299,14 +2284,14 @@ sc_switch_scr(sc_softc_t *sc, u_int next_scr)
|
||||
* console even if it is closed.
|
||||
*/
|
||||
if ((sc_console == NULL) || (next_scr != sc_console->index)) {
|
||||
tp = VIRTUAL_TTY(sc, next_scr);
|
||||
if (!ISTTYOPEN(tp)) {
|
||||
tp = SC_DEV(sc, next_scr);
|
||||
if (!tty_opened(tp)) {
|
||||
splx(s);
|
||||
sc_bell(cur_scp, bios_value.bell_pitch, BELL_DURATION);
|
||||
DPRINTF(5, ("error 2, requested vty isn't open!\n"));
|
||||
return EINVAL;
|
||||
}
|
||||
if ((debugger > 0) && (SC_STAT(tp->t_dev)->smode.mode == VT_PROCESS)) {
|
||||
if ((debugger > 0) && (SC_STAT(tp)->smode.mode == VT_PROCESS)) {
|
||||
splx(s);
|
||||
DPRINTF(5, ("error 3, requested vty is in the VT_PROCESS mode\n"));
|
||||
return EINVAL;
|
||||
@ -2609,7 +2594,7 @@ void
|
||||
sc_change_cursor_shape(scr_stat *scp, int flags, int base, int height)
|
||||
{
|
||||
sc_softc_t *sc;
|
||||
struct cdev *dev;
|
||||
struct tty *tp;
|
||||
int s;
|
||||
int i;
|
||||
|
||||
@ -2635,9 +2620,9 @@ sc_change_cursor_shape(scr_stat *scp, int flags, int base, int height)
|
||||
}
|
||||
|
||||
for (i = sc->first_vty; i < sc->first_vty + sc->vtys; ++i) {
|
||||
if ((dev = SC_DEV(sc, i)) == NULL)
|
||||
if ((tp = SC_DEV(sc, i)) == NULL)
|
||||
continue;
|
||||
if ((scp = sc_get_stat(dev)) == NULL)
|
||||
if ((scp = sc_get_stat(tp)) == NULL)
|
||||
continue;
|
||||
scp->dflt_curs_attr = sc->curs_attr;
|
||||
change_cursor_shape(scp, CONS_RESET_CURSOR, -1, -1);
|
||||
@ -2759,10 +2744,9 @@ scinit(int unit, int flags)
|
||||
kernel_default.rev_color);
|
||||
} else {
|
||||
/* assert(sc_malloc) */
|
||||
sc->dev = malloc(sizeof(struct cdev *)*sc->vtys, M_DEVBUF, M_WAITOK|M_ZERO);
|
||||
sc->dev[0] = make_dev(&sc_cdevsw, unit * MAXCONS,
|
||||
UID_ROOT, GID_WHEEL, 0600, "ttyv%r", unit * MAXCONS);
|
||||
sc_alloc_tty(sc->dev[0]);
|
||||
sc->dev = malloc(sizeof(struct tty *)*sc->vtys, M_DEVBUF,
|
||||
M_WAITOK|M_ZERO);
|
||||
sc->dev[0] = sc_alloc_tty(0, "ttyv%r", unit * MAXCONS);
|
||||
scp = alloc_scp(sc, sc->first_vty);
|
||||
SC_STAT(sc->dev[0]) = scp;
|
||||
}
|
||||
@ -3287,9 +3271,9 @@ scgetc(sc_softc_t *sc, u_int flags)
|
||||
scp->status |= CURSOR_ENABLED;
|
||||
sc_draw_cursor_image(scp);
|
||||
}
|
||||
tp = VIRTUAL_TTY(sc, scp->index);
|
||||
if (ISTTYOPEN(tp))
|
||||
scstart(tp);
|
||||
tp = SC_DEV(sc, scp->index);
|
||||
if (tty_opened(tp))
|
||||
sctty_outwakeup(tp);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@ -3382,8 +3366,8 @@ scgetc(sc_softc_t *sc, u_int flags)
|
||||
for (i = (this_scr - sc->first_vty + 1)%sc->vtys;
|
||||
sc->first_vty + i != this_scr;
|
||||
i = (i + 1)%sc->vtys) {
|
||||
struct tty *tp = VIRTUAL_TTY(sc, sc->first_vty + i);
|
||||
if (ISTTYOPEN(tp)) {
|
||||
struct tty *tp = SC_DEV(sc, sc->first_vty + i);
|
||||
if (tty_opened(tp)) {
|
||||
sc_switch_scr(scp->sc, sc->first_vty + i);
|
||||
break;
|
||||
}
|
||||
@ -3395,8 +3379,8 @@ scgetc(sc_softc_t *sc, u_int flags)
|
||||
for (i = (this_scr - sc->first_vty + sc->vtys - 1)%sc->vtys;
|
||||
sc->first_vty + i != this_scr;
|
||||
i = (i + sc->vtys - 1)%sc->vtys) {
|
||||
struct tty *tp = VIRTUAL_TTY(sc, sc->first_vty + i);
|
||||
if (ISTTYOPEN(tp)) {
|
||||
struct tty *tp = SC_DEV(sc, sc->first_vty + i);
|
||||
if (tty_opened(tp)) {
|
||||
sc_switch_scr(scp->sc, sc->first_vty + i);
|
||||
break;
|
||||
}
|
||||
@ -3425,11 +3409,11 @@ scgetc(sc_softc_t *sc, u_int flags)
|
||||
}
|
||||
|
||||
static int
|
||||
scmmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
|
||||
sctty_mmap(struct tty *tp, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
|
||||
{
|
||||
scr_stat *scp;
|
||||
|
||||
scp = sc_get_stat(dev);
|
||||
scp = sc_get_stat(tp);
|
||||
if (scp != scp->sc->cur_scp)
|
||||
return -1;
|
||||
return vidd_mmap(scp->sc->adp, offset, paddr, nprot);
|
||||
@ -3586,12 +3570,13 @@ sc_paste(scr_stat *scp, u_char *p, int count)
|
||||
struct tty *tp;
|
||||
u_char *rmap;
|
||||
|
||||
tp = VIRTUAL_TTY(scp->sc, scp->sc->cur_scp->index);
|
||||
if (!ISTTYOPEN(tp))
|
||||
tp = SC_DEV(scp->sc, scp->sc->cur_scp->index);
|
||||
if (!tty_opened(tp))
|
||||
return;
|
||||
rmap = scp->sc->scr_rmap;
|
||||
for (; count > 0; --count)
|
||||
ttyld_rint(tp, rmap[*p++]);
|
||||
ttydisc_rint(tp, rmap[*p++], 0);
|
||||
ttydisc_rint_done(tp);
|
||||
}
|
||||
|
||||
void
|
||||
@ -3626,9 +3611,9 @@ blink_screen(void *arg)
|
||||
if (ISGRAPHSC(scp) || (scp->sc->blink_in_progress <= 1)) {
|
||||
scp->sc->blink_in_progress = 0;
|
||||
mark_all(scp);
|
||||
tp = VIRTUAL_TTY(scp->sc, scp->index);
|
||||
if (ISTTYOPEN(tp))
|
||||
scstart(tp);
|
||||
tp = SC_DEV(scp->sc, scp->index);
|
||||
if (tty_opened(tp))
|
||||
sctty_outwakeup(tp);
|
||||
if (scp->sc->delayed_next_scr)
|
||||
sc_switch_scr(scp->sc, scp->sc->delayed_next_scr - 1);
|
||||
}
|
||||
@ -3650,11 +3635,11 @@ blink_screen(void *arg)
|
||||
*/
|
||||
|
||||
static scr_stat *
|
||||
sc_get_stat(struct cdev *devptr)
|
||||
sc_get_stat(struct tty *tp)
|
||||
{
|
||||
if (devptr == NULL)
|
||||
if (tp == NULL)
|
||||
return (&main_console);
|
||||
return (SC_STAT(devptr));
|
||||
return (SC_STAT(tp));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -102,9 +102,9 @@
|
||||
*/
|
||||
#define SC_DRIVER_NAME "syscons"
|
||||
#endif
|
||||
#define SC_VTY(dev) minor(dev)
|
||||
#define SC_VTY(dev) (((sc_ttysoftc *)tty_softc(tp))->st_index)
|
||||
#define SC_DEV(sc, vty) ((sc)->dev[(vty) - (sc)->first_vty])
|
||||
#define SC_STAT(dev) (*((scr_stat **)&(dev)->si_drv1))
|
||||
#define SC_STAT(tp) (*((scr_stat **)&((sc_ttysoftc *)tty_softc(tp))->st_stat))
|
||||
|
||||
/* printable chars */
|
||||
#ifndef PRINTABLE
|
||||
@ -220,7 +220,7 @@ typedef struct sc_softc {
|
||||
|
||||
int first_vty;
|
||||
int vtys;
|
||||
struct cdev **dev;
|
||||
struct tty **dev;
|
||||
struct scr_stat *cur_scp;
|
||||
struct scr_stat *new_scp;
|
||||
struct scr_stat *old_scp;
|
||||
@ -339,6 +339,12 @@ typedef struct scr_stat {
|
||||
#endif
|
||||
} scr_stat;
|
||||
|
||||
/* TTY softc. */
|
||||
typedef struct sc_ttysoftc {
|
||||
int st_index;
|
||||
scr_stat *st_stat;
|
||||
} sc_ttysoftc;
|
||||
|
||||
#ifndef SC_NORM_ATTR
|
||||
#define SC_NORM_ATTR (FG_LIGHTGREY | BG_BLACK)
|
||||
#endif
|
||||
@ -364,7 +370,7 @@ typedef int sc_term_init_t(scr_stat *scp, void **tcp, int code);
|
||||
typedef int sc_term_term_t(scr_stat *scp, void **tcp);
|
||||
typedef void sc_term_puts_t(scr_stat *scp, u_char *buf, int len);
|
||||
typedef int sc_term_ioctl_t(scr_stat *scp, struct tty *tp, u_long cmd,
|
||||
caddr_t data, int flag, struct thread *td);
|
||||
caddr_t data, struct thread *td);
|
||||
typedef int sc_term_reset_t(scr_stat *scp, int code);
|
||||
#define SC_TE_HARD_RESET 0
|
||||
#define SC_TE_SOFT_RESET 1
|
||||
@ -531,8 +537,8 @@ typedef struct {
|
||||
} while(0)
|
||||
|
||||
/* syscons.c */
|
||||
extern int (*sc_user_ioctl)(struct cdev *dev, u_long cmd, caddr_t data,
|
||||
int flag, struct thread *td);
|
||||
extern int (*sc_user_ioctl)(struct tty *tp, u_long cmd, caddr_t data,
|
||||
struct thread *td);
|
||||
|
||||
int sc_probe_unit(int unit, int flags);
|
||||
int sc_attach_unit(int unit, int flags);
|
||||
@ -574,7 +580,7 @@ void sc_hist_end(scr_stat *scp);
|
||||
int sc_hist_up_line(scr_stat *scp);
|
||||
int sc_hist_down_line(scr_stat *scp);
|
||||
int sc_hist_ioctl(struct tty *tp, u_long cmd, caddr_t data,
|
||||
int flag, struct thread *td);
|
||||
struct thread *td);
|
||||
#endif /* SC_NO_HISTORY */
|
||||
|
||||
/* scmouse.c */
|
||||
@ -599,7 +605,7 @@ void sc_mouse_paste(scr_stat *scp);
|
||||
#ifndef SC_NO_SYSMOUSE
|
||||
void sc_mouse_move(scr_stat *scp, int x, int y);
|
||||
int sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data,
|
||||
int flag, struct thread *td);
|
||||
struct thread *td);
|
||||
#endif /* SC_NO_SYSMOUSE */
|
||||
|
||||
/* scvidctl.c */
|
||||
@ -609,7 +615,7 @@ int sc_set_text_mode(scr_stat *scp, struct tty *tp, int mode,
|
||||
int sc_set_graphics_mode(scr_stat *scp, struct tty *tp, int mode);
|
||||
int sc_set_pixel_mode(scr_stat *scp, struct tty *tp, int xsize,
|
||||
int ysize, int fontsize, int font_width);
|
||||
int sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
|
||||
int sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data,
|
||||
struct thread *td);
|
||||
|
||||
int sc_render_add(sc_renderer_t *rndr);
|
||||
|
@ -32,8 +32,8 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/priv.h>
|
||||
#include <sys/serial.h>
|
||||
#include <sys/tty.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/consio.h>
|
||||
@ -45,106 +45,24 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#define SC_MOUSE 128 /* minor number */
|
||||
|
||||
static d_open_t smopen;
|
||||
static d_close_t smclose;
|
||||
static d_ioctl_t smioctl;
|
||||
|
||||
static struct cdevsw sm_cdevsw = {
|
||||
.d_version = D_VERSION,
|
||||
.d_open = smopen,
|
||||
.d_close = smclose,
|
||||
.d_ioctl = smioctl,
|
||||
.d_name = "sysmouse",
|
||||
.d_flags = D_TTY | D_NEEDGIANT,
|
||||
};
|
||||
|
||||
/* local variables */
|
||||
static struct tty *sysmouse_tty;
|
||||
static int mouse_level; /* sysmouse protocol level */
|
||||
static mousestatus_t mouse_status;
|
||||
|
||||
static void smstart(struct tty *tp);
|
||||
static int smparam(struct tty *tp, struct termios *t);
|
||||
|
||||
static int
|
||||
smopen(struct cdev *dev, int flag, int mode, struct thread *td)
|
||||
{
|
||||
struct tty *tp;
|
||||
|
||||
DPRINTF(5, ("smopen: dev:%s, vty:%d\n",
|
||||
devtoname(dev), SC_VTY(dev)));
|
||||
|
||||
#if 0
|
||||
if (SC_VTY(dev) != SC_MOUSE)
|
||||
return ENXIO;
|
||||
#endif
|
||||
|
||||
tp = dev->si_tty;
|
||||
if (!(tp->t_state & TS_ISOPEN)) {
|
||||
ttyinitmode(tp, 0, 0);
|
||||
smparam(tp, &tp->t_termios);
|
||||
ttyld_modem(tp, 1);
|
||||
} else if (tp->t_state & TS_XCLUDE &&
|
||||
priv_check(td, PRIV_TTY_EXCLUSIVE)) {
|
||||
return EBUSY;
|
||||
}
|
||||
|
||||
return ttyld_open(tp, dev);
|
||||
}
|
||||
|
||||
static int
|
||||
smclose(struct cdev *dev, int flag, int mode, struct thread *td)
|
||||
{
|
||||
struct tty *tp;
|
||||
int s;
|
||||
|
||||
tp = dev->si_tty;
|
||||
s = spltty();
|
||||
mouse_level = 0;
|
||||
ttyld_close(tp, flag);
|
||||
tty_close(tp);
|
||||
splx(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
smstart(struct tty *tp)
|
||||
smdev_close(struct tty *tp)
|
||||
{
|
||||
struct clist *rbp;
|
||||
u_char buf[PCBURST];
|
||||
int s;
|
||||
|
||||
s = spltty();
|
||||
if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
|
||||
tp->t_state |= TS_BUSY;
|
||||
rbp = &tp->t_outq;
|
||||
while (rbp->c_cc)
|
||||
q_to_b(rbp, buf, PCBURST);
|
||||
tp->t_state &= ~TS_BUSY;
|
||||
ttwwakeup(tp);
|
||||
}
|
||||
splx(s);
|
||||
mouse_level = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
smparam(struct tty *tp, struct termios *t)
|
||||
smdev_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
|
||||
{
|
||||
tp->t_ispeed = t->c_ispeed;
|
||||
tp->t_ospeed = t->c_ospeed;
|
||||
tp->t_cflag = t->c_cflag;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
smioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
{
|
||||
struct tty *tp;
|
||||
mousehw_t *hw;
|
||||
mousemode_t *mode;
|
||||
int s;
|
||||
|
||||
tp = dev->si_tty;
|
||||
switch (cmd) {
|
||||
|
||||
case MOUSE_GETHWINFO: /* get device information */
|
||||
@ -224,25 +142,35 @@ smioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
return ENODEV;
|
||||
}
|
||||
|
||||
return(ttyioctl(dev, cmd, data, flag, td));
|
||||
return (ENOIOCTL);
|
||||
}
|
||||
|
||||
static int
|
||||
smdev_param(struct tty *tp, struct termios *t)
|
||||
{
|
||||
|
||||
/*
|
||||
* Set the output baud rate to zero. The mouse device supports
|
||||
* no output, so we don't want to waste buffers.
|
||||
*/
|
||||
t->c_ispeed = TTYDEF_SPEED_PSEUDO;
|
||||
t->c_ospeed = B0;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static struct ttydevsw smdev_ttydevsw = {
|
||||
.tsw_flags = TF_NOPREFIX,
|
||||
.tsw_close = smdev_close,
|
||||
.tsw_ioctl = smdev_ioctl,
|
||||
.tsw_param = smdev_param,
|
||||
};
|
||||
|
||||
static void
|
||||
sm_attach_mouse(void *unused)
|
||||
{
|
||||
struct cdev *dev;
|
||||
struct tty *tp;
|
||||
|
||||
dev = make_dev(&sm_cdevsw, SC_MOUSE, UID_ROOT, GID_WHEEL, 0600,
|
||||
"sysmouse");
|
||||
dev->si_tty = tp = ttyalloc();
|
||||
tp->t_oproc = smstart;
|
||||
tp->t_param = smparam;
|
||||
tp->t_stop = nottystop;
|
||||
tp->t_dev = dev;
|
||||
|
||||
sysmouse_tty = tp;
|
||||
/* sysmouse doesn't have scr_stat */
|
||||
sysmouse_tty = tty_alloc(&smdev_ttydevsw, NULL, &Giant);
|
||||
tty_makedev(sysmouse_tty, NULL, "sysmouse");
|
||||
}
|
||||
|
||||
SYSINIT(sysmouse, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, sm_attach_mouse, NULL);
|
||||
@ -293,7 +221,7 @@ sysmouse_event(mouse_info_t *info)
|
||||
if (mouse_status.flags == 0)
|
||||
return 0;
|
||||
|
||||
if ((sysmouse_tty == NULL) || !(sysmouse_tty->t_state & TS_ISOPEN))
|
||||
if ((sysmouse_tty == NULL) || !tty_opened(sysmouse_tty))
|
||||
return mouse_status.flags;
|
||||
|
||||
/* the first five bytes are compatible with MouseSystems' */
|
||||
@ -306,7 +234,7 @@ sysmouse_event(mouse_info_t *info)
|
||||
buf[2] = y >> 1;
|
||||
buf[4] = y - buf[2];
|
||||
for (i = 0; i < MOUSE_MSC_PACKETSIZE; ++i)
|
||||
ttyld_rint(sysmouse_tty, buf[i]);
|
||||
ttydisc_rint(sysmouse_tty, buf[i], 0);
|
||||
if (mouse_level >= 1) {
|
||||
/* extended part */
|
||||
z = imax(imin(z, 127), -128);
|
||||
@ -315,8 +243,9 @@ sysmouse_event(mouse_info_t *info)
|
||||
/* buttons 4-10 */
|
||||
buf[7] = (~mouse_status.button >> 3) & 0x7f;
|
||||
for (i = MOUSE_MSC_PACKETSIZE; i < MOUSE_SYS_PACKETSIZE; ++i)
|
||||
ttyld_rint(sysmouse_tty, buf[i]);
|
||||
ttydisc_rint(sysmouse_tty, buf[i], 0);
|
||||
}
|
||||
ttydisc_rint_done(sysmouse_tty);
|
||||
|
||||
return mouse_status.flags;
|
||||
}
|
||||
|
@ -46,7 +46,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <machine/bus.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/termios.h>
|
||||
#include <sys/tty.h>
|
||||
#include <machine/resource.h>
|
||||
#include <machine/stdarg.h>
|
||||
|
||||
@ -466,7 +465,7 @@ uart_bus_attach(device_t dev)
|
||||
sc->sc_polled = 1;
|
||||
}
|
||||
|
||||
sc->sc_rxbufsz = IBUFSIZ;
|
||||
sc->sc_rxbufsz = 384;
|
||||
sc->sc_rxbuf = malloc(sc->sc_rxbufsz * sizeof(*sc->sc_rxbuf),
|
||||
M_UART, M_WAITOK);
|
||||
sc->sc_txbuf = malloc(sc->sc_txfifosz * sizeof(*sc->sc_txbuf),
|
||||
|
@ -123,11 +123,11 @@ uart_cngetc(struct consdev *cp)
|
||||
}
|
||||
|
||||
static int
|
||||
uart_tty_open(struct tty *tp, struct cdev *dev)
|
||||
uart_tty_open(struct tty *tp)
|
||||
{
|
||||
struct uart_softc *sc;
|
||||
|
||||
sc = tp->t_sc;
|
||||
sc = tty_softc(tp);
|
||||
|
||||
if (sc == NULL || sc->sc_leaving)
|
||||
return (ENXIO);
|
||||
@ -141,7 +141,7 @@ uart_tty_close(struct tty *tp)
|
||||
{
|
||||
struct uart_softc *sc;
|
||||
|
||||
sc = tp->t_sc;
|
||||
sc = tty_softc(tp);
|
||||
if (sc == NULL || sc->sc_leaving || !sc->sc_opened)
|
||||
return;
|
||||
|
||||
@ -158,11 +158,11 @@ uart_tty_close(struct tty *tp)
|
||||
}
|
||||
|
||||
static void
|
||||
uart_tty_oproc(struct tty *tp)
|
||||
uart_tty_outwakeup(struct tty *tp)
|
||||
{
|
||||
struct uart_softc *sc;
|
||||
|
||||
sc = tp->t_sc;
|
||||
sc = tty_softc(tp);
|
||||
if (sc == NULL || sc->sc_leaving)
|
||||
return;
|
||||
|
||||
@ -173,30 +173,45 @@ uart_tty_oproc(struct tty *tp)
|
||||
* de-assert RTS for us. In that situation we're completely stuffed.
|
||||
* Without hardware support, we need to toggle RTS ourselves.
|
||||
*/
|
||||
if ((tp->t_cflag & CRTS_IFLOW) && !sc->sc_hwiflow) {
|
||||
if ((tp->t_state & TS_TBLOCK) &&
|
||||
if ((tp->t_termios.c_cflag & CRTS_IFLOW) && !sc->sc_hwiflow) {
|
||||
#if 0
|
||||
/*if ((tp->t_state & TS_TBLOCK) &&
|
||||
(sc->sc_hwsig & SER_RTS))
|
||||
UART_SETSIG(sc, SER_DRTS);
|
||||
else if (!(tp->t_state & TS_TBLOCK) &&
|
||||
else */ if (/*!(tp->t_state & TS_TBLOCK) &&*/
|
||||
!(sc->sc_hwsig & SER_RTS))
|
||||
UART_SETSIG(sc, SER_DRTS|SER_RTS);
|
||||
#endif
|
||||
/* XXX: we should use inwakeup to implement this! */
|
||||
if (!(sc->sc_hwsig & SER_RTS))
|
||||
UART_SETSIG(sc, SER_DRTS|SER_RTS);
|
||||
}
|
||||
|
||||
if (tp->t_state & TS_TTSTOP)
|
||||
if (sc->sc_txbusy)
|
||||
return;
|
||||
|
||||
if ((tp->t_state & TS_BUSY) || sc->sc_txbusy)
|
||||
return;
|
||||
sc->sc_txdatasz = ttydisc_getc(tp, sc->sc_txbuf, sc->sc_txfifosz);
|
||||
if (sc->sc_txdatasz != 0)
|
||||
UART_TRANSMIT(sc);
|
||||
}
|
||||
|
||||
if (tp->t_outq.c_cc == 0) {
|
||||
ttwwakeup(tp);
|
||||
return;
|
||||
static int
|
||||
uart_tty_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
|
||||
{
|
||||
struct uart_softc *sc;
|
||||
|
||||
sc = tty_softc(tp);
|
||||
|
||||
switch (cmd) {
|
||||
case TIOCSBRK:
|
||||
UART_IOCTL(sc, UART_IOCTL_BREAK, 1);
|
||||
return (0);
|
||||
case TIOCCBRK:
|
||||
UART_IOCTL(sc, UART_IOCTL_BREAK, 0);
|
||||
return (0);
|
||||
default:
|
||||
return pps_ioctl(cmd, data, &sc->sc_pps);
|
||||
}
|
||||
|
||||
sc->sc_txdatasz = q_to_b(&tp->t_outq, sc->sc_txbuf, sc->sc_txfifosz);
|
||||
tp->t_state |= TS_BUSY;
|
||||
UART_TRANSMIT(sc);
|
||||
ttwwakeup(tp);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -205,7 +220,7 @@ uart_tty_param(struct tty *tp, struct termios *t)
|
||||
struct uart_softc *sc;
|
||||
int databits, parity, stopbits;
|
||||
|
||||
sc = tp->t_sc;
|
||||
sc = tty_softc(tp);
|
||||
if (sc == NULL || sc->sc_leaving)
|
||||
return (ENODEV);
|
||||
if (t->c_ispeed != t->c_ospeed && t->c_ospeed != 0)
|
||||
@ -237,16 +252,16 @@ uart_tty_param(struct tty *tp, struct termios *t)
|
||||
UART_SETSIG(sc, SER_DDTR | SER_DTR);
|
||||
/* Set input flow control state. */
|
||||
if (!sc->sc_hwiflow) {
|
||||
if ((t->c_cflag & CRTS_IFLOW) && (tp->t_state & TS_TBLOCK))
|
||||
/* if ((t->c_cflag & CRTS_IFLOW) && (tp->t_state & TS_TBLOCK))
|
||||
UART_SETSIG(sc, SER_DRTS);
|
||||
else
|
||||
else */
|
||||
UART_SETSIG(sc, SER_DRTS | SER_RTS);
|
||||
} else
|
||||
UART_IOCTL(sc, UART_IOCTL_IFLOW, (t->c_cflag & CRTS_IFLOW));
|
||||
/* Set output flow control state. */
|
||||
if (sc->sc_hwoflow)
|
||||
UART_IOCTL(sc, UART_IOCTL_OFLOW, (t->c_cflag & CCTS_OFLOW));
|
||||
ttsetwater(tp);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -255,48 +270,18 @@ uart_tty_modem(struct tty *tp, int biton, int bitoff)
|
||||
{
|
||||
struct uart_softc *sc;
|
||||
|
||||
sc = tp->t_sc;
|
||||
sc = tty_softc(tp);
|
||||
if (biton != 0 || bitoff != 0)
|
||||
UART_SETSIG(sc, SER_DELTA(bitoff|biton) | biton);
|
||||
return (sc->sc_hwsig);
|
||||
}
|
||||
|
||||
static void
|
||||
uart_tty_break(struct tty *tp, int state)
|
||||
{
|
||||
struct uart_softc *sc;
|
||||
|
||||
sc = tp->t_sc;
|
||||
UART_IOCTL(sc, UART_IOCTL_BREAK, state);
|
||||
}
|
||||
|
||||
static void
|
||||
uart_tty_stop(struct tty *tp, int rw)
|
||||
{
|
||||
struct uart_softc *sc;
|
||||
|
||||
sc = tp->t_sc;
|
||||
if (sc == NULL || sc->sc_leaving)
|
||||
return;
|
||||
if (rw & FWRITE) {
|
||||
if (sc->sc_txbusy) {
|
||||
sc->sc_txbusy = 0;
|
||||
UART_FLUSH(sc, UART_FLUSH_TRANSMITTER);
|
||||
}
|
||||
tp->t_state &= ~TS_BUSY;
|
||||
}
|
||||
if (rw & FREAD) {
|
||||
UART_FLUSH(sc, UART_FLUSH_RECEIVER);
|
||||
sc->sc_rxget = sc->sc_rxput = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
uart_tty_intr(void *arg)
|
||||
{
|
||||
struct uart_softc *sc = arg;
|
||||
struct tty *tp;
|
||||
int c, pend, sig, xc;
|
||||
int c, err = 0, pend, sig, xc;
|
||||
|
||||
if (sc->sc_leaving)
|
||||
return;
|
||||
@ -306,78 +291,72 @@ uart_tty_intr(void *arg)
|
||||
return;
|
||||
|
||||
tp = sc->sc_u.u_tty.tp;
|
||||
tty_lock(tp);
|
||||
|
||||
if (pend & SER_INT_RXREADY) {
|
||||
while (!uart_rx_empty(sc) && !(tp->t_state & TS_TBLOCK)) {
|
||||
while (!uart_rx_empty(sc) /* && !(tp->t_state & TS_TBLOCK)*/) {
|
||||
xc = uart_rx_get(sc);
|
||||
c = xc & 0xff;
|
||||
if (xc & UART_STAT_FRAMERR)
|
||||
c |= TTY_FE;
|
||||
err |= TRE_FRAMING;
|
||||
if (xc & UART_STAT_OVERRUN)
|
||||
c |= TTY_OE;
|
||||
err |= TRE_OVERRUN;
|
||||
if (xc & UART_STAT_PARERR)
|
||||
c |= TTY_PE;
|
||||
ttyld_rint(tp, c);
|
||||
err |= TRE_PARITY;
|
||||
ttydisc_rint(tp, c, err);
|
||||
}
|
||||
}
|
||||
|
||||
if (pend & SER_INT_BREAK) {
|
||||
if (tp != NULL && !(tp->t_iflag & IGNBRK))
|
||||
ttyld_rint(tp, 0);
|
||||
}
|
||||
if (pend & SER_INT_BREAK)
|
||||
ttydisc_rint(tp, 0, TRE_BREAK);
|
||||
|
||||
if (pend & SER_INT_SIGCHG) {
|
||||
sig = pend & SER_INT_SIGMASK;
|
||||
if (sig & SER_DDCD)
|
||||
ttyld_modem(tp, sig & SER_DCD);
|
||||
if ((sig & SER_DCTS) && (tp->t_cflag & CCTS_OFLOW) &&
|
||||
ttydisc_modem(tp, sig & SER_DCD);
|
||||
if ((sig & SER_DCTS) && (tp->t_termios.c_cflag & CCTS_OFLOW) &&
|
||||
!sc->sc_hwoflow) {
|
||||
if (sig & SER_CTS) {
|
||||
tp->t_state &= ~TS_TTSTOP;
|
||||
ttyld_start(tp);
|
||||
} else
|
||||
tp->t_state |= TS_TTSTOP;
|
||||
if (sig & SER_CTS)
|
||||
uart_tty_outwakeup(tp);
|
||||
}
|
||||
}
|
||||
|
||||
if (pend & SER_INT_TXIDLE) {
|
||||
tp->t_state &= ~TS_BUSY;
|
||||
ttyld_start(tp);
|
||||
}
|
||||
if (pend & SER_INT_TXIDLE)
|
||||
uart_tty_outwakeup(tp);
|
||||
ttydisc_rint_done(tp);
|
||||
tty_unlock(tp);
|
||||
}
|
||||
|
||||
static struct ttydevsw uart_tty_class = {
|
||||
.tsw_flags = TF_INITLOCK|TF_CALLOUT,
|
||||
.tsw_open = uart_tty_open,
|
||||
.tsw_close = uart_tty_close,
|
||||
.tsw_outwakeup = uart_tty_outwakeup,
|
||||
.tsw_ioctl = uart_tty_ioctl,
|
||||
.tsw_param = uart_tty_param,
|
||||
.tsw_modem = uart_tty_modem,
|
||||
};
|
||||
|
||||
int
|
||||
uart_tty_attach(struct uart_softc *sc)
|
||||
{
|
||||
struct tty *tp;
|
||||
int unit;
|
||||
|
||||
tp = ttyalloc();
|
||||
sc->sc_u.u_tty.tp = tp;
|
||||
tp->t_sc = sc;
|
||||
sc->sc_u.u_tty.tp = tp = tty_alloc(&uart_tty_class, sc, NULL);
|
||||
|
||||
unit = device_get_unit(sc->sc_dev);
|
||||
|
||||
tp->t_oproc = uart_tty_oproc;
|
||||
tp->t_param = uart_tty_param;
|
||||
tp->t_stop = uart_tty_stop;
|
||||
tp->t_modem = uart_tty_modem;
|
||||
tp->t_break = uart_tty_break;
|
||||
tp->t_open = uart_tty_open;
|
||||
tp->t_close = uart_tty_close;
|
||||
|
||||
tp->t_pps = &sc->sc_pps;
|
||||
|
||||
if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) {
|
||||
sprintf(((struct consdev *)sc->sc_sysdev->cookie)->cn_name,
|
||||
"ttyu%r", unit);
|
||||
ttyconsolemode(tp, 0);
|
||||
tty_init_console(tp, 0);
|
||||
}
|
||||
|
||||
swi_add(&tty_intr_event, uart_driver_name, uart_tty_intr, sc, SWI_TTY,
|
||||
INTR_TYPE_TTY, &sc->sc_softih);
|
||||
|
||||
ttycreate(tp, TS_CALLOUT, "u%r", unit);
|
||||
tty_makedev(tp, NULL, "u%r", unit);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -387,10 +366,10 @@ int uart_tty_detach(struct uart_softc *sc)
|
||||
struct tty *tp;
|
||||
|
||||
tp = sc->sc_u.u_tty.tp;
|
||||
tp->t_pps = NULL;
|
||||
ttygone(tp);
|
||||
|
||||
tty_lock(tp);
|
||||
swi_remove(sc->sc_softih);
|
||||
ttyfree(tp);
|
||||
tty_rel_gone(tp);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -116,22 +116,33 @@ SYSCTL_INT(_hw_usb_ucom, OID_AUTO, debug, CTLFLAG_RW,
|
||||
|
||||
static int ucom_modevent(module_t, int, void *);
|
||||
static void ucom_cleanup(struct ucom_softc *);
|
||||
static int ucomparam(struct tty *, struct termios *);
|
||||
static void ucomstart(struct tty *);
|
||||
static void ucomstop(struct tty *, int);
|
||||
static void ucom_shutdown(struct ucom_softc *);
|
||||
static void ucom_dtr(struct ucom_softc *, int);
|
||||
static void ucom_rts(struct ucom_softc *, int);
|
||||
static void ucombreak(struct tty *, int);
|
||||
static void ucombreak(struct ucom_softc *, int);
|
||||
static usbd_status ucomstartread(struct ucom_softc *);
|
||||
static void ucomreadcb(usbd_xfer_handle, usbd_private_handle, usbd_status);
|
||||
static void ucomwritecb(usbd_xfer_handle, usbd_private_handle, usbd_status);
|
||||
static void ucomstopread(struct ucom_softc *);
|
||||
|
||||
static t_open_t ucomopen;
|
||||
static t_close_t ucomclose;
|
||||
static t_modem_t ucommodem;
|
||||
static t_ioctl_t ucomioctl;
|
||||
static tsw_open_t ucomtty_open;
|
||||
static tsw_close_t ucomtty_close;
|
||||
static tsw_outwakeup_t ucomtty_outwakeup;
|
||||
static tsw_ioctl_t ucomtty_ioctl;
|
||||
static tsw_param_t ucomtty_param;
|
||||
static tsw_modem_t ucomtty_modem;
|
||||
static tsw_free_t ucomtty_free;
|
||||
|
||||
static struct ttydevsw ucomtty_class = {
|
||||
.tsw_flags = TF_INITLOCK|TF_CALLOUT,
|
||||
.tsw_open = ucomtty_open,
|
||||
.tsw_close = ucomtty_close,
|
||||
.tsw_outwakeup = ucomtty_outwakeup,
|
||||
.tsw_ioctl = ucomtty_ioctl,
|
||||
.tsw_param = ucomtty_param,
|
||||
.tsw_modem = ucomtty_modem,
|
||||
.tsw_free = ucomtty_free,
|
||||
};
|
||||
|
||||
devclass_t ucom_devclass;
|
||||
|
||||
@ -160,31 +171,20 @@ ucom_modevent(module_t mod, int type, void *data)
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
ucom_attach_tty(struct ucom_softc *sc, int flags, char* fmt, int unit)
|
||||
void
|
||||
ucom_attach_tty(struct ucom_softc *sc, char* fmt, int unit)
|
||||
{
|
||||
struct tty *tp;
|
||||
|
||||
sc->sc_tty = tp = ttyalloc();
|
||||
tp->t_sc = sc;
|
||||
tp->t_oproc = ucomstart;
|
||||
tp->t_param = ucomparam;
|
||||
tp->t_stop = ucomstop;
|
||||
tp->t_break = ucombreak;
|
||||
tp->t_open = ucomopen;
|
||||
tp->t_close = ucomclose;
|
||||
tp->t_modem = ucommodem;
|
||||
tp->t_ioctl = ucomioctl;
|
||||
|
||||
return ttycreate(tp, flags, fmt, unit);
|
||||
sc->sc_tty = tp = tty_alloc(&ucomtty_class, sc, &Giant);
|
||||
tty_makedev(tp, NULL, fmt, unit);
|
||||
}
|
||||
|
||||
int
|
||||
ucom_attach(struct ucom_softc *sc)
|
||||
{
|
||||
|
||||
ucom_attach_tty(sc, TS_CALLOUT,
|
||||
"U%d", device_get_unit(sc->sc_dev));
|
||||
ucom_attach_tty(sc, "U%d", device_get_unit(sc->sc_dev));
|
||||
|
||||
DPRINTF(("ucom_attach: ttycreate: tp = %p, %s\n",
|
||||
sc->sc_tty, sc->sc_tty->t_dev->si_name));
|
||||
@ -195,24 +195,17 @@ ucom_attach(struct ucom_softc *sc)
|
||||
int
|
||||
ucom_detach(struct ucom_softc *sc)
|
||||
{
|
||||
int s;
|
||||
|
||||
DPRINTF(("ucom_detach: sc = %p, tp = %p\n", sc, sc->sc_tty));
|
||||
|
||||
tty_lock(sc->sc_tty);
|
||||
sc->sc_dying = 1;
|
||||
ttygone(sc->sc_tty);
|
||||
if (sc->sc_tty->t_state & TS_ISOPEN)
|
||||
ucomclose(sc->sc_tty);
|
||||
|
||||
if (sc->sc_bulkin_pipe != NULL)
|
||||
usbd_abort_pipe(sc->sc_bulkin_pipe);
|
||||
if (sc->sc_bulkout_pipe != NULL)
|
||||
usbd_abort_pipe(sc->sc_bulkout_pipe);
|
||||
|
||||
ttyfree(sc->sc_tty);
|
||||
|
||||
s = splusb();
|
||||
splx(s);
|
||||
tty_rel_gone(sc->sc_tty);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -227,30 +220,30 @@ ucom_shutdown(struct ucom_softc *sc)
|
||||
* Hang up if necessary. Wait a bit, so the other side has time to
|
||||
* notice even if we immediately open the port again.
|
||||
*/
|
||||
if (ISSET(tp->t_cflag, HUPCL)) {
|
||||
(void)ucommodem(tp, 0, SER_DTR);
|
||||
if (tp->t_termios.c_cflag & HUPCL) {
|
||||
(void)ucomtty_modem(tp, 0, SER_DTR);
|
||||
#if 0
|
||||
(void)tsleep(sc, TTIPRI, "ucomsd", hz);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
ucomopen(struct tty *tp, struct cdev *dev)
|
||||
ucomtty_open(struct tty *tp)
|
||||
{
|
||||
struct ucom_softc *sc;
|
||||
struct ucom_softc *sc = tty_softc(tp);
|
||||
usbd_status err;
|
||||
int error;
|
||||
|
||||
sc = tp->t_sc;
|
||||
|
||||
if (sc->sc_dying)
|
||||
return (ENXIO);
|
||||
|
||||
DPRINTF(("%s: ucomopen: tp = %p\n", device_get_nameunit(sc->sc_dev), tp));
|
||||
DPRINTF(("%s: ucomtty_open: tp = %p\n", device_get_nameunit(sc->sc_dev), tp));
|
||||
|
||||
sc->sc_poll = 0;
|
||||
sc->sc_lsr = sc->sc_msr = sc->sc_mcr = 0;
|
||||
|
||||
(void)ucommodem(tp, SER_DTR | SER_RTS, 0);
|
||||
(void)ucomtty_modem(tp, SER_DTR | SER_RTS, 0);
|
||||
|
||||
/* Device specific open */
|
||||
if (sc->sc_callback->ucom_open != NULL) {
|
||||
@ -262,7 +255,7 @@ ucomopen(struct tty *tp, struct cdev *dev)
|
||||
}
|
||||
}
|
||||
|
||||
DPRINTF(("ucomopen: open pipes in = %d out = %d\n",
|
||||
DPRINTF(("ucomtty_open: open pipes in = %d out = %d\n",
|
||||
sc->sc_bulkin_no, sc->sc_bulkout_no));
|
||||
|
||||
/* Open the bulk pipes */
|
||||
@ -328,13 +321,11 @@ ucomopen(struct tty *tp, struct cdev *dev)
|
||||
}
|
||||
|
||||
static void
|
||||
ucomclose(struct tty *tp)
|
||||
ucomtty_close(struct tty *tp)
|
||||
{
|
||||
struct ucom_softc *sc;
|
||||
struct ucom_softc *sc = tty_softc(tp);
|
||||
|
||||
sc = tp->t_sc;
|
||||
|
||||
DPRINTF(("%s: ucomclose \n", device_get_nameunit(sc->sc_dev)));
|
||||
DPRINTF(("%s: ucomtty_close \n", device_get_nameunit(sc->sc_dev)));
|
||||
|
||||
ucom_cleanup(sc);
|
||||
|
||||
@ -343,35 +334,41 @@ ucomclose(struct tty *tp)
|
||||
}
|
||||
|
||||
static int
|
||||
ucomioctl(struct tty *tp, u_long cmd, void *data, int flag, struct thread *p)
|
||||
ucomtty_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *p)
|
||||
{
|
||||
struct ucom_softc *sc;
|
||||
struct ucom_softc *sc = tty_softc(tp);
|
||||
int error;
|
||||
|
||||
sc = tp->t_sc;;
|
||||
if (sc->sc_dying)
|
||||
return (EIO);
|
||||
|
||||
DPRINTF(("ucomioctl: cmd = 0x%08lx\n", cmd));
|
||||
|
||||
error = ENOTTY;
|
||||
switch (cmd) {
|
||||
case TIOCSBRK:
|
||||
ucombreak(sc, 1);
|
||||
return (0);
|
||||
case TIOCCBRK:
|
||||
ucombreak(sc, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
error = ENOIOCTL;
|
||||
if (sc->sc_callback->ucom_ioctl != NULL)
|
||||
error = sc->sc_callback->ucom_ioctl(sc->sc_parent,
|
||||
sc->sc_portno,
|
||||
cmd, data, flag, p);
|
||||
cmd, data, p);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
ucommodem(struct tty *tp, int sigon, int sigoff)
|
||||
ucomtty_modem(struct tty *tp, int sigon, int sigoff)
|
||||
{
|
||||
struct ucom_softc *sc;
|
||||
struct ucom_softc *sc = tty_softc(tp);
|
||||
int mcr;
|
||||
int msr;
|
||||
int onoff;
|
||||
|
||||
sc = tp->t_sc;
|
||||
|
||||
if (sigon == 0 && sigoff == 0) {
|
||||
mcr = sc->sc_mcr;
|
||||
if (ISSET(mcr, SER_DTR))
|
||||
@ -412,12 +409,10 @@ ucommodem(struct tty *tp, int sigon, int sigoff)
|
||||
}
|
||||
|
||||
static void
|
||||
ucombreak(struct tty *tp, int onoff)
|
||||
ucombreak(struct ucom_softc *sc, int onoff)
|
||||
{
|
||||
struct ucom_softc *sc;
|
||||
|
||||
sc = tp->t_sc;
|
||||
DPRINTF(("ucombreak: onoff = %d\n", onoff));
|
||||
|
||||
if (sc->sc_callback->ucom_set == NULL)
|
||||
return;
|
||||
sc->sc_callback->ucom_set(sc->sc_parent, sc->sc_portno,
|
||||
@ -467,47 +462,32 @@ ucom_status_change(struct ucom_softc *sc)
|
||||
return;
|
||||
onoff = ISSET(sc->sc_msr, SER_DCD) ? 1 : 0;
|
||||
DPRINTF(("ucom_status_change: DCD changed to %d\n", onoff));
|
||||
ttyld_modem(tp, onoff);
|
||||
ttydisc_modem(tp, onoff);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
ucomparam(struct tty *tp, struct termios *t)
|
||||
ucomtty_param(struct tty *tp, struct termios *t)
|
||||
{
|
||||
struct ucom_softc *sc;
|
||||
struct ucom_softc *sc = tty_softc(tp);
|
||||
int error;
|
||||
usbd_status uerr;
|
||||
|
||||
sc = tp->t_sc;
|
||||
|
||||
if (sc->sc_dying)
|
||||
return (EIO);
|
||||
|
||||
DPRINTF(("ucomparam: sc = %p\n", sc));
|
||||
DPRINTF(("ucomtty_param: sc = %p\n", sc));
|
||||
|
||||
/* Check requested parameters. */
|
||||
if (t->c_ospeed < 0) {
|
||||
DPRINTF(("ucomparam: negative ospeed\n"));
|
||||
DPRINTF(("ucomtty_param: negative ospeed\n"));
|
||||
return (EINVAL);
|
||||
}
|
||||
if (t->c_ispeed && t->c_ispeed != t->c_ospeed) {
|
||||
DPRINTF(("ucomparam: mismatch ispeed and ospeed\n"));
|
||||
DPRINTF(("ucomtty_param: mismatch ispeed and ospeed\n"));
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* If there were no changes, don't do anything. This avoids dropping
|
||||
* input and improves performance when all we did was frob things like
|
||||
* VMIN and VTIME.
|
||||
*/
|
||||
if (tp->t_ospeed == t->c_ospeed &&
|
||||
tp->t_cflag == t->c_cflag)
|
||||
return (0);
|
||||
|
||||
/* And copy to tty. */
|
||||
tp->t_ispeed = 0;
|
||||
tp->t_ospeed = t->c_ospeed;
|
||||
tp->t_cflag = t->c_cflag;
|
||||
t->c_ispeed = t->c_ospeed;
|
||||
|
||||
if (sc->sc_callback->ucom_param == NULL)
|
||||
return (0);
|
||||
@ -516,20 +496,24 @@ ucomparam(struct tty *tp, struct termios *t)
|
||||
|
||||
error = sc->sc_callback->ucom_param(sc->sc_parent, sc->sc_portno, t);
|
||||
if (error) {
|
||||
DPRINTF(("ucomparam: callback: error = %d\n", error));
|
||||
DPRINTF(("ucomtty_param: callback: error = %d\n", error));
|
||||
return (error);
|
||||
}
|
||||
|
||||
#if 0
|
||||
ttsetwater(tp);
|
||||
#endif
|
||||
|
||||
if (t->c_cflag & CRTS_IFLOW) {
|
||||
sc->sc_state |= UCS_RTS_IFLOW;
|
||||
} else if (sc->sc_state & UCS_RTS_IFLOW) {
|
||||
sc->sc_state &= ~UCS_RTS_IFLOW;
|
||||
(void)ucommodem(tp, SER_RTS, 0);
|
||||
(void)ucomtty_modem(tp, SER_RTS, 0);
|
||||
}
|
||||
|
||||
#if 0
|
||||
ttyldoptim(tp);
|
||||
#endif
|
||||
|
||||
uerr = ucomstartread(sc);
|
||||
if (uerr != USBD_NORMAL_COMPLETION)
|
||||
@ -539,17 +523,23 @@ ucomparam(struct tty *tp, struct termios *t)
|
||||
}
|
||||
|
||||
static void
|
||||
ucomstart(struct tty *tp)
|
||||
ucomtty_free(void *sc)
|
||||
{
|
||||
struct ucom_softc *sc;
|
||||
struct cblock *cbp;
|
||||
usbd_status err;
|
||||
int s;
|
||||
u_char *data;
|
||||
int cnt;
|
||||
/*
|
||||
* Our softc gets deallocated earlier on.
|
||||
* XXX: we should make sure the TTY device name doesn't get
|
||||
* recycled before we end up here!
|
||||
*/
|
||||
}
|
||||
|
||||
sc = tp->t_sc;
|
||||
DPRINTF(("ucomstart: sc = %p\n", sc));
|
||||
static void
|
||||
ucomtty_outwakeup(struct tty *tp)
|
||||
{
|
||||
struct ucom_softc *sc = tty_softc(tp);
|
||||
usbd_status err;
|
||||
size_t cnt;
|
||||
|
||||
DPRINTF(("ucomtty_outwakeup: sc = %p\n", sc));
|
||||
|
||||
if (sc->sc_dying)
|
||||
return;
|
||||
@ -564,90 +554,59 @@ ucomstart(struct tty *tp)
|
||||
if (sc->sc_oxfer == NULL)
|
||||
return;
|
||||
|
||||
s = spltty();
|
||||
|
||||
/* XXX: hardware flow control. We should use inwakeup here. */
|
||||
#if 0
|
||||
if (tp->t_state & TS_TBLOCK) {
|
||||
if (ISSET(sc->sc_mcr, SER_RTS) &&
|
||||
ISSET(sc->sc_state, UCS_RTS_IFLOW)) {
|
||||
DPRINTF(("ucomstart: clear RTS\n"));
|
||||
(void)ucommodem(tp, 0, SER_RTS);
|
||||
DPRINTF(("ucomtty_outwakeup: clear RTS\n"));
|
||||
(void)ucomtty_modem(tp, 0, SER_RTS);
|
||||
}
|
||||
} else {
|
||||
if (!ISSET(sc->sc_mcr, SER_RTS) &&
|
||||
tp->t_rawq.c_cc <= tp->t_ilowat &&
|
||||
ISSET(sc->sc_state, UCS_RTS_IFLOW)) {
|
||||
DPRINTF(("ucomstart: set RTS\n"));
|
||||
(void)ucommodem(tp, SER_RTS, 0);
|
||||
DPRINTF(("ucomtty_outwakeup: set RTS\n"));
|
||||
(void)ucomtty_modem(tp, SER_RTS, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) {
|
||||
ttwwakeup(tp);
|
||||
DPRINTF(("ucomstart: stopped\n"));
|
||||
goto out;
|
||||
}
|
||||
if (sc->sc_state & UCS_TXBUSY)
|
||||
return;
|
||||
|
||||
if (tp->t_outq.c_cc <= tp->t_olowat) {
|
||||
if (ISSET(tp->t_state, TS_SO_OLOWAT)) {
|
||||
CLR(tp->t_state, TS_SO_OLOWAT);
|
||||
wakeup(TSA_OLOWAT(tp));
|
||||
}
|
||||
selwakeuppri(&tp->t_wsel, TTIPRI);
|
||||
if (tp->t_outq.c_cc == 0) {
|
||||
if (ISSET(tp->t_state, TS_BUSY | TS_SO_OCOMPLETE) ==
|
||||
TS_SO_OCOMPLETE && tp->t_outq.c_cc == 0) {
|
||||
CLR(tp->t_state, TS_SO_OCOMPLETE);
|
||||
wakeup(TSA_OCOMPLETE(tp));
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Grab the first contiguous region of buffer space. */
|
||||
data = tp->t_outq.c_cf;
|
||||
cbp = (struct cblock *) ((intptr_t) tp->t_outq.c_cf & ~CROUND);
|
||||
cnt = min((char *) (cbp+1) - tp->t_outq.c_cf, tp->t_outq.c_cc);
|
||||
sc->sc_state |= UCS_TXBUSY;
|
||||
if (sc->sc_callback->ucom_write != NULL)
|
||||
cnt = sc->sc_callback->ucom_write(sc->sc_parent,
|
||||
sc->sc_portno, tp, sc->sc_obuf, sc->sc_obufsize);
|
||||
else
|
||||
cnt = ttydisc_getc(tp, sc->sc_obuf, sc->sc_obufsize);
|
||||
|
||||
if (cnt == 0) {
|
||||
DPRINTF(("ucomstart: cnt == 0\n"));
|
||||
goto out;
|
||||
DPRINTF(("ucomtty_outwakeup: cnt == 0\n"));
|
||||
sc->sc_state &= ~UCS_TXBUSY;
|
||||
return;
|
||||
}
|
||||
|
||||
SET(tp->t_state, TS_BUSY);
|
||||
|
||||
if (cnt > sc->sc_obufsize) {
|
||||
DPRINTF(("ucomstart: big buffer %d chars\n", cnt));
|
||||
cnt = sc->sc_obufsize;
|
||||
}
|
||||
if (sc->sc_callback->ucom_write != NULL)
|
||||
sc->sc_callback->ucom_write(sc->sc_parent, sc->sc_portno,
|
||||
sc->sc_obuf, data, &cnt);
|
||||
else
|
||||
memcpy(sc->sc_obuf, data, cnt);
|
||||
|
||||
DPRINTF(("ucomstart: %d chars\n", cnt));
|
||||
DPRINTF(("ucomtty_outwakeup: %zu chars\n", cnt));
|
||||
usbd_setup_xfer(sc->sc_oxfer, sc->sc_bulkout_pipe,
|
||||
(usbd_private_handle)sc, sc->sc_obuf, cnt,
|
||||
USBD_NO_COPY, USBD_NO_TIMEOUT, ucomwritecb);
|
||||
/* What can we do on error? */
|
||||
err = usbd_transfer(sc->sc_oxfer);
|
||||
if (err != USBD_IN_PROGRESS)
|
||||
printf("ucomstart: err=%s\n", usbd_errstr(err));
|
||||
|
||||
ttwwakeup(tp);
|
||||
|
||||
out:
|
||||
splx(s);
|
||||
if (err != USBD_IN_PROGRESS) {
|
||||
printf("ucomtty_outwakeup: err=%s\n", usbd_errstr(err));
|
||||
sc->sc_state &= ~UCS_TXBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
ucomstop(struct tty *tp, int flag)
|
||||
{
|
||||
struct ucom_softc *sc;
|
||||
struct ucom_softc *sc = tty_softc(tp);
|
||||
int s;
|
||||
|
||||
sc = tp->t_sc;
|
||||
|
||||
DPRINTF(("ucomstop: %d\n", flag));
|
||||
|
||||
if ((flag & FREAD) && (sc->sc_state & UCS_RXSTOP) == 0) {
|
||||
@ -658,19 +617,18 @@ ucomstop(struct tty *tp, int flag)
|
||||
|
||||
if (flag & FWRITE) {
|
||||
DPRINTF(("ucomstop: write\n"));
|
||||
s = spltty();
|
||||
if (ISSET(tp->t_state, TS_BUSY)) {
|
||||
/* XXX do what? */
|
||||
if (!ISSET(tp->t_state, TS_TTSTOP))
|
||||
SET(tp->t_state, TS_FLUSH);
|
||||
}
|
||||
splx(s);
|
||||
}
|
||||
|
||||
ucomstart(tp);
|
||||
ucomtty_outwakeup(tp);
|
||||
|
||||
DPRINTF(("ucomstop: done\n"));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
ucomwritecb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
|
||||
@ -678,12 +636,11 @@ ucomwritecb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
|
||||
struct ucom_softc *sc = (struct ucom_softc *)p;
|
||||
struct tty *tp = sc->sc_tty;
|
||||
u_int32_t cc;
|
||||
int s;
|
||||
|
||||
DPRINTF(("ucomwritecb: status = %d\n", status));
|
||||
|
||||
if (status == USBD_CANCELLED || sc->sc_dying)
|
||||
goto error;
|
||||
return;
|
||||
|
||||
if (status != USBD_NORMAL_COMPLETION) {
|
||||
printf("%s: ucomwritecb: %s\n",
|
||||
@ -691,7 +648,7 @@ ucomwritecb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
|
||||
if (status == USBD_STALLED)
|
||||
usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
|
||||
/* XXX we should restart after some delay. */
|
||||
goto error;
|
||||
return;
|
||||
}
|
||||
|
||||
usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL);
|
||||
@ -699,28 +656,21 @@ ucomwritecb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
|
||||
if (cc <= sc->sc_opkthdrlen) {
|
||||
printf("%s: sent size too small, cc = %d\n",
|
||||
device_get_nameunit(sc->sc_dev), cc);
|
||||
goto error;
|
||||
return;
|
||||
}
|
||||
|
||||
/* convert from USB bytes to tty bytes */
|
||||
cc -= sc->sc_opkthdrlen;
|
||||
|
||||
s = spltty();
|
||||
sc->sc_state &= ~UCS_TXBUSY;
|
||||
#if 0
|
||||
CLR(tp->t_state, TS_BUSY);
|
||||
if (ISSET(tp->t_state, TS_FLUSH))
|
||||
CLR(tp->t_state, TS_FLUSH);
|
||||
else
|
||||
ndflush(&tp->t_outq, cc);
|
||||
ttyld_start(tp);
|
||||
splx(s);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
s = spltty();
|
||||
CLR(tp->t_state, TS_BUSY);
|
||||
splx(s);
|
||||
return;
|
||||
#endif
|
||||
ucomtty_outwakeup(tp);
|
||||
}
|
||||
|
||||
static usbd_status
|
||||
@ -758,8 +708,6 @@ ucomreadcb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
|
||||
usbd_status err;
|
||||
u_int32_t cc;
|
||||
u_char *cp;
|
||||
int lostcc;
|
||||
int s;
|
||||
|
||||
DPRINTF(("ucomreadcb: status = %d\n", status));
|
||||
|
||||
@ -791,42 +739,20 @@ ucomreadcb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
|
||||
}
|
||||
if (cc < 1)
|
||||
goto resubmit;
|
||||
|
||||
s = spltty();
|
||||
if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
|
||||
if (tp->t_rawq.c_cc + cc > tp->t_ihiwat
|
||||
&& (sc->sc_state & UCS_RTS_IFLOW
|
||||
|| tp->t_iflag & IXOFF)
|
||||
&& !(tp->t_state & TS_TBLOCK))
|
||||
ttyblock(tp);
|
||||
lostcc = b_to_q((char *)cp, cc, &tp->t_rawq);
|
||||
tp->t_rawcc += cc;
|
||||
ttwakeup(tp);
|
||||
if (tp->t_state & TS_TTSTOP
|
||||
&& (tp->t_iflag & IXANY
|
||||
|| tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
|
||||
tp->t_state &= ~TS_TTSTOP;
|
||||
tp->t_lflag &= ~FLUSHO;
|
||||
ucomstart(tp);
|
||||
}
|
||||
if (lostcc > 0)
|
||||
printf("%s: lost %d chars\n", device_get_nameunit(sc->sc_dev),
|
||||
lostcc);
|
||||
} else {
|
||||
/* Give characters to tty layer. */
|
||||
while (cc > 0) {
|
||||
DPRINTFN(7, ("ucomreadcb: char = 0x%02x\n", *cp));
|
||||
if (ttyld_rint(tp, *cp) == -1) {
|
||||
/* XXX what should we do? */
|
||||
printf("%s: lost %d chars\n",
|
||||
device_get_nameunit(sc->sc_dev), cc);
|
||||
break;
|
||||
}
|
||||
cc--;
|
||||
cp++;
|
||||
|
||||
/* Give characters to tty layer. */
|
||||
while (cc > 0) {
|
||||
DPRINTFN(7, ("ucomreadcb: char = 0x%02x\n", *cp));
|
||||
if (ttydisc_rint(tp, *cp, 0) == -1) {
|
||||
/* XXX what should we do? */
|
||||
printf("%s: lost %d chars\n",
|
||||
device_get_nameunit(sc->sc_dev), cc);
|
||||
break;
|
||||
}
|
||||
cc--;
|
||||
cp++;
|
||||
}
|
||||
splx(s);
|
||||
ttydisc_rint_done(tp);
|
||||
|
||||
resubmit:
|
||||
err = ucomstartread(sc);
|
||||
@ -835,9 +761,11 @@ ucomreadcb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
|
||||
/* XXX what should we dow now? */
|
||||
}
|
||||
|
||||
#if 0
|
||||
if ((sc->sc_state & UCS_RTS_IFLOW) && !ISSET(sc->sc_mcr, SER_RTS)
|
||||
&& !(tp->t_state & TS_TBLOCK))
|
||||
ucommodem(tp, SER_RTS, 0);
|
||||
ucomtty_modem(tp, SER_RTS, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -88,6 +88,7 @@
|
||||
|
||||
#define UCOM_UNK_PORTNO -1 /* XXX */
|
||||
|
||||
struct tty;
|
||||
struct ucom_softc;
|
||||
|
||||
struct ucom_callback {
|
||||
@ -97,11 +98,11 @@ struct ucom_callback {
|
||||
#define UCOM_SET_RTS 2
|
||||
#define UCOM_SET_BREAK 3
|
||||
int (*ucom_param)(void *, int, struct termios *);
|
||||
int (*ucom_ioctl)(void *, int, u_long, caddr_t, int, struct thread *);
|
||||
int (*ucom_ioctl)(void *, int, u_long, caddr_t, struct thread *);
|
||||
int (*ucom_open)(void *, int);
|
||||
void (*ucom_close)(void *, int);
|
||||
void (*ucom_read)(void *, int, u_char **, u_int32_t *);
|
||||
void (*ucom_write)(void *, int, u_char *, u_char *, u_int32_t *);
|
||||
size_t (*ucom_write)(void *, int, struct tty *, u_char *, u_int32_t);
|
||||
};
|
||||
|
||||
/* line status register */
|
||||
@ -117,6 +118,7 @@ struct ucom_callback {
|
||||
|
||||
/* ucom state declarations */
|
||||
#define UCS_RXSTOP 0x0001 /* Rx stopped */
|
||||
#define UCS_TXBUSY 0x0002 /* Tx busy */
|
||||
#define UCS_RTS_IFLOW 0x0008 /* use RTS input flow control */
|
||||
|
||||
struct ucom_softc {
|
||||
@ -159,7 +161,7 @@ struct ucom_softc {
|
||||
|
||||
extern devclass_t ucom_devclass;
|
||||
|
||||
int ucom_attach_tty(struct ucom_softc *, int, char*, int);
|
||||
void ucom_attach_tty(struct ucom_softc *, char*, int);
|
||||
int ucom_attach(struct ucom_softc *);
|
||||
int ucom_detach(struct ucom_softc *);
|
||||
void ucom_status_change(struct ucom_softc *);
|
||||
|
@ -118,8 +118,8 @@ static void uftdi_set(void *, int, int, int);
|
||||
static int uftdi_param(void *, int, struct termios *);
|
||||
static int uftdi_open(void *sc, int portno);
|
||||
static void uftdi_read(void *sc, int portno, u_char **ptr,u_int32_t *count);
|
||||
static void uftdi_write(void *sc, int portno, u_char *to, u_char *from,
|
||||
u_int32_t *count);
|
||||
static size_t uftdi_write(void *sc, int portno, struct tty *,
|
||||
u_char *to, u_int32_t count);
|
||||
static void uftdi_break(void *sc, int portno, int onoff);
|
||||
static int uftdi_8u232am_getrate(speed_t speed, int *rate);
|
||||
|
||||
@ -486,20 +486,25 @@ uftdi_read(void *vsc, int portno, u_char **ptr, u_int32_t *count)
|
||||
*count -= 2;
|
||||
}
|
||||
|
||||
static void
|
||||
uftdi_write(void *vsc, int portno, u_char *to, u_char *from, u_int32_t *count)
|
||||
static size_t
|
||||
uftdi_write(void *vsc, int portno, struct tty *tp, u_char *to, u_int32_t count)
|
||||
{
|
||||
struct uftdi_softc *sc = vsc;
|
||||
size_t l;
|
||||
|
||||
DPRINTFN(10,("uftdi_write: sc=%p, port=%d count=%u data[0]=0x%02x\n",
|
||||
vsc, portno, *count, from[0]));
|
||||
DPRINTFN(10,("uftdi_write: sc=%p, port=%d tp=%p, count=%u\n",
|
||||
vsc, portno, tp, count));
|
||||
|
||||
/* Make length tag and copy data */
|
||||
/* Leave space for the length tag. */
|
||||
l = ttydisc_getc(tp, to + sc->sc_hdrlen, count - sc->sc_hdrlen);
|
||||
if (l == 0)
|
||||
return (0);
|
||||
|
||||
/* Make length tag. */
|
||||
if (sc->sc_hdrlen > 0)
|
||||
*to = FTDI_OUT_TAG(*count, portno);
|
||||
|
||||
memcpy(to + sc->sc_hdrlen, from, *count);
|
||||
*count += sc->sc_hdrlen;
|
||||
*to = FTDI_OUT_TAG(l, portno);
|
||||
|
||||
return (l + sc->sc_hdrlen);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -187,7 +187,7 @@ static void umodem_rts(struct umodem_softc *, int);
|
||||
static void umodem_break(struct umodem_softc *, int);
|
||||
static void umodem_set_line_state(struct umodem_softc *);
|
||||
static int umodem_param(void *, int, struct termios *);
|
||||
static int umodem_ioctl(void *, int, u_long, caddr_t, int, struct thread *);
|
||||
static int umodem_ioctl(void *, int, u_long, caddr_t, struct thread *);
|
||||
static int umodem_open(void *, int portno);
|
||||
static void umodem_close(void *, int portno);
|
||||
static void umodem_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
|
||||
@ -611,7 +611,7 @@ umodem_param(void *addr, int portno, struct termios *t)
|
||||
}
|
||||
|
||||
int
|
||||
umodem_ioctl(void *addr, int portno, u_long cmd, caddr_t data, int flag,
|
||||
umodem_ioctl(void *addr, int portno, u_long cmd, caddr_t data,
|
||||
struct thread *p)
|
||||
{
|
||||
struct umodem_softc *sc = addr;
|
||||
|
@ -597,8 +597,6 @@ devfs_ioctl_f(struct file *fp, u_long com, void *data, struct ucred *cred, struc
|
||||
return (0);
|
||||
}
|
||||
|
||||
mtx_lock(&Giant); /* XXX TTY */
|
||||
|
||||
vpold = td->td_proc->p_session->s_ttyvp;
|
||||
VREF(vp);
|
||||
SESS_LOCK(td->td_proc->p_session);
|
||||
@ -610,7 +608,6 @@ devfs_ioctl_f(struct file *fp, u_long com, void *data, struct ucred *cred, struc
|
||||
/* Get rid of reference to old control tty */
|
||||
if (vpold)
|
||||
vrele(vpold);
|
||||
mtx_unlock(&Giant); /* XXX TTY */
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
@ -272,7 +272,7 @@ device loop # Network loopback
|
||||
device random # Entropy device
|
||||
device ether # Ethernet support
|
||||
device tun # Packet tunnel.
|
||||
device pty # Pseudo-ttys (telnet etc)
|
||||
device pty # BSD-style compatibility pseudo ttys
|
||||
device md # Memory "disks"
|
||||
device gif # IPv6 and IPv4 tunneling
|
||||
device faith # IPv6-to-IPv4 relaying (translation)
|
||||
|
@ -71,7 +71,7 @@ device io # I/O device
|
||||
device random # Entropy device
|
||||
device ether # Ethernet support
|
||||
#device tun # Packet tunnel.
|
||||
device pty # Pseudo-ttys (telnet etc)
|
||||
device pty # BSD-style compatibility pseudo ttys
|
||||
#device md # Memory "disks"
|
||||
#device gif # IPv6 and IPv4 tunneling
|
||||
#device faith # IPv6-to-IPv4 relaying (translation)
|
||||
|
@ -88,6 +88,11 @@ ibcs2_stty(struct thread *td, struct ibcs2_stty_args *args)
|
||||
* iBCS2 ioctl calls.
|
||||
*/
|
||||
|
||||
struct speedtab {
|
||||
int sp_speed; /* Speed. */
|
||||
int sp_code; /* Code. */
|
||||
};
|
||||
|
||||
static struct speedtab sptab[] = {
|
||||
{ 0, 0 },
|
||||
{ 50, 1 },
|
||||
@ -128,6 +133,16 @@ static u_long s2btab[] = {
|
||||
38400,
|
||||
};
|
||||
|
||||
static int
|
||||
ttspeedtab(int speed, struct speedtab *table)
|
||||
{
|
||||
|
||||
for ( ; table->sp_speed != -1; table++)
|
||||
if (table->sp_speed == speed)
|
||||
return (table->sp_code);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static void
|
||||
stios2btios(st, bt)
|
||||
struct ibcs2_termios *st;
|
||||
@ -154,7 +169,7 @@ stios2btios(st, bt)
|
||||
l = st->c_oflag; r = 0;
|
||||
if (l & IBCS2_OPOST) r |= OPOST;
|
||||
if (l & IBCS2_ONLCR) r |= ONLCR;
|
||||
if (l & IBCS2_TAB3) r |= OXTABS;
|
||||
if (l & IBCS2_TAB3) r |= TAB3;
|
||||
bt->c_oflag = r;
|
||||
|
||||
l = st->c_cflag; r = 0;
|
||||
@ -248,7 +263,7 @@ btios2stios(bt, st)
|
||||
l = bt->c_oflag; r = 0;
|
||||
if (l & OPOST) r |= IBCS2_OPOST;
|
||||
if (l & ONLCR) r |= IBCS2_ONLCR;
|
||||
if (l & OXTABS) r |= IBCS2_TAB3;
|
||||
if (l & TAB3) r |= IBCS2_TAB3;
|
||||
st->c_oflag = r;
|
||||
|
||||
l = bt->c_cflag; r = 0;
|
||||
|
@ -151,7 +151,7 @@ device faith # IPv6-to-IPv4 relaying (translation)
|
||||
device gif # IPv6 and IPv4 tunneling
|
||||
device loop # Network loopback
|
||||
device md # Memory "disks"
|
||||
device pty # Pseudo-ttys (telnet etc)
|
||||
device pty # BSD-style compatibility pseudo ttys
|
||||
device puc # Multi I/O cards and multi-channel UARTs
|
||||
device random # Entropy device
|
||||
device tun # Packet tunnel.
|
||||
|
@ -53,7 +53,7 @@ device pci # PCI bus support
|
||||
device ether # Ethernet support
|
||||
device loop # Network loopback
|
||||
device md # Memory "disks"
|
||||
device pty # Pseudo-ttys (telnet etc)
|
||||
device pty # BSD-style compatibility pseudo ttys
|
||||
device random # Entropy device
|
||||
device tun # Packet tunnel.
|
||||
|
||||
|
@ -54,26 +54,22 @@
|
||||
|
||||
#define SSC_POLL_HZ 50
|
||||
|
||||
static d_open_t ssc_open;
|
||||
static d_close_t ssc_close;
|
||||
static tsw_open_t ssc_open;
|
||||
static tsw_outwakeup_t ssc_outwakeup;
|
||||
static tsw_close_t ssc_close;
|
||||
|
||||
static struct cdevsw ssc_cdevsw = {
|
||||
.d_version = D_VERSION,
|
||||
.d_open = ssc_open,
|
||||
.d_close = ssc_close,
|
||||
.d_name = "ssc",
|
||||
.d_flags = D_TTY | D_NEEDGIANT,
|
||||
static struct ttydevsw ssc_class = {
|
||||
.tsw_flags = TF_NOPREFIX,
|
||||
.tsw_open = ssc_open,
|
||||
.tsw_outwakeup = ssc_outwakeup,
|
||||
.tsw_close = ssc_close,
|
||||
};
|
||||
|
||||
static struct tty *ssc_tp = NULL;
|
||||
static int polltime;
|
||||
static struct callout_handle ssc_timeouthandle
|
||||
= CALLOUT_HANDLE_INITIALIZER(&ssc_timeouthandle);
|
||||
|
||||
static void ssc_start(struct tty *);
|
||||
static void ssc_timeout(void *);
|
||||
static int ssc_param(struct tty *, struct termios *);
|
||||
static void ssc_stop(struct tty *, int);
|
||||
|
||||
static u_int64_t
|
||||
ssc(u_int64_t in0, u_int64_t in1, u_int64_t in2, u_int64_t in3, int which)
|
||||
@ -90,7 +86,8 @@ ssc(u_int64_t in0, u_int64_t in1, u_int64_t in2, u_int64_t in3, int which)
|
||||
static void
|
||||
ssc_cnprobe(struct consdev *cp)
|
||||
{
|
||||
sprintf(cp->cn_name, "ssccons");
|
||||
|
||||
strcpy(cp->cn_name, "ssccons");
|
||||
cp->cn_pri = CN_INTERNAL;
|
||||
}
|
||||
|
||||
@ -107,8 +104,10 @@ ssc_cnterm(struct consdev *cp)
|
||||
static void
|
||||
ssc_cnattach(void *arg)
|
||||
{
|
||||
make_dev(&ssc_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "ssccons");
|
||||
ssc_tp = ttyalloc();
|
||||
struct tty *tp;
|
||||
|
||||
tp = tty_alloc(&ssc_class, NULL, NULL);
|
||||
tty_makedev(tp, NULL, "ssccons");
|
||||
}
|
||||
|
||||
SYSINIT(ssc_cnattach, SI_SUB_DRIVERS, SI_ORDER_ANY, ssc_cnattach, 0);
|
||||
@ -130,100 +129,39 @@ ssc_cngetc(struct consdev *cp)
|
||||
}
|
||||
|
||||
static int
|
||||
ssc_open(struct cdev *dev, int flag, int mode, struct thread *td)
|
||||
ssc_open(struct tty *tp)
|
||||
{
|
||||
struct tty *tp;
|
||||
int s;
|
||||
int error = 0, setuptimeout = 0;
|
||||
|
||||
tp = dev->si_tty = ssc_tp;
|
||||
|
||||
s = spltty();
|
||||
tp->t_oproc = ssc_start;
|
||||
tp->t_param = ssc_param;
|
||||
tp->t_stop = ssc_stop;
|
||||
tp->t_dev = dev;
|
||||
if ((tp->t_state & TS_ISOPEN) == 0) {
|
||||
tp->t_state |= TS_CARR_ON;
|
||||
ttyconsolemode(tp, 0);
|
||||
polltime = hz / SSC_POLL_HZ;
|
||||
if (polltime < 1)
|
||||
polltime = 1;
|
||||
ssc_timeouthandle = timeout(ssc_timeout, tp, polltime);
|
||||
|
||||
setuptimeout = 1;
|
||||
} else if ((tp->t_state & TS_XCLUDE) &&
|
||||
priv_check(td, PRIV_TTY_EXCLUSIVE)) {
|
||||
splx(s);
|
||||
return EBUSY;
|
||||
}
|
||||
|
||||
splx(s);
|
||||
|
||||
error = ttyld_open(tp, dev);
|
||||
|
||||
if (error == 0 && setuptimeout) {
|
||||
polltime = hz / SSC_POLL_HZ;
|
||||
if (polltime < 1)
|
||||
polltime = 1;
|
||||
ssc_timeouthandle = timeout(ssc_timeout, tp, polltime);
|
||||
}
|
||||
return error;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ssc_close(struct cdev *dev, int flag, int mode, struct thread *td)
|
||||
static void
|
||||
ssc_close(struct tty *tp)
|
||||
{
|
||||
int unit = minor(dev);
|
||||
struct tty *tp = ssc_tp;
|
||||
|
||||
if (unit != 0)
|
||||
return ENXIO;
|
||||
|
||||
untimeout(ssc_timeout, tp, ssc_timeouthandle);
|
||||
ttyld_close(tp, flag);
|
||||
tty_close(tp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ssc_param(struct tty *tp, struct termios *t)
|
||||
{
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ssc_start(struct tty *tp)
|
||||
ssc_outwakeup(struct tty *tp)
|
||||
{
|
||||
int s;
|
||||
char buf[128];
|
||||
size_t len, c;
|
||||
|
||||
s = spltty();
|
||||
for (;;) {
|
||||
len = ttydisc_getc(tp, buf, sizeof buf);
|
||||
if (len == 0)
|
||||
break;
|
||||
|
||||
if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
|
||||
ttwwakeup(tp);
|
||||
splx(s);
|
||||
return;
|
||||
c = 0;
|
||||
while (len-- > 0)
|
||||
ssc_cnputc(NULL, buf[c++]);
|
||||
}
|
||||
|
||||
tp->t_state |= TS_BUSY;
|
||||
while (tp->t_outq.c_cc != 0)
|
||||
ssc_cnputc(NULL, getc(&tp->t_outq));
|
||||
tp->t_state &= ~TS_BUSY;
|
||||
|
||||
ttwwakeup(tp);
|
||||
splx(s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Stop output on a line.
|
||||
*/
|
||||
static void
|
||||
ssc_stop(struct tty *tp, int flag)
|
||||
{
|
||||
int s;
|
||||
|
||||
s = spltty();
|
||||
if (tp->t_state & TS_BUSY)
|
||||
if ((tp->t_state & TS_TTSTOP) == 0)
|
||||
tp->t_state |= TS_FLUSH;
|
||||
splx(s);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -232,10 +170,12 @@ ssc_timeout(void *v)
|
||||
struct tty *tp = v;
|
||||
int c;
|
||||
|
||||
while ((c = ssc_cngetc(NULL)) != -1) {
|
||||
if (tp->t_state & TS_ISOPEN)
|
||||
ttyld_rint(tp, c);
|
||||
}
|
||||
tty_lock(tp);
|
||||
while ((c = ssc_cngetc(NULL)) != -1)
|
||||
ttydisc_rint(tp, c, 0);
|
||||
ttydisc_rint_done(tp);
|
||||
tty_unlock(tp);
|
||||
|
||||
ssc_timeouthandle = timeout(ssc_timeout, tp, polltime);
|
||||
}
|
||||
|
||||
|
@ -415,7 +415,7 @@ proc0_init(void *dummy __unused)
|
||||
|
||||
pgrp0.pg_session = &session0;
|
||||
mtx_init(&session0.s_mtx, "session", NULL, MTX_DEF);
|
||||
session0.s_count = 1;
|
||||
refcount_init(&session0.s_count, 1);
|
||||
session0.s_leader = p;
|
||||
|
||||
p->p_sysent = &null_sysvec;
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* DO NOT EDIT-- this file is automatically generated.
|
||||
* $FreeBSD$
|
||||
* created from FreeBSD: src/sys/kern/syscalls.master,v 1.242 2008/03/31 12:06:55 kib Exp
|
||||
* created from FreeBSD: head/sys/kern/syscalls.master 178888 2008-05-09 23:03:00Z julian
|
||||
*/
|
||||
|
||||
#include "opt_compat.h"
|
||||
@ -532,4 +532,5 @@ struct sysent sysent[] = {
|
||||
{ AS(renameat_args), (sy_call_t *)renameat, AUE_RENAMEAT, NULL, 0, 0 }, /* 501 = renameat */
|
||||
{ AS(symlinkat_args), (sy_call_t *)symlinkat, AUE_SYMLINKAT, NULL, 0, 0 }, /* 502 = symlinkat */
|
||||
{ AS(unlinkat_args), (sy_call_t *)unlinkat, AUE_UNLINKAT, NULL, 0, 0 }, /* 503 = unlinkat */
|
||||
{ AS(posix_openpt_args), (sy_call_t *)posix_openpt, AUE_POSIXOPENPT, NULL, 0, 0 }, /* 504 = posix_openpt */
|
||||
};
|
||||
|
@ -402,12 +402,12 @@ acct_process(struct thread *td)
|
||||
acct.ac_gid = p->p_ucred->cr_rgid;
|
||||
|
||||
/* (7) The terminal from which the process was started */
|
||||
SESS_LOCK(p->p_session);
|
||||
sx_slock(&proctree_lock);
|
||||
if ((p->p_flag & P_CONTROLT) && p->p_pgrp->pg_session->s_ttyp)
|
||||
acct.ac_tty = dev2udev(p->p_pgrp->pg_session->s_ttyp->t_dev);
|
||||
acct.ac_tty = tty_udev(p->p_pgrp->pg_session->s_ttyp);
|
||||
else
|
||||
acct.ac_tty = NODEV;
|
||||
SESS_UNLOCK(p->p_session);
|
||||
sx_sunlock(&proctree_lock);
|
||||
|
||||
/* (8) The boolean flags that tell how the process terminated, etc. */
|
||||
acct.ac_flagx = p->p_acflag;
|
||||
|
@ -42,7 +42,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/poll.h>
|
||||
#include <sys/sx.h>
|
||||
#include <sys/ctype.h>
|
||||
#include <sys/tty.h>
|
||||
#include <sys/ucred.h>
|
||||
#include <sys/taskqueue.h>
|
||||
#include <machine/stdarg.h>
|
||||
@ -611,14 +610,6 @@ prep_cdevsw(struct cdevsw *devsw)
|
||||
devsw->d_kqfilter = dead_kqfilter;
|
||||
}
|
||||
|
||||
if (devsw->d_flags & D_TTY) {
|
||||
if (devsw->d_ioctl == NULL) devsw->d_ioctl = ttyioctl;
|
||||
if (devsw->d_read == NULL) devsw->d_read = ttyread;
|
||||
if (devsw->d_write == NULL) devsw->d_write = ttywrite;
|
||||
if (devsw->d_kqfilter == NULL) devsw->d_kqfilter = ttykqfilter;
|
||||
if (devsw->d_poll == NULL) devsw->d_poll = ttypoll;
|
||||
}
|
||||
|
||||
if (devsw->d_flags & D_NEEDGIANT) {
|
||||
if (devsw->d_gianttrick == NULL) {
|
||||
memcpy(dsw2, devsw, sizeof *dsw2);
|
||||
@ -692,11 +683,9 @@ make_dev_credv(int flags, struct cdevsw *devsw, int minornr,
|
||||
}
|
||||
|
||||
dev->si_flags |= SI_NAMED;
|
||||
#ifdef MAC
|
||||
if (cr != NULL)
|
||||
dev->si_cred = crhold(cr);
|
||||
else
|
||||
#endif
|
||||
dev->si_cred = NULL;
|
||||
dev->si_uid = uid;
|
||||
dev->si_gid = gid;
|
||||
|
@ -70,6 +70,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/syscallsubr.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/sysproto.h>
|
||||
#include <sys/tty.h>
|
||||
#include <sys/unistd.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/vnode.h>
|
||||
@ -2564,6 +2565,7 @@ sysctl_kern_proc_filedesc(SYSCTL_HANDLER_ARGS)
|
||||
struct vnode *vp;
|
||||
struct file *fp;
|
||||
struct proc *p;
|
||||
struct tty *tp;
|
||||
int vfslocked;
|
||||
|
||||
name = (int *)arg1;
|
||||
@ -2595,6 +2597,7 @@ sysctl_kern_proc_filedesc(SYSCTL_HANDLER_ARGS)
|
||||
kif->kf_structsize = sizeof(*kif);
|
||||
vp = NULL;
|
||||
so = NULL;
|
||||
tp = NULL;
|
||||
kif->kf_fd = i;
|
||||
switch (fp->f_type) {
|
||||
case DTYPE_VNODE:
|
||||
@ -2637,6 +2640,11 @@ sysctl_kern_proc_filedesc(SYSCTL_HANDLER_ARGS)
|
||||
kif->kf_type = KF_TYPE_SEM;
|
||||
break;
|
||||
|
||||
case DTYPE_PTS:
|
||||
kif->kf_type = KF_TYPE_PTS;
|
||||
tp = fp->f_data;
|
||||
break;
|
||||
|
||||
default:
|
||||
kif->kf_type = KF_TYPE_UNKNOWN;
|
||||
break;
|
||||
@ -2730,6 +2738,10 @@ sysctl_kern_proc_filedesc(SYSCTL_HANDLER_ARGS)
|
||||
kif->kf_sock_type = so->so_type;
|
||||
kif->kf_sock_protocol = so->so_proto->pr_protocol;
|
||||
}
|
||||
if (tp != NULL) {
|
||||
strlcpy(kif->kf_path, tty_devname(tp),
|
||||
sizeof(kif->kf_path));
|
||||
}
|
||||
error = SYSCTL_OUT(req, kif, sizeof(*kif));
|
||||
if (error)
|
||||
break;
|
||||
|
@ -119,9 +119,8 @@ void
|
||||
exit1(struct thread *td, int rv)
|
||||
{
|
||||
struct proc *p, *nq, *q;
|
||||
struct tty *tp;
|
||||
struct vnode *ttyvp;
|
||||
struct vnode *vtmp;
|
||||
struct vnode *ttyvp = NULL;
|
||||
#ifdef KTRACE
|
||||
struct vnode *tracevp;
|
||||
struct ucred *tracecred;
|
||||
@ -298,56 +297,48 @@ exit1(struct thread *td, int rv)
|
||||
|
||||
vmspace_exit(td);
|
||||
|
||||
mtx_lock(&Giant); /* XXX TTY */
|
||||
sx_xlock(&proctree_lock);
|
||||
if (SESS_LEADER(p)) {
|
||||
struct session *sp;
|
||||
|
||||
sp = p->p_session;
|
||||
if (sp->s_ttyvp) {
|
||||
|
||||
SESS_LOCK(sp);
|
||||
ttyvp = sp->s_ttyvp;
|
||||
sp->s_ttyvp = NULL;
|
||||
SESS_UNLOCK(sp);
|
||||
|
||||
if (ttyvp != NULL) {
|
||||
/*
|
||||
* Controlling process.
|
||||
* Signal foreground pgrp,
|
||||
* drain controlling terminal
|
||||
* and revoke access to controlling terminal.
|
||||
* Signal foreground pgrp and revoke access to
|
||||
* controlling terminal.
|
||||
*
|
||||
* There is no need to drain the terminal here,
|
||||
* because this will be done on revocation.
|
||||
*/
|
||||
if (sp->s_ttyp && (sp->s_ttyp->t_session == sp)) {
|
||||
tp = sp->s_ttyp;
|
||||
if (sp->s_ttyp->t_pgrp) {
|
||||
PGRP_LOCK(sp->s_ttyp->t_pgrp);
|
||||
pgsignal(sp->s_ttyp->t_pgrp, SIGHUP, 1);
|
||||
PGRP_UNLOCK(sp->s_ttyp->t_pgrp);
|
||||
}
|
||||
/* XXX tp should be locked. */
|
||||
sx_xunlock(&proctree_lock);
|
||||
(void) ttywait(tp);
|
||||
sx_xlock(&proctree_lock);
|
||||
if (sp->s_ttyp != NULL) {
|
||||
struct tty *tp = sp->s_ttyp;
|
||||
|
||||
tty_lock(tp);
|
||||
tty_signal_pgrp(tp, SIGHUP);
|
||||
tty_unlock(tp);
|
||||
|
||||
/*
|
||||
* The tty could have been revoked
|
||||
* if we blocked.
|
||||
*/
|
||||
if (sp->s_ttyvp) {
|
||||
ttyvp = sp->s_ttyvp;
|
||||
SESS_LOCK(p->p_session);
|
||||
sp->s_ttyvp = NULL;
|
||||
SESS_UNLOCK(p->p_session);
|
||||
if (ttyvp->v_type != VBAD) {
|
||||
sx_xunlock(&proctree_lock);
|
||||
VOP_LOCK(ttyvp, LK_EXCLUSIVE);
|
||||
VOP_REVOKE(ttyvp, REVOKEALL);
|
||||
vput(ttyvp);
|
||||
VOP_UNLOCK(ttyvp, 0);
|
||||
sx_xlock(&proctree_lock);
|
||||
}
|
||||
}
|
||||
if (sp->s_ttyvp) {
|
||||
ttyvp = sp->s_ttyvp;
|
||||
SESS_LOCK(p->p_session);
|
||||
sp->s_ttyvp = NULL;
|
||||
SESS_UNLOCK(p->p_session);
|
||||
vrele(ttyvp);
|
||||
}
|
||||
/*
|
||||
* s_ttyp is not zero'd; we use this to indicate
|
||||
* that the session once had a controlling terminal.
|
||||
* s_ttyp is not zero'd; we use this to indicate that
|
||||
* the session once had a controlling terminal.
|
||||
* (for logging and informational purposes)
|
||||
*/
|
||||
}
|
||||
@ -358,7 +349,10 @@ exit1(struct thread *td, int rv)
|
||||
fixjobc(p, p->p_pgrp, 0);
|
||||
sx_xunlock(&proctree_lock);
|
||||
(void)acct_process(td);
|
||||
mtx_unlock(&Giant);
|
||||
|
||||
/* Release the TTY now we've unlocked everything. */
|
||||
if (ttyvp != NULL)
|
||||
vrele(ttyvp);
|
||||
#ifdef KTRACE
|
||||
/*
|
||||
* Disable tracing, then drain any pending records and release
|
||||
|
@ -352,14 +352,13 @@ enterpgrp(p, pgid, pgrp, sess)
|
||||
* new session
|
||||
*/
|
||||
mtx_init(&sess->s_mtx, "session", NULL, MTX_DEF);
|
||||
mtx_lock(&Giant); /* XXX TTY */
|
||||
PROC_LOCK(p);
|
||||
p->p_flag &= ~P_CONTROLT;
|
||||
PROC_UNLOCK(p);
|
||||
PGRP_LOCK(pgrp);
|
||||
sess->s_leader = p;
|
||||
sess->s_sid = p->p_pid;
|
||||
sess->s_count = 1;
|
||||
refcount_init(&sess->s_count, 1);
|
||||
sess->s_ttyvp = NULL;
|
||||
sess->s_ttyp = NULL;
|
||||
bcopy(p->p_session->s_login, sess->s_login,
|
||||
@ -368,11 +367,8 @@ enterpgrp(p, pgid, pgrp, sess)
|
||||
KASSERT(p == curproc,
|
||||
("enterpgrp: mksession and p != curproc"));
|
||||
} else {
|
||||
mtx_lock(&Giant); /* XXX TTY */
|
||||
pgrp->pg_session = p->p_session;
|
||||
SESS_LOCK(pgrp->pg_session);
|
||||
pgrp->pg_session->s_count++;
|
||||
SESS_UNLOCK(pgrp->pg_session);
|
||||
sess_hold(pgrp->pg_session);
|
||||
PGRP_LOCK(pgrp);
|
||||
}
|
||||
pgrp->pg_id = pgid;
|
||||
@ -386,7 +382,6 @@ enterpgrp(p, pgid, pgrp, sess)
|
||||
pgrp->pg_jobc = 0;
|
||||
SLIST_INIT(&pgrp->pg_sigiolst);
|
||||
PGRP_UNLOCK(pgrp);
|
||||
mtx_unlock(&Giant); /* XXX TTY */
|
||||
|
||||
doenterpgrp(p, pgrp);
|
||||
|
||||
@ -446,7 +441,6 @@ doenterpgrp(p, pgrp)
|
||||
fixjobc(p, pgrp, 1);
|
||||
fixjobc(p, p->p_pgrp, 0);
|
||||
|
||||
mtx_lock(&Giant); /* XXX TTY */
|
||||
PGRP_LOCK(pgrp);
|
||||
PGRP_LOCK(savepgrp);
|
||||
PROC_LOCK(p);
|
||||
@ -456,7 +450,6 @@ doenterpgrp(p, pgrp)
|
||||
LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist);
|
||||
PGRP_UNLOCK(savepgrp);
|
||||
PGRP_UNLOCK(pgrp);
|
||||
mtx_unlock(&Giant); /* XXX TTY */
|
||||
if (LIST_EMPTY(&savepgrp->pg_members))
|
||||
pgdelete(savepgrp);
|
||||
}
|
||||
@ -472,14 +465,12 @@ leavepgrp(p)
|
||||
|
||||
sx_assert(&proctree_lock, SX_XLOCKED);
|
||||
savepgrp = p->p_pgrp;
|
||||
mtx_lock(&Giant); /* XXX TTY */
|
||||
PGRP_LOCK(savepgrp);
|
||||
PROC_LOCK(p);
|
||||
LIST_REMOVE(p, p_pglist);
|
||||
p->p_pgrp = NULL;
|
||||
PROC_UNLOCK(p);
|
||||
PGRP_UNLOCK(savepgrp);
|
||||
mtx_unlock(&Giant); /* XXX TTY */
|
||||
if (LIST_EMPTY(&savepgrp->pg_members))
|
||||
pgdelete(savepgrp);
|
||||
return (0);
|
||||
@ -493,6 +484,7 @@ pgdelete(pgrp)
|
||||
register struct pgrp *pgrp;
|
||||
{
|
||||
struct session *savesess;
|
||||
struct tty *tp;
|
||||
|
||||
sx_assert(&proctree_lock, SX_XLOCKED);
|
||||
PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED);
|
||||
@ -504,18 +496,22 @@ pgdelete(pgrp)
|
||||
*/
|
||||
funsetownlst(&pgrp->pg_sigiolst);
|
||||
|
||||
mtx_lock(&Giant); /* XXX TTY */
|
||||
PGRP_LOCK(pgrp);
|
||||
if (pgrp->pg_session->s_ttyp != NULL &&
|
||||
pgrp->pg_session->s_ttyp->t_pgrp == pgrp)
|
||||
pgrp->pg_session->s_ttyp->t_pgrp = NULL;
|
||||
tp = pgrp->pg_session->s_ttyp;
|
||||
LIST_REMOVE(pgrp, pg_hash);
|
||||
savesess = pgrp->pg_session;
|
||||
SESSRELE(savesess);
|
||||
PGRP_UNLOCK(pgrp);
|
||||
|
||||
/* Remove the reference to the pgrp before deallocating it. */
|
||||
if (tp != NULL) {
|
||||
tty_lock(tp);
|
||||
tty_rel_pgrp(tp, pgrp);
|
||||
tty_unlock(tp);
|
||||
}
|
||||
|
||||
mtx_destroy(&pgrp->pg_mtx);
|
||||
FREE(pgrp, M_PGRP);
|
||||
mtx_unlock(&Giant); /* XXX TTY */
|
||||
sess_release(savesess);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -618,16 +614,21 @@ orphanpg(pg)
|
||||
}
|
||||
|
||||
void
|
||||
sessrele(struct session *s)
|
||||
sess_hold(struct session *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
SESS_LOCK(s);
|
||||
i = --s->s_count;
|
||||
SESS_UNLOCK(s);
|
||||
if (i == 0) {
|
||||
if (s->s_ttyp != NULL)
|
||||
ttyrel(s->s_ttyp);
|
||||
refcount_acquire(&s->s_count);
|
||||
}
|
||||
|
||||
void
|
||||
sess_release(struct session *s)
|
||||
{
|
||||
|
||||
if (refcount_release(&s->s_count)) {
|
||||
if (s->s_ttyp != NULL) {
|
||||
tty_lock(s->s_ttyp);
|
||||
tty_rel_sess(s->s_ttyp, s);
|
||||
}
|
||||
mtx_destroy(&s->s_mtx);
|
||||
FREE(s, M_SESSION);
|
||||
}
|
||||
@ -779,12 +780,13 @@ fill_kinfo_proc_only(struct proc *p, struct kinfo_proc *kp)
|
||||
kp->ki_kiflag |= KI_CTTY;
|
||||
if (SESS_LEADER(p))
|
||||
kp->ki_kiflag |= KI_SLEADER;
|
||||
/* XXX proctree_lock */
|
||||
tp = sp->s_ttyp;
|
||||
SESS_UNLOCK(sp);
|
||||
}
|
||||
}
|
||||
if ((p->p_flag & P_CONTROLT) && tp != NULL) {
|
||||
kp->ki_tdev = dev2udev(tp->t_dev);
|
||||
kp->ki_tdev = tty_udev(tp);
|
||||
kp->ki_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
|
||||
if (tp->t_session)
|
||||
kp->ki_tsid = tp->t_session->s_sid;
|
||||
@ -1122,9 +1124,10 @@ sysctl_kern_proc(SYSCTL_HANDLER_ARGS)
|
||||
PROC_UNLOCK(p);
|
||||
continue;
|
||||
}
|
||||
/* XXX proctree_lock */
|
||||
SESS_LOCK(p->p_session);
|
||||
if (p->p_session->s_ttyp == NULL ||
|
||||
dev2udev(p->p_session->s_ttyp->t_dev) !=
|
||||
tty_udev(p->p_session->s_ttyp) !=
|
||||
(dev_t)name[0]) {
|
||||
SESS_UNLOCK(p->p_session);
|
||||
PROC_UNLOCK(p);
|
||||
|
@ -1329,3 +1329,28 @@ chgsbsize(uip, hiwat, to, max)
|
||||
*hiwat = to;
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Change the count associated with number of pseudo-terminals
|
||||
* a given user is using. When 'max' is 0, don't enforce a limit
|
||||
*/
|
||||
int
|
||||
chgptscnt(uip, diff, max)
|
||||
struct uidinfo *uip;
|
||||
int diff;
|
||||
rlim_t max;
|
||||
{
|
||||
|
||||
/* Don't allow them to exceed max, but allow subtraction. */
|
||||
if (diff > 0 && max != 0) {
|
||||
if (atomic_fetchadd_long(&uip->ui_ptscnt, (long)diff) + diff > max) {
|
||||
atomic_subtract_long(&uip->ui_ptscnt, (long)diff);
|
||||
return (0);
|
||||
}
|
||||
} else {
|
||||
atomic_add_long(&uip->ui_ptscnt, (long)diff);
|
||||
if (uip->ui_ptscnt < 0)
|
||||
printf("negative ptscnt for uid = %d\n", uip->ui_uid);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ uprintf(const char *fmt, ...)
|
||||
if (td == NULL || TD_IS_IDLETHREAD(td))
|
||||
return (0);
|
||||
|
||||
mtx_lock(&Giant);
|
||||
sx_slock(&proctree_lock);
|
||||
p = td->td_proc;
|
||||
PROC_LOCK(p);
|
||||
if ((p->p_flag & P_CONTROLT) == 0) {
|
||||
@ -154,10 +154,12 @@ uprintf(const char *fmt, ...)
|
||||
}
|
||||
pca.flags = TOTTY;
|
||||
va_start(ap, fmt);
|
||||
tty_lock(pca.tty);
|
||||
retval = kvprintf(fmt, putchar, &pca, 10, ap);
|
||||
tty_unlock(pca.tty);
|
||||
va_end(ap);
|
||||
out:
|
||||
mtx_unlock(&Giant);
|
||||
sx_sunlock(&proctree_lock);
|
||||
return (retval);
|
||||
}
|
||||
|
||||
@ -174,19 +176,17 @@ tprintf(struct proc *p, int pri, const char *fmt, ...)
|
||||
struct putchar_arg pca;
|
||||
struct session *sess = NULL;
|
||||
|
||||
mtx_lock(&Giant);
|
||||
sx_slock(&proctree_lock);
|
||||
if (pri != -1)
|
||||
flags |= TOLOG;
|
||||
if (p != NULL) {
|
||||
PROC_LOCK(p);
|
||||
if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
|
||||
sess = p->p_session;
|
||||
SESS_LOCK(sess);
|
||||
sess_hold(sess);
|
||||
PROC_UNLOCK(p);
|
||||
SESSHOLD(sess);
|
||||
tp = sess->s_ttyp;
|
||||
SESS_UNLOCK(sess);
|
||||
if (ttycheckoutq(tp, 0))
|
||||
if (tp != NULL && tty_checkoutq(tp))
|
||||
flags |= TOTTY;
|
||||
else
|
||||
tp = NULL;
|
||||
@ -197,12 +197,16 @@ tprintf(struct proc *p, int pri, const char *fmt, ...)
|
||||
pca.tty = tp;
|
||||
pca.flags = flags;
|
||||
va_start(ap, fmt);
|
||||
if (pca.tty != NULL)
|
||||
tty_lock(pca.tty);
|
||||
kvprintf(fmt, putchar, &pca, 10, ap);
|
||||
if (pca.tty != NULL)
|
||||
tty_unlock(pca.tty);
|
||||
va_end(ap);
|
||||
if (sess != NULL)
|
||||
SESSRELE(sess);
|
||||
sess_release(sess);
|
||||
msgbuftrigger = 1;
|
||||
mtx_unlock(&Giant);
|
||||
sx_sunlock(&proctree_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -413,7 +417,7 @@ putchar(int c, void *arg)
|
||||
putcons(c, ap);
|
||||
} else {
|
||||
if ((flags & TOTTY) && tp != NULL)
|
||||
tputchar(c, tp);
|
||||
tty_putchar(tp, c);
|
||||
if (flags & TOCONS) {
|
||||
if (constty != NULL)
|
||||
msgbuf_addchar(&consmsgbuf, c);
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* DO NOT EDIT-- this file is automatically generated.
|
||||
* $FreeBSD$
|
||||
* created from FreeBSD: src/sys/kern/syscalls.master,v 1.242 2008/03/31 12:06:55 kib Exp
|
||||
* created from FreeBSD: head/sys/kern/syscalls.master 178888 2008-05-09 23:03:00Z julian
|
||||
*/
|
||||
|
||||
const char *syscallnames[] = {
|
||||
@ -511,4 +511,5 @@ const char *syscallnames[] = {
|
||||
"renameat", /* 501 = renameat */
|
||||
"symlinkat", /* 502 = symlinkat */
|
||||
"unlinkat", /* 503 = unlinkat */
|
||||
"posix_openpt", /* 504 = posix_openpt */
|
||||
};
|
||||
|
@ -886,5 +886,6 @@
|
||||
502 AUE_SYMLINKAT STD { int symlinkat(char *path1, int fd, \
|
||||
char *path2); }
|
||||
503 AUE_UNLINKAT STD { int unlinkat(int fd, char *path, int flag); }
|
||||
504 AUE_POSIXOPENPT STD { int posix_openpt(int flags); }
|
||||
; Please copy any additions and changes to the following compatability tables:
|
||||
; sys/compat/freebsd32/syscalls.master
|
||||
|
@ -3054,6 +3054,13 @@ systrace_args(int sysnum, void *params, u_int64_t *uarg, int *n_args)
|
||||
*n_args = 3;
|
||||
break;
|
||||
}
|
||||
/* posix_openpt */
|
||||
case 504: {
|
||||
struct posix_openpt_args *p = params;
|
||||
iarg[0] = p->flags; /* int */
|
||||
*n_args = 1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
*n_args = 0;
|
||||
break;
|
||||
@ -4607,6 +4614,16 @@ systrace_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
|
||||
break;
|
||||
};
|
||||
break;
|
||||
/* setfib */
|
||||
case 175:
|
||||
switch(ndx) {
|
||||
case 0:
|
||||
p = "int";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
break;
|
||||
/* ntp_adjtime */
|
||||
case 176:
|
||||
switch(ndx) {
|
||||
@ -8093,6 +8110,16 @@ systrace_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
|
||||
break;
|
||||
};
|
||||
break;
|
||||
/* posix_openpt */
|
||||
case 504:
|
||||
switch(ndx) {
|
||||
case 0:
|
||||
p = "int";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
4470
sys/kern/tty.c
4470
sys/kern/tty.c
File diff suppressed because it is too large
Load Diff
@ -45,6 +45,11 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
struct speedtab {
|
||||
int sp_speed; /* Speed. */
|
||||
int sp_code; /* Code. */
|
||||
};
|
||||
|
||||
static int ttcompatgetflags(struct tty *tp);
|
||||
static void ttcompatsetflags(struct tty *tp, struct termios *t);
|
||||
static void ttcompatsetlflags(struct tty *tp, struct termios *t);
|
||||
@ -102,16 +107,18 @@ ttsetcompat(struct tty *tp, u_long *com, caddr_t data, struct termios *term)
|
||||
|
||||
if ((speed = sg->sg_ispeed) > MAX_SPEED || speed < 0)
|
||||
return(EINVAL);
|
||||
else if (speed != ttcompatspeedtab(tp->t_ispeed, compatspeeds))
|
||||
else if (speed != ttcompatspeedtab(tp->t_termios.c_ispeed,
|
||||
compatspeeds))
|
||||
term->c_ispeed = compatspcodes[speed];
|
||||
else
|
||||
term->c_ispeed = tp->t_ispeed;
|
||||
term->c_ispeed = tp->t_termios.c_ispeed;
|
||||
if ((speed = sg->sg_ospeed) > MAX_SPEED || speed < 0)
|
||||
return(EINVAL);
|
||||
else if (speed != ttcompatspeedtab(tp->t_ospeed, compatspeeds))
|
||||
else if (speed != ttcompatspeedtab(tp->t_termios.c_ospeed,
|
||||
compatspeeds))
|
||||
term->c_ospeed = compatspcodes[speed];
|
||||
else
|
||||
term->c_ospeed = tp->t_ospeed;
|
||||
term->c_ospeed = tp->t_termios.c_ospeed;
|
||||
term->c_cc[VERASE] = sg->sg_erase;
|
||||
term->c_cc[VKILL] = sg->sg_kill;
|
||||
tp->t_flags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff);
|
||||
@ -171,7 +178,7 @@ ttsetcompat(struct tty *tp, u_long *com, caddr_t data, struct termios *term)
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
ttcompat(struct tty *tp, u_long com, caddr_t data, int flag)
|
||||
tty_ioctl_compat(struct tty *tp, u_long com, caddr_t data, struct thread *td)
|
||||
{
|
||||
switch (com) {
|
||||
case TIOCSETP:
|
||||
@ -187,17 +194,19 @@ ttcompat(struct tty *tp, u_long com, caddr_t data, int flag)
|
||||
term = tp->t_termios;
|
||||
if ((error = ttsetcompat(tp, &com, data, &term)) != 0)
|
||||
return error;
|
||||
return ttioctl(tp, com, &term, flag);
|
||||
return tty_ioctl(tp, com, &term, td);
|
||||
}
|
||||
case TIOCGETP: {
|
||||
struct sgttyb *sg = (struct sgttyb *)data;
|
||||
cc_t *cc = tp->t_cc;
|
||||
cc_t *cc = tp->t_termios.c_cc;
|
||||
|
||||
sg->sg_ospeed = ttcompatspeedtab(tp->t_ospeed, compatspeeds);
|
||||
if (tp->t_ispeed == 0)
|
||||
sg->sg_ospeed = ttcompatspeedtab(tp->t_termios.c_ospeed,
|
||||
compatspeeds);
|
||||
if (tp->t_termios.c_ispeed == 0)
|
||||
sg->sg_ispeed = sg->sg_ospeed;
|
||||
else
|
||||
sg->sg_ispeed = ttcompatspeedtab(tp->t_ispeed, compatspeeds);
|
||||
sg->sg_ispeed = ttcompatspeedtab(tp->t_termios.c_ispeed,
|
||||
compatspeeds);
|
||||
sg->sg_erase = cc[VERASE];
|
||||
sg->sg_kill = cc[VKILL];
|
||||
sg->sg_flags = tp->t_flags = ttcompatgetflags(tp);
|
||||
@ -205,7 +214,7 @@ ttcompat(struct tty *tp, u_long com, caddr_t data, int flag)
|
||||
}
|
||||
case TIOCGETC: {
|
||||
struct tchars *tc = (struct tchars *)data;
|
||||
cc_t *cc = tp->t_cc;
|
||||
cc_t *cc = tp->t_termios.c_cc;
|
||||
|
||||
tc->t_intrc = cc[VINTR];
|
||||
tc->t_quitc = cc[VQUIT];
|
||||
@ -217,7 +226,7 @@ ttcompat(struct tty *tp, u_long com, caddr_t data, int flag)
|
||||
}
|
||||
case TIOCGLTC: {
|
||||
struct ltchars *ltc = (struct ltchars *)data;
|
||||
cc_t *cc = tp->t_cc;
|
||||
cc_t *cc = tp->t_termios.c_cc;
|
||||
|
||||
ltc->t_suspc = cc[VSUSP];
|
||||
ltc->t_dsuspc = cc[VDSUSP];
|
||||
@ -237,19 +246,19 @@ ttcompat(struct tty *tp, u_long com, caddr_t data, int flag)
|
||||
break;
|
||||
|
||||
case OTIOCGETD:
|
||||
*(int *)data = tp->t_line ? tp->t_line : 2;
|
||||
*(int *)data = 2;
|
||||
break;
|
||||
|
||||
case OTIOCSETD: {
|
||||
int ldisczero = 0;
|
||||
|
||||
return (ttioctl(tp, TIOCSETD,
|
||||
*(int *)data == 2 ? (caddr_t)&ldisczero : data, flag));
|
||||
return (tty_ioctl(tp, TIOCSETD,
|
||||
*(int *)data == 2 ? (caddr_t)&ldisczero : data, td));
|
||||
}
|
||||
|
||||
case OTIOCCONS:
|
||||
*(int *)data = 1;
|
||||
return (ttioctl(tp, TIOCCONS, data, flag));
|
||||
return (tty_ioctl(tp, TIOCCONS, data, td));
|
||||
|
||||
default:
|
||||
return (ENOIOCTL);
|
||||
@ -260,10 +269,10 @@ ttcompat(struct tty *tp, u_long com, caddr_t data, int flag)
|
||||
static int
|
||||
ttcompatgetflags(struct tty *tp)
|
||||
{
|
||||
tcflag_t iflag = tp->t_iflag;
|
||||
tcflag_t lflag = tp->t_lflag;
|
||||
tcflag_t oflag = tp->t_oflag;
|
||||
tcflag_t cflag = tp->t_cflag;
|
||||
tcflag_t iflag = tp->t_termios.c_iflag;
|
||||
tcflag_t lflag = tp->t_termios.c_lflag;
|
||||
tcflag_t oflag = tp->t_termios.c_oflag;
|
||||
tcflag_t cflag = tp->t_termios.c_cflag;
|
||||
int flags = 0;
|
||||
|
||||
if (iflag&IXOFF)
|
||||
@ -299,7 +308,7 @@ ttcompatgetflags(struct tty *tp)
|
||||
flags |= MDMBUF;
|
||||
if ((cflag&HUPCL) == 0)
|
||||
flags |= NOHANG;
|
||||
if (oflag&OXTABS)
|
||||
if (oflag&TAB3)
|
||||
flags |= XTABS;
|
||||
if (lflag&ECHOE)
|
||||
flags |= CRTERA|CRTBS;
|
||||
@ -334,9 +343,9 @@ ttcompatsetflags(struct tty *tp, struct termios *t)
|
||||
iflag |= BRKINT|IXON|IMAXBEL;
|
||||
lflag |= ISIG|IEXTEN|ECHOCTL; /* XXX was echoctl on ? */
|
||||
if (flags & XTABS)
|
||||
oflag |= OXTABS;
|
||||
oflag |= TAB3;
|
||||
else
|
||||
oflag &= ~OXTABS;
|
||||
oflag &= ~TAB3;
|
||||
if (flags & CBREAK)
|
||||
lflag &= ~ICANON;
|
||||
else
|
||||
|
@ -1,205 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2004 Poul-Henning Kamp. All rights reserved.
|
||||
* Copyright (c) 1982, 1986, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* (c) UNIX System Laboratories, Inc.
|
||||
* All or some portions of this file are derived from material licensed
|
||||
* to the University of California by American Telephone and Telegraph
|
||||
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
|
||||
* the permission of UNIX System Laboratories, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)tty_conf.c 8.4 (Berkeley) 1/21/94
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "opt_compat.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/tty.h>
|
||||
#include <sys/conf.h>
|
||||
|
||||
#ifndef MAXLDISC
|
||||
#define MAXLDISC 9
|
||||
#endif
|
||||
|
||||
static l_open_t l_noopen;
|
||||
static l_close_t l_noclose;
|
||||
static l_rint_t l_norint;
|
||||
static l_start_t l_nostart;
|
||||
|
||||
/*
|
||||
* XXX it probably doesn't matter what the entries other than the l_open
|
||||
* entry are here. The l_nullioctl and ttymodem entries still look fishy.
|
||||
* Reconsider the removal of nullmodem anyway. It was too much like
|
||||
* ttymodem, but a completely null version might be useful.
|
||||
*/
|
||||
|
||||
static struct linesw nodisc = {
|
||||
.l_open = l_noopen,
|
||||
.l_close = l_noclose,
|
||||
.l_read = l_noread,
|
||||
.l_write = l_nowrite,
|
||||
.l_ioctl = l_nullioctl,
|
||||
.l_rint = l_norint,
|
||||
.l_start = l_nostart,
|
||||
.l_modem = ttymodem
|
||||
};
|
||||
|
||||
static struct linesw termios_disc = {
|
||||
.l_open = tty_open,
|
||||
.l_close = ttylclose,
|
||||
.l_read = ttread,
|
||||
.l_write = ttwrite,
|
||||
.l_ioctl = l_nullioctl,
|
||||
.l_rint = ttyinput,
|
||||
.l_start = ttstart,
|
||||
.l_modem = ttymodem
|
||||
};
|
||||
|
||||
#ifdef COMPAT_43
|
||||
# define ntty_disc termios_disc
|
||||
#else
|
||||
# define ntty_disc nodisc
|
||||
#endif
|
||||
|
||||
struct linesw *linesw[MAXLDISC] = {
|
||||
&termios_disc, /* 0 - termios */
|
||||
&nodisc, /* 1 - defunct */
|
||||
&ntty_disc, /* 2 - NTTYDISC */
|
||||
&nodisc, /* 3 - loadable */
|
||||
&nodisc, /* 4 - SLIPDISC */
|
||||
&nodisc, /* 5 - PPPDISC */
|
||||
&nodisc, /* 6 - NETGRAPHDISC */
|
||||
&nodisc, /* 7 - loadable */
|
||||
&nodisc, /* 8 - loadable */
|
||||
};
|
||||
|
||||
int nlinesw = sizeof (linesw) / sizeof (linesw[0]);
|
||||
|
||||
#define LOADABLE_LDISC 7
|
||||
|
||||
/*
|
||||
* ldisc_register: Register a line discipline.
|
||||
*
|
||||
* discipline: Index for discipline to load, or LDISC_LOAD for us to choose.
|
||||
* linesw_p: Pointer to linesw_p.
|
||||
*
|
||||
* Returns: Index used or -1 on failure.
|
||||
*/
|
||||
|
||||
int
|
||||
ldisc_register(int discipline, struct linesw *linesw_p)
|
||||
{
|
||||
int slot = -1;
|
||||
|
||||
if (discipline == LDISC_LOAD) {
|
||||
int i;
|
||||
for (i = LOADABLE_LDISC; i < MAXLDISC; i++)
|
||||
if (linesw[i] == &nodisc) {
|
||||
slot = i;
|
||||
break;
|
||||
}
|
||||
} else if (discipline >= 0 && discipline < MAXLDISC) {
|
||||
slot = discipline;
|
||||
}
|
||||
|
||||
if (slot != -1 && linesw_p)
|
||||
linesw[slot] = linesw_p;
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
/*
|
||||
* ldisc_deregister: Deregister a line discipline obtained with
|
||||
* ldisc_register.
|
||||
*
|
||||
* discipline: Index for discipline to unload.
|
||||
*/
|
||||
|
||||
void
|
||||
ldisc_deregister(int discipline)
|
||||
{
|
||||
|
||||
if (discipline < MAXLDISC)
|
||||
linesw[discipline] = &nodisc;
|
||||
}
|
||||
|
||||
/*
|
||||
* "no" and "null" versions of line discipline functions
|
||||
*/
|
||||
|
||||
static int
|
||||
l_noopen(struct cdev *dev, struct tty *tp)
|
||||
{
|
||||
|
||||
return (ENODEV);
|
||||
}
|
||||
|
||||
static int
|
||||
l_noclose(struct tty *tp, int flag)
|
||||
{
|
||||
|
||||
return (ENODEV);
|
||||
}
|
||||
|
||||
int
|
||||
l_noread(struct tty *tp, struct uio *uio, int flag)
|
||||
{
|
||||
|
||||
return (ENODEV);
|
||||
}
|
||||
|
||||
int
|
||||
l_nowrite(struct tty *tp, struct uio *uio, int flag)
|
||||
{
|
||||
|
||||
return (ENODEV);
|
||||
}
|
||||
|
||||
static int
|
||||
l_norint(int c, struct tty *tp)
|
||||
{
|
||||
|
||||
return (ENODEV);
|
||||
}
|
||||
|
||||
static int
|
||||
l_nostart(struct tty *tp)
|
||||
{
|
||||
|
||||
return (ENODEV);
|
||||
}
|
||||
|
||||
int
|
||||
l_nullioctl(struct tty *tp, u_long cmd, char *data, int flags, struct thread *td)
|
||||
{
|
||||
|
||||
return (ENOIOCTL);
|
||||
}
|
@ -711,9 +711,18 @@ constty_timeout(void *arg)
|
||||
{
|
||||
int c;
|
||||
|
||||
while (constty != NULL && (c = msgbuf_getchar(&consmsgbuf)) != -1) {
|
||||
if (tputchar(c, constty) < 0)
|
||||
constty = NULL;
|
||||
if (constty != NULL) {
|
||||
tty_lock(constty);
|
||||
while ((c = msgbuf_getchar(&consmsgbuf)) != -1) {
|
||||
if (tty_putchar(constty, c) < 0) {
|
||||
tty_unlock(constty);
|
||||
constty = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (constty != NULL)
|
||||
tty_unlock(constty);
|
||||
}
|
||||
if (constty != NULL) {
|
||||
callout_reset(&conscallout, hz / constty_wakeups_per_second,
|
||||
|
@ -211,7 +211,7 @@ proc_compare(struct proc *p1, struct proc *p2)
|
||||
* Report on state of foreground process group.
|
||||
*/
|
||||
void
|
||||
ttyinfo(struct tty *tp)
|
||||
tty_info(struct tty *tp)
|
||||
{
|
||||
struct timeval utime, stime;
|
||||
struct proc *p, *pick;
|
||||
@ -223,32 +223,27 @@ ttyinfo(struct tty *tp)
|
||||
char comm[MAXCOMLEN + 1];
|
||||
struct rusage ru;
|
||||
|
||||
if (ttycheckoutq(tp,0) == 0)
|
||||
tty_lock_assert(tp, MA_OWNED);
|
||||
|
||||
if (tty_checkoutq(tp) == 0)
|
||||
return;
|
||||
|
||||
/* Print load average. */
|
||||
load = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT;
|
||||
ttyprintf(tp, "load: %d.%02d ", load / 100, load % 100);
|
||||
|
||||
/*
|
||||
* On return following a ttyprintf(), we set tp->t_rocount to 0 so
|
||||
* that pending input will be retyped on BS.
|
||||
*/
|
||||
if (tp->t_session == NULL) {
|
||||
ttyprintf(tp, "not a controlling terminal\n");
|
||||
tp->t_rocount = 0;
|
||||
return;
|
||||
}
|
||||
if (tp->t_pgrp == NULL) {
|
||||
ttyprintf(tp, "no foreground process group\n");
|
||||
tp->t_rocount = 0;
|
||||
return;
|
||||
}
|
||||
PGRP_LOCK(tp->t_pgrp);
|
||||
if (LIST_EMPTY(&tp->t_pgrp->pg_members)) {
|
||||
PGRP_UNLOCK(tp->t_pgrp);
|
||||
ttyprintf(tp, "empty foreground process group\n");
|
||||
tp->t_rocount = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -313,5 +308,4 @@ ttyinfo(struct tty *tp)
|
||||
(long)utime.tv_sec, utime.tv_usec / 10000,
|
||||
(long)stime.tv_sec, stime.tv_usec / 10000,
|
||||
pctcpu / 100, rss);
|
||||
tp->t_rocount = 0;
|
||||
}
|
||||
|
502
sys/kern/tty_inq.c
Normal file
502
sys/kern/tty_inq.c
Normal file
@ -0,0 +1,502 @@
|
||||
/*-
|
||||
* Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions of this software were developed under sponsorship from Snow
|
||||
* B.V., the Netherlands.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/tty.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include <vm/uma.h>
|
||||
|
||||
/*
|
||||
* TTY input queue buffering.
|
||||
*
|
||||
* Unlike the output queue, the input queue has more features that are
|
||||
* needed to properly implement various features offered by the TTY
|
||||
* interface:
|
||||
*
|
||||
* - Data can be removed from the tail of the queue, which is used to
|
||||
* implement backspace.
|
||||
* - Once in a while, input has to be `canonicalized'. When ICANON is
|
||||
* turned on, this will be done after a CR has been inserted.
|
||||
* Otherwise, it should be done after any character has been inserted.
|
||||
* - The input queue can store one bit per byte, called the quoting bit.
|
||||
* This bit is used by TTYDISC to make backspace work on quoted
|
||||
* characters.
|
||||
*
|
||||
* In most cases, there is probably less input than output, so unlike
|
||||
* the outq, we'll stick to 128 byte blocks here.
|
||||
*/
|
||||
|
||||
/* Statistics. */
|
||||
static long ttyinq_nfast = 0;
|
||||
SYSCTL_LONG(_kern, OID_AUTO, tty_inq_nfast, CTLFLAG_RD,
|
||||
&ttyinq_nfast, 0, "Unbuffered reads to userspace on input");
|
||||
static long ttyinq_nslow = 0;
|
||||
SYSCTL_LONG(_kern, OID_AUTO, tty_inq_nslow, CTLFLAG_RD,
|
||||
&ttyinq_nslow, 0, "Buffered reads to userspace on input");
|
||||
|
||||
#define TTYINQ_QUOTESIZE (TTYINQ_DATASIZE / BMSIZE)
|
||||
#define BMSIZE 32
|
||||
#define GETBIT(tib,boff) \
|
||||
((tib)->tib_quotes[(boff) / BMSIZE] & (1 << ((boff) % BMSIZE)))
|
||||
#define SETBIT(tib,boff) \
|
||||
((tib)->tib_quotes[(boff) / BMSIZE] |= (1 << ((boff) % BMSIZE)))
|
||||
#define CLRBIT(tib,boff) \
|
||||
((tib)->tib_quotes[(boff) / BMSIZE] &= ~(1 << ((boff) % BMSIZE)))
|
||||
|
||||
struct ttyinq_block {
|
||||
TAILQ_ENTRY(ttyinq_block) tib_list;
|
||||
uint32_t tib_quotes[TTYINQ_QUOTESIZE];
|
||||
char tib_data[TTYINQ_DATASIZE];
|
||||
};
|
||||
|
||||
static uma_zone_t ttyinq_zone;
|
||||
|
||||
void
|
||||
ttyinq_setsize(struct ttyinq *ti, struct tty *tp, size_t size)
|
||||
{
|
||||
unsigned int nblocks;
|
||||
struct ttyinq_block *tib;
|
||||
|
||||
nblocks = howmany(size, TTYINQ_DATASIZE);
|
||||
|
||||
while (nblocks > ti->ti_nblocks) {
|
||||
/*
|
||||
* List is getting bigger.
|
||||
* Add new blocks to the tail of the list.
|
||||
*
|
||||
* We must unlock the TTY temporarily, because we need
|
||||
* to allocate memory. This won't be a problem, because
|
||||
* in the worst case, another thread ends up here, which
|
||||
* may cause us to allocate too many blocks, but this
|
||||
* will be caught by the loop below.
|
||||
*/
|
||||
tty_unlock(tp);
|
||||
tib = uma_zalloc(ttyinq_zone, M_WAITOK);
|
||||
tty_lock(tp);
|
||||
|
||||
if (tty_gone(tp))
|
||||
return;
|
||||
|
||||
TAILQ_INSERT_TAIL(&ti->ti_list, tib, tib_list);
|
||||
ti->ti_nblocks++;
|
||||
}
|
||||
|
||||
while (nblocks < ti->ti_nblocks) {
|
||||
/*
|
||||
* List is getting smaller. Remove unused blocks at the
|
||||
* end. This means we cannot guarantee this routine
|
||||
* shrinks buffers properly, when we need to reclaim
|
||||
* more space than there is available.
|
||||
*
|
||||
* XXX TODO: Two solutions here:
|
||||
* - Throw data away
|
||||
* - Temporarily hit the watermark until enough data has
|
||||
* been flushed, so we can remove the blocks.
|
||||
*/
|
||||
|
||||
if (ti->ti_end == 0)
|
||||
tib = TAILQ_FIRST(&ti->ti_list);
|
||||
else
|
||||
tib = TAILQ_NEXT(ti->ti_lastblock, tib_list);
|
||||
if (tib == NULL)
|
||||
break;
|
||||
TAILQ_REMOVE(&ti->ti_list, tib, tib_list);
|
||||
uma_zfree(ttyinq_zone, tib);
|
||||
ti->ti_nblocks--;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
ttyinq_read_uio(struct ttyinq *ti, struct tty *tp, struct uio *uio,
|
||||
size_t rlen, size_t flen)
|
||||
{
|
||||
|
||||
MPASS(rlen <= uio->uio_resid);
|
||||
|
||||
while (rlen > 0) {
|
||||
int error;
|
||||
struct ttyinq_block *tib;
|
||||
size_t cbegin, cend, clen;
|
||||
|
||||
/* See if there still is data. */
|
||||
if (ti->ti_begin == ti->ti_linestart)
|
||||
return (0);
|
||||
tib = TAILQ_FIRST(&ti->ti_list);
|
||||
if (tib == NULL)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* The end address should be the lowest of these three:
|
||||
* - The write pointer
|
||||
* - The blocksize - we can't read beyond the block
|
||||
* - The end address if we could perform the full read
|
||||
*/
|
||||
cbegin = ti->ti_begin;
|
||||
cend = MIN(MIN(ti->ti_linestart, ti->ti_begin + rlen),
|
||||
TTYINQ_DATASIZE);
|
||||
clen = cend - cbegin;
|
||||
MPASS(clen >= flen);
|
||||
rlen -= clen;
|
||||
|
||||
/*
|
||||
* We can prevent buffering in some cases:
|
||||
* - We need to read the block until the end.
|
||||
* - We don't need to read the block until the end, but
|
||||
* there is no data beyond it, which allows us to move
|
||||
* the write pointer to a new block.
|
||||
*/
|
||||
if (cend == TTYINQ_DATASIZE || cend == ti->ti_end) {
|
||||
atomic_add_long(&ttyinq_nfast, 1);
|
||||
|
||||
/*
|
||||
* Fast path: zero copy. Remove the first block,
|
||||
* so we can unlock the TTY temporarily.
|
||||
*/
|
||||
TAILQ_REMOVE(&ti->ti_list, tib, tib_list);
|
||||
ti->ti_nblocks--;
|
||||
ti->ti_begin = 0;
|
||||
|
||||
/*
|
||||
* Because we remove the first block, we must
|
||||
* fix up the block offsets.
|
||||
*/
|
||||
#define CORRECT_BLOCK(t) do { \
|
||||
if (t <= TTYINQ_DATASIZE) { \
|
||||
t = 0; \
|
||||
} else { \
|
||||
t -= TTYINQ_DATASIZE; \
|
||||
} \
|
||||
} while (0)
|
||||
CORRECT_BLOCK(ti->ti_linestart);
|
||||
CORRECT_BLOCK(ti->ti_reprint);
|
||||
CORRECT_BLOCK(ti->ti_end);
|
||||
#undef CORRECT_BLOCK
|
||||
|
||||
/*
|
||||
* Temporary unlock and copy the data to
|
||||
* userspace. We may need to flush trailing
|
||||
* bytes, like EOF characters.
|
||||
*/
|
||||
tty_unlock(tp);
|
||||
error = uiomove(tib->tib_data + cbegin,
|
||||
clen - flen, uio);
|
||||
tty_lock(tp);
|
||||
|
||||
if (tty_gone(tp)) {
|
||||
/* Something went bad - discard this block. */
|
||||
uma_zfree(ttyinq_zone, tib);
|
||||
return (ENXIO);
|
||||
}
|
||||
/* Block can now be readded to the list. */
|
||||
/*
|
||||
* XXX: we could remove the blocks here when the
|
||||
* queue was shrunk, but still in use. See
|
||||
* ttyinq_setsize().
|
||||
*/
|
||||
TAILQ_INSERT_TAIL(&ti->ti_list, tib, tib_list);
|
||||
ti->ti_nblocks++;
|
||||
if (error != 0)
|
||||
return (error);
|
||||
} else {
|
||||
char ob[TTYINQ_DATASIZE - 1];
|
||||
atomic_add_long(&ttyinq_nslow, 1);
|
||||
|
||||
/*
|
||||
* Slow path: store data in a temporary buffer.
|
||||
*/
|
||||
memcpy(ob, tib->tib_data + cbegin, clen - flen);
|
||||
ti->ti_begin += clen;
|
||||
MPASS(ti->ti_begin < TTYINQ_DATASIZE);
|
||||
|
||||
/* Temporary unlock and copy the data to userspace. */
|
||||
tty_unlock(tp);
|
||||
error = uiomove(ob, clen - flen, uio);
|
||||
tty_lock(tp);
|
||||
|
||||
if (error != 0)
|
||||
return (error);
|
||||
if (tty_gone(tp))
|
||||
return (ENXIO);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ttyinq_set_quotes(struct ttyinq_block *tib, size_t offset,
|
||||
size_t length, int value)
|
||||
{
|
||||
|
||||
if (value) {
|
||||
/* Set the bits. */
|
||||
for (; length > 0; length--, offset++)
|
||||
SETBIT(tib, offset);
|
||||
} else {
|
||||
/* Unset the bits. */
|
||||
for (; length > 0; length--, offset++)
|
||||
CLRBIT(tib, offset);
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
ttyinq_write(struct ttyinq *ti, const void *buf, size_t nbytes, int quote)
|
||||
{
|
||||
const char *cbuf = buf;
|
||||
struct ttyinq_block *tib;
|
||||
unsigned int boff;
|
||||
size_t l;
|
||||
|
||||
while (nbytes > 0) {
|
||||
tib = ti->ti_lastblock;
|
||||
boff = ti->ti_end % TTYINQ_DATASIZE;
|
||||
|
||||
if (ti->ti_end == 0) {
|
||||
/* First time we're being used or drained. */
|
||||
MPASS(ti->ti_begin == 0);
|
||||
tib = ti->ti_lastblock = TAILQ_FIRST(&ti->ti_list);
|
||||
if (tib == NULL) {
|
||||
/* Queue has no blocks. */
|
||||
break;
|
||||
}
|
||||
} else if (boff == 0) {
|
||||
/* We reached the end of this block on last write. */
|
||||
tib = TAILQ_NEXT(tib, tib_list);
|
||||
if (tib == NULL) {
|
||||
/* We've reached the watermark. */
|
||||
break;
|
||||
}
|
||||
ti->ti_lastblock = tib;
|
||||
}
|
||||
|
||||
/* Don't copy more than was requested. */
|
||||
l = MIN(nbytes, TTYINQ_DATASIZE - boff);
|
||||
MPASS(l > 0);
|
||||
memcpy(tib->tib_data + boff, cbuf, l);
|
||||
|
||||
/* Set the quoting bits for the proper region. */
|
||||
ttyinq_set_quotes(tib, boff, l, quote);
|
||||
|
||||
cbuf += l;
|
||||
nbytes -= l;
|
||||
ti->ti_end += l;
|
||||
}
|
||||
|
||||
return (cbuf - (const char *)buf);
|
||||
}
|
||||
|
||||
int
|
||||
ttyinq_write_nofrag(struct ttyinq *ti, const void *buf, size_t nbytes, int quote)
|
||||
{
|
||||
size_t ret;
|
||||
|
||||
if (ttyinq_bytesleft(ti) < nbytes)
|
||||
return (-1);
|
||||
|
||||
/* We should always be able to write it back. */
|
||||
ret = ttyinq_write(ti, buf, nbytes, quote);
|
||||
MPASS(ret == nbytes);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
ttyinq_canonicalize(struct ttyinq *ti)
|
||||
{
|
||||
|
||||
ti->ti_linestart = ti->ti_reprint = ti->ti_end;
|
||||
ti->ti_startblock = ti->ti_reprintblock = ti->ti_lastblock;
|
||||
}
|
||||
|
||||
size_t
|
||||
ttyinq_findchar(struct ttyinq *ti, const char *breakc, size_t maxlen,
|
||||
char *lastc)
|
||||
{
|
||||
struct ttyinq_block *tib = TAILQ_FIRST(&ti->ti_list);
|
||||
unsigned int boff = ti->ti_begin;
|
||||
unsigned int bend = MIN(MIN(TTYINQ_DATASIZE, ti->ti_linestart),
|
||||
ti->ti_begin + maxlen);
|
||||
|
||||
MPASS(maxlen > 0);
|
||||
|
||||
if (tib == NULL)
|
||||
return (0);
|
||||
|
||||
while (boff < bend) {
|
||||
if (index(breakc, tib->tib_data[boff]) && !GETBIT(tib, boff)) {
|
||||
*lastc = tib->tib_data[boff];
|
||||
return (boff - ti->ti_begin + 1);
|
||||
}
|
||||
boff++;
|
||||
}
|
||||
|
||||
/* Not found - just process the entire block. */
|
||||
return (bend - ti->ti_begin);
|
||||
}
|
||||
|
||||
void
|
||||
ttyinq_flush(struct ttyinq *ti)
|
||||
{
|
||||
|
||||
ti->ti_begin = 0;
|
||||
ti->ti_linestart = 0;
|
||||
ti->ti_reprint = 0;
|
||||
ti->ti_end = 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void
|
||||
ttyinq_flush_safe(struct ttyinq *ti)
|
||||
{
|
||||
struct ttyinq_block *tib;
|
||||
|
||||
ttyinq_flush(ti);
|
||||
|
||||
/* Zero all data in the input queue to make it more safe */
|
||||
TAILQ_FOREACH(tib, &ti->ti_list, tib_list) {
|
||||
bzero(&tib->tib_quotes, sizeof tib->tib_quotes);
|
||||
bzero(&tib->tib_data, sizeof tib->tib_data);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
ttyinq_peekchar(struct ttyinq *ti, char *c, int *quote)
|
||||
{
|
||||
unsigned int boff;
|
||||
struct ttyinq_block *tib = ti->ti_lastblock;
|
||||
|
||||
if (ti->ti_linestart == ti->ti_end)
|
||||
return (-1);
|
||||
|
||||
MPASS(ti->ti_end > 0);
|
||||
boff = (ti->ti_end - 1) % TTYINQ_DATASIZE;
|
||||
|
||||
*c = tib->tib_data[boff];
|
||||
*quote = GETBIT(tib, boff);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
ttyinq_unputchar(struct ttyinq *ti)
|
||||
{
|
||||
|
||||
MPASS(ti->ti_linestart < ti->ti_end);
|
||||
|
||||
if (--ti->ti_end % TTYINQ_DATASIZE == 0) {
|
||||
/* Roll back to the previous block. */
|
||||
ti->ti_lastblock = TAILQ_PREV(ti->ti_lastblock,
|
||||
ttyinq_bhead, tib_list);
|
||||
/*
|
||||
* This can only fail if we are unputchar()'ing the
|
||||
* first character in the queue.
|
||||
*/
|
||||
MPASS((ti->ti_lastblock == NULL) == (ti->ti_end == 0));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ttyinq_reprintpos_set(struct ttyinq *ti)
|
||||
{
|
||||
|
||||
ti->ti_reprint = ti->ti_end;
|
||||
ti->ti_reprintblock = ti->ti_lastblock;
|
||||
}
|
||||
|
||||
void
|
||||
ttyinq_reprintpos_reset(struct ttyinq *ti)
|
||||
{
|
||||
|
||||
ti->ti_reprint = ti->ti_linestart;
|
||||
ti->ti_reprintblock = ti->ti_startblock;
|
||||
}
|
||||
|
||||
static void
|
||||
ttyinq_line_iterate(struct ttyinq *ti,
|
||||
ttyinq_line_iterator_t *iterator, void *data,
|
||||
unsigned int offset, struct ttyinq_block *tib)
|
||||
{
|
||||
unsigned int boff;
|
||||
|
||||
/* Use the proper block when we're at the queue head. */
|
||||
if (offset == 0)
|
||||
tib = TAILQ_FIRST(&ti->ti_list);
|
||||
|
||||
/* Iterate all characters and call the iterator function. */
|
||||
for (; offset < ti->ti_end; offset++) {
|
||||
boff = offset % TTYINQ_DATASIZE;
|
||||
MPASS(tib != NULL);
|
||||
|
||||
/* Call back the iterator function. */
|
||||
iterator(data, tib->tib_data[boff], GETBIT(tib, boff));
|
||||
|
||||
/* Last byte iterated - go to the next block. */
|
||||
if (boff == TTYINQ_DATASIZE - 1)
|
||||
tib = TAILQ_NEXT(tib, tib_list);
|
||||
MPASS(tib != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ttyinq_line_iterate_from_linestart(struct ttyinq *ti,
|
||||
ttyinq_line_iterator_t *iterator, void *data)
|
||||
{
|
||||
|
||||
ttyinq_line_iterate(ti, iterator, data,
|
||||
ti->ti_linestart, ti->ti_startblock);
|
||||
}
|
||||
|
||||
void
|
||||
ttyinq_line_iterate_from_reprintpos(struct ttyinq *ti,
|
||||
ttyinq_line_iterator_t *iterator, void *data)
|
||||
{
|
||||
|
||||
ttyinq_line_iterate(ti, iterator, data,
|
||||
ti->ti_reprint, ti->ti_reprintblock);
|
||||
}
|
||||
|
||||
static void
|
||||
ttyinq_startup(void *dummy)
|
||||
{
|
||||
|
||||
ttyinq_zone = uma_zcreate("ttyinq", sizeof(struct ttyinq_block),
|
||||
NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
|
||||
}
|
||||
|
||||
SYSINIT(ttyinq, SI_SUB_DRIVERS, SI_ORDER_FIRST, ttyinq_startup, NULL);
|
365
sys/kern/tty_outq.c
Normal file
365
sys/kern/tty_outq.c
Normal file
@ -0,0 +1,365 @@
|
||||
/*-
|
||||
* Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions of this software were developed under sponsorship from Snow
|
||||
* B.V., the Netherlands.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/tty.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include <vm/uma.h>
|
||||
|
||||
/*
|
||||
* TTY output queue buffering.
|
||||
*
|
||||
* The previous design of the TTY layer offered the so-called clists.
|
||||
* These clists were used for both the input queues and the output
|
||||
* queue. We don't use certain features on the output side, like quoting
|
||||
* bits for parity marking and such. This mechanism is similar to the
|
||||
* old clists, but only contains the features we need to buffer the
|
||||
* output.
|
||||
*/
|
||||
|
||||
/* Statistics. */
|
||||
static long ttyoutq_nfast = 0;
|
||||
SYSCTL_LONG(_kern, OID_AUTO, tty_outq_nfast, CTLFLAG_RD,
|
||||
&ttyoutq_nfast, 0, "Unbuffered reads to userspace on output");
|
||||
static long ttyoutq_nslow = 0;
|
||||
SYSCTL_LONG(_kern, OID_AUTO, tty_outq_nslow, CTLFLAG_RD,
|
||||
&ttyoutq_nslow, 0, "Buffered reads to userspace on output");
|
||||
|
||||
struct ttyoutq_block {
|
||||
STAILQ_ENTRY(ttyoutq_block) tob_list;
|
||||
char tob_data[TTYOUTQ_DATASIZE];
|
||||
};
|
||||
|
||||
static uma_zone_t ttyoutq_zone;
|
||||
|
||||
void
|
||||
ttyoutq_flush(struct ttyoutq *to)
|
||||
{
|
||||
|
||||
to->to_begin = 0;
|
||||
to->to_end = 0;
|
||||
}
|
||||
|
||||
void
|
||||
ttyoutq_setsize(struct ttyoutq *to, struct tty *tp, size_t size)
|
||||
{
|
||||
unsigned int nblocks;
|
||||
struct ttyoutq_block *tob;
|
||||
|
||||
nblocks = howmany(size, TTYOUTQ_DATASIZE);
|
||||
|
||||
while (nblocks > to->to_nblocks) {
|
||||
/*
|
||||
* List is getting bigger.
|
||||
* Add new blocks to the tail of the list.
|
||||
*
|
||||
* We must unlock the TTY temporarily, because we need
|
||||
* to allocate memory. This won't be a problem, because
|
||||
* in the worst case, another thread ends up here, which
|
||||
* may cause us to allocate too many blocks, but this
|
||||
* will be caught by the loop below.
|
||||
*/
|
||||
tty_unlock(tp);
|
||||
tob = uma_zalloc(ttyoutq_zone, M_WAITOK);
|
||||
tty_lock(tp);
|
||||
|
||||
if (tty_gone(tp))
|
||||
return;
|
||||
|
||||
STAILQ_INSERT_TAIL(&to->to_list, tob, tob_list);
|
||||
to->to_nblocks++;
|
||||
}
|
||||
|
||||
while (nblocks < to->to_nblocks) {
|
||||
/*
|
||||
* List is getting smaller. Remove unused blocks at the
|
||||
* end. This means we cannot guarantee this routine
|
||||
* shrinks buffers properly, when we need to reclaim
|
||||
* more space than there is available.
|
||||
*
|
||||
* XXX TODO: Two solutions here:
|
||||
* - Throw data away
|
||||
* - Temporarily hit the watermark until enough data has
|
||||
* been flushed, so we can remove the blocks.
|
||||
*/
|
||||
|
||||
if (to->to_end == 0) {
|
||||
tob = STAILQ_FIRST(&to->to_list);
|
||||
if (tob == NULL)
|
||||
break;
|
||||
STAILQ_REMOVE_HEAD(&to->to_list, tob_list);
|
||||
} else {
|
||||
tob = STAILQ_NEXT(to->to_lastblock, tob_list);
|
||||
if (tob == NULL)
|
||||
break;
|
||||
STAILQ_REMOVE_NEXT(&to->to_list, to->to_lastblock, tob_list);
|
||||
}
|
||||
uma_zfree(ttyoutq_zone, tob);
|
||||
to->to_nblocks--;
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
ttyoutq_read(struct ttyoutq *to, void *buf, size_t len)
|
||||
{
|
||||
char *cbuf = buf;
|
||||
|
||||
while (len > 0) {
|
||||
struct ttyoutq_block *tob;
|
||||
size_t cbegin, cend, clen;
|
||||
|
||||
/* See if there still is data. */
|
||||
if (to->to_begin == to->to_end)
|
||||
break;
|
||||
tob = STAILQ_FIRST(&to->to_list);
|
||||
if (tob == NULL)
|
||||
break;
|
||||
|
||||
/*
|
||||
* The end address should be the lowest of these three:
|
||||
* - The write pointer
|
||||
* - The blocksize - we can't read beyond the block
|
||||
* - The end address if we could perform the full read
|
||||
*/
|
||||
cbegin = to->to_begin;
|
||||
cend = MIN(MIN(to->to_end, to->to_begin + len),
|
||||
TTYOUTQ_DATASIZE);
|
||||
clen = cend - cbegin;
|
||||
|
||||
if (cend == TTYOUTQ_DATASIZE || cend == to->to_end) {
|
||||
/* Read the block until the end. */
|
||||
STAILQ_REMOVE_HEAD(&to->to_list, tob_list);
|
||||
STAILQ_INSERT_TAIL(&to->to_list, tob, tob_list);
|
||||
to->to_begin = 0;
|
||||
if (to->to_end <= TTYOUTQ_DATASIZE) {
|
||||
to->to_end = 0;
|
||||
} else {
|
||||
to->to_end -= TTYOUTQ_DATASIZE;
|
||||
}
|
||||
} else {
|
||||
/* Read the block partially. */
|
||||
to->to_begin += clen;
|
||||
}
|
||||
|
||||
/* Copy the data out of the buffers. */
|
||||
memcpy(cbuf, tob->tob_data + cbegin, clen);
|
||||
cbuf += clen;
|
||||
len -= clen;
|
||||
}
|
||||
|
||||
return (cbuf - (char *)buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* An optimized version of ttyoutq_read() which can be used in pseudo
|
||||
* TTY drivers to directly copy data from the outq to userspace, instead
|
||||
* of buffering it.
|
||||
*
|
||||
* We can only copy data directly if we need to read the entire block
|
||||
* back to the user, because we temporarily remove the block from the
|
||||
* queue. Otherwise we need to copy it to a temporary buffer first, to
|
||||
* make sure data remains in the correct order.
|
||||
*/
|
||||
int
|
||||
ttyoutq_read_uio(struct ttyoutq *to, struct tty *tp, struct uio *uio)
|
||||
{
|
||||
|
||||
while (uio->uio_resid > 0) {
|
||||
int error;
|
||||
struct ttyoutq_block *tob;
|
||||
size_t cbegin, cend, clen;
|
||||
|
||||
/* See if there still is data. */
|
||||
if (to->to_begin == to->to_end)
|
||||
return (0);
|
||||
tob = STAILQ_FIRST(&to->to_list);
|
||||
if (tob == NULL)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* The end address should be the lowest of these three:
|
||||
* - The write pointer
|
||||
* - The blocksize - we can't read beyond the block
|
||||
* - The end address if we could perform the full read
|
||||
*/
|
||||
cbegin = to->to_begin;
|
||||
cend = MIN(MIN(to->to_end, to->to_begin + uio->uio_resid),
|
||||
TTYOUTQ_DATASIZE);
|
||||
clen = cend - cbegin;
|
||||
|
||||
/*
|
||||
* We can prevent buffering in some cases:
|
||||
* - We need to read the block until the end.
|
||||
* - We don't need to read the block until the end, but
|
||||
* there is no data beyond it, which allows us to move
|
||||
* the write pointer to a new block.
|
||||
*/
|
||||
if (cend == TTYOUTQ_DATASIZE || cend == to->to_end) {
|
||||
atomic_add_long(&ttyoutq_nfast, 1);
|
||||
|
||||
/*
|
||||
* Fast path: zero copy. Remove the first block,
|
||||
* so we can unlock the TTY temporarily.
|
||||
*/
|
||||
STAILQ_REMOVE_HEAD(&to->to_list, tob_list);
|
||||
to->to_nblocks--;
|
||||
to->to_begin = 0;
|
||||
if (to->to_end <= TTYOUTQ_DATASIZE) {
|
||||
to->to_end = 0;
|
||||
} else {
|
||||
to->to_end -= TTYOUTQ_DATASIZE;
|
||||
}
|
||||
|
||||
/* Temporary unlock and copy the data to userspace. */
|
||||
tty_unlock(tp);
|
||||
error = uiomove(tob->tob_data + cbegin, clen, uio);
|
||||
tty_lock(tp);
|
||||
|
||||
if (tty_gone(tp)) {
|
||||
/* We lost the discipline. */
|
||||
uma_zfree(ttyoutq_zone, tob);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* Block can now be readded to the list. */
|
||||
/*
|
||||
* XXX: we could remove the blocks here when the
|
||||
* queue was shrunk, but still in use. See
|
||||
* ttyoutq_setsize().
|
||||
*/
|
||||
STAILQ_INSERT_TAIL(&to->to_list, tob, tob_list);
|
||||
to->to_nblocks++;
|
||||
if (error != 0)
|
||||
return (error);
|
||||
} else {
|
||||
char ob[TTYOUTQ_DATASIZE - 1];
|
||||
atomic_add_long(&ttyoutq_nslow, 1);
|
||||
|
||||
/*
|
||||
* Slow path: store data in a temporary buffer.
|
||||
*/
|
||||
memcpy(ob, tob->tob_data + cbegin, clen);
|
||||
to->to_begin += clen;
|
||||
MPASS(to->to_begin < TTYOUTQ_DATASIZE);
|
||||
|
||||
/* Temporary unlock and copy the data to userspace. */
|
||||
tty_unlock(tp);
|
||||
error = uiomove(ob, clen, uio);
|
||||
tty_lock(tp);
|
||||
|
||||
if (tty_gone(tp)) {
|
||||
/* We lost the discipline. */
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
if (error != 0)
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
size_t
|
||||
ttyoutq_write(struct ttyoutq *to, const void *buf, size_t nbytes)
|
||||
{
|
||||
const char *cbuf = buf;
|
||||
struct ttyoutq_block *tob;
|
||||
unsigned int boff;
|
||||
size_t l;
|
||||
|
||||
while (nbytes > 0) {
|
||||
/* Offset in current block. */
|
||||
tob = to->to_lastblock;
|
||||
boff = to->to_end % TTYOUTQ_DATASIZE;
|
||||
|
||||
if (to->to_end == 0) {
|
||||
/* First time we're being used or drained. */
|
||||
MPASS(to->to_begin == 0);
|
||||
tob = to->to_lastblock = STAILQ_FIRST(&to->to_list);
|
||||
if (tob == NULL) {
|
||||
/* Queue has no blocks. */
|
||||
break;
|
||||
}
|
||||
} else if (boff == 0) {
|
||||
/* We reached the end of this block on last write. */
|
||||
tob = STAILQ_NEXT(tob, tob_list);
|
||||
if (tob == NULL) {
|
||||
/* We've reached the watermark. */
|
||||
break;
|
||||
}
|
||||
to->to_lastblock = tob;
|
||||
}
|
||||
|
||||
/* Don't copy more than was requested. */
|
||||
l = MIN(nbytes, TTYOUTQ_DATASIZE - boff);
|
||||
MPASS(l > 0);
|
||||
memcpy(tob->tob_data + boff, cbuf, l);
|
||||
|
||||
cbuf += l;
|
||||
nbytes -= l;
|
||||
to->to_end += l;
|
||||
}
|
||||
|
||||
return (cbuf - (const char *)buf);
|
||||
}
|
||||
|
||||
int
|
||||
ttyoutq_write_nofrag(struct ttyoutq *to, const void *buf, size_t nbytes)
|
||||
{
|
||||
size_t ret;
|
||||
|
||||
if (ttyoutq_bytesleft(to) < nbytes)
|
||||
return (-1);
|
||||
|
||||
/* We should always be able to write it back. */
|
||||
ret = ttyoutq_write(to, buf, nbytes);
|
||||
MPASS(ret == nbytes);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
ttyoutq_startup(void *dummy)
|
||||
{
|
||||
|
||||
ttyoutq_zone = uma_zcreate("ttyoutq", sizeof(struct ttyoutq_block),
|
||||
NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
|
||||
}
|
||||
|
||||
SYSINIT(ttyoutq, SI_SUB_DRIVERS, SI_ORDER_FIRST, ttyoutq_startup, NULL);
|
1345
sys/kern/tty_pts.c
1345
sys/kern/tty_pts.c
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,9 @@
|
||||
/*-
|
||||
* Copyright (c) 1982, 1986, 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions of this software were developed under sponsorship from Snow
|
||||
* B.V., the Netherlands.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -10,14 +13,11 @@
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
@ -25,793 +25,101 @@
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)tty_pty.c 8.4 (Berkeley) 2/20/95
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* Pseudo-teletype Driver
|
||||
* (Actually two drivers, requiring two entries in 'cdevsw')
|
||||
*/
|
||||
#include "opt_compat.h"
|
||||
#include "opt_tty.h"
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/libkern.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/sx.h>
|
||||
#if defined(COMPAT_43TTY)
|
||||
#include <sys/ioctl_compat.h>
|
||||
#endif
|
||||
#include <sys/priv.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/tty.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/eventhandler.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/signalvar.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/tty.h>
|
||||
|
||||
static MALLOC_DEFINE(M_PTY, "ptys", "pty data structures");
|
||||
|
||||
static void ptsstart(struct tty *tp);
|
||||
static void ptsstop(struct tty *tp, int rw);
|
||||
static void ptcwakeup(struct tty *tp, int flag);
|
||||
static struct cdev *ptyinit(struct cdev *cdev, struct thread *td);
|
||||
|
||||
static d_open_t ptsopen;
|
||||
static d_close_t ptsclose;
|
||||
static d_read_t ptsread;
|
||||
static d_write_t ptswrite;
|
||||
static d_ioctl_t ptsioctl;
|
||||
static d_open_t ptcopen;
|
||||
static d_close_t ptcclose;
|
||||
static d_read_t ptcread;
|
||||
static d_ioctl_t ptcioctl;
|
||||
static d_write_t ptcwrite;
|
||||
static d_poll_t ptcpoll;
|
||||
|
||||
static struct cdevsw pts_cdevsw = {
|
||||
.d_version = D_VERSION,
|
||||
.d_open = ptsopen,
|
||||
.d_close = ptsclose,
|
||||
.d_read = ptsread,
|
||||
.d_write = ptswrite,
|
||||
.d_ioctl = ptsioctl,
|
||||
.d_name = "pts",
|
||||
.d_flags = D_TTY | D_NEEDGIANT,
|
||||
};
|
||||
|
||||
static struct cdevsw ptc_cdevsw = {
|
||||
.d_version = D_VERSION,
|
||||
.d_open = ptcopen,
|
||||
.d_close = ptcclose,
|
||||
.d_read = ptcread,
|
||||
.d_write = ptcwrite,
|
||||
.d_ioctl = ptcioctl,
|
||||
.d_poll = ptcpoll,
|
||||
.d_name = "ptc",
|
||||
.d_flags = D_TTY | D_NEEDGIANT,
|
||||
};
|
||||
|
||||
static struct mtx ptyinit_lock;
|
||||
MTX_SYSINIT(ptyinit_lock, &ptyinit_lock, "ptyinit", MTX_DEF);
|
||||
|
||||
#define BUFSIZ 100 /* Chunk size iomoved to/from user */
|
||||
|
||||
struct ptsc {
|
||||
int pt_flags;
|
||||
struct selinfo pt_selr, pt_selw;
|
||||
u_char pt_send;
|
||||
u_char pt_ucntl;
|
||||
struct tty *pt_tty;
|
||||
struct cdev *devs, *devc;
|
||||
int pt_devs_open, pt_devc_open;
|
||||
struct prison *pt_prison;
|
||||
};
|
||||
|
||||
#define PF_PKT 0x08 /* packet mode */
|
||||
#define PF_STOPPED 0x10 /* user told stopped */
|
||||
#define PF_NOSTOP 0x40
|
||||
#define PF_UCNTL 0x80 /* user control mode */
|
||||
|
||||
#define TSA_PTC_READ(tp) ((void *)&(tp)->t_outq.c_cf)
|
||||
#define TSA_PTC_WRITE(tp) ((void *)&(tp)->t_rawq.c_cl)
|
||||
#define TSA_PTS_READ(tp) ((void *)&(tp)->t_canq)
|
||||
|
||||
static const char names[] = "pqrsPQRSlmnoLMNO";
|
||||
/*
|
||||
* This function creates and initializes a pts/ptc pair
|
||||
*
|
||||
* pts == /dev/tty[pqrsPQRSlmnoLMNO][0123456789abcdefghijklmnopqrstuv]
|
||||
* ptc == /dev/pty[pqrsPQRSlmnoLMNO][0123456789abcdefghijklmnopqrstuv]
|
||||
* This driver implements a BSD-style compatibility naming scheme for
|
||||
* the pts(4) driver. We just call into pts(4) to create the actual PTY.
|
||||
* To make sure we don't use the same PTY multiple times, we abuse
|
||||
* si_drv1 inside the cdev to mark whether the PTY is in use.
|
||||
*/
|
||||
static struct cdev *
|
||||
ptyinit(struct cdev *devc, struct thread *td)
|
||||
|
||||
static int pty_warningcnt = 10;
|
||||
|
||||
static int
|
||||
ptydev_fdopen(struct cdev *dev, int fflags, struct thread *td, struct file *fp)
|
||||
{
|
||||
struct ptsc *pt;
|
||||
int n;
|
||||
int u, error;
|
||||
char name[] = "ttyXX";
|
||||
|
||||
n = minor2unit(minor(devc));
|
||||
|
||||
/* We only allow for up to 32 ptys per char in "names". */
|
||||
if (n >= 32 * (sizeof(names) - 1))
|
||||
return (NULL);
|
||||
|
||||
devc->si_flags &= ~SI_CHEAPCLONE;
|
||||
|
||||
/*
|
||||
* Initially do not create a slave endpoint.
|
||||
*/
|
||||
pt = malloc(sizeof(*pt), M_PTY, M_WAITOK | M_ZERO);
|
||||
pt->devc = devc;
|
||||
|
||||
pt->pt_tty = ttyalloc();
|
||||
pt->pt_tty->t_sc = pt;
|
||||
mtx_lock(&ptyinit_lock);
|
||||
if (devc->si_drv1 == NULL) {
|
||||
devc->si_drv1 = pt;
|
||||
devc->si_tty = pt->pt_tty;
|
||||
mtx_unlock(&ptyinit_lock);
|
||||
} else {
|
||||
mtx_unlock(&ptyinit_lock);
|
||||
ttyrel(pt->pt_tty);
|
||||
free(pt, M_PTY);
|
||||
}
|
||||
return (devc);
|
||||
}
|
||||
|
||||
static void
|
||||
pty_create_slave(struct ucred *cred, struct ptsc *pt, int m)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = minor2unit(m);
|
||||
KASSERT(n >= 0 && n / 32 < sizeof(names),
|
||||
("pty_create_slave: n %d ptsc %p", n, pt));
|
||||
pt->devs = make_dev_cred(&pts_cdevsw, m, cred, UID_ROOT, GID_WHEEL,
|
||||
0666, "tty%c%r", names[n / 32], n % 32);
|
||||
pt->devs->si_drv1 = pt;
|
||||
pt->devs->si_tty = pt->pt_tty;
|
||||
pt->pt_tty->t_dev = pt->devs;
|
||||
}
|
||||
|
||||
static void
|
||||
pty_destroy_slave(struct ptsc *pt)
|
||||
{
|
||||
|
||||
if (pt->pt_tty->t_refcnt > 1)
|
||||
return;
|
||||
pt->pt_tty->t_dev = NULL;
|
||||
ttyrel(pt->pt_tty);
|
||||
pt->pt_tty = NULL;
|
||||
destroy_dev(pt->devs);
|
||||
pt->devs = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
pty_maybe_destroy_slave(struct ptsc *pt)
|
||||
{
|
||||
|
||||
/*
|
||||
* vfs bugs and complications near revoke() make
|
||||
* it currently impossible to destroy struct cdev
|
||||
*/
|
||||
if (0 && pt->pt_devc_open == 0 && pt->pt_devs_open == 0)
|
||||
pty_destroy_slave(pt);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
static int
|
||||
ptsopen(struct cdev *dev, int flag, int devtype, struct thread *td)
|
||||
{
|
||||
struct tty *tp;
|
||||
int error;
|
||||
struct ptsc *pt;
|
||||
|
||||
if (!dev->si_drv1)
|
||||
return(ENXIO);
|
||||
pt = dev->si_drv1;
|
||||
tp = dev->si_tty;
|
||||
|
||||
if ((tp->t_state & TS_ISOPEN) == 0) {
|
||||
ttyinitmode(tp, 1, 0);
|
||||
} else if (tp->t_state & TS_XCLUDE && priv_check(td,
|
||||
PRIV_TTY_EXCLUSIVE))
|
||||
if (!atomic_cmpset_ptr((uintptr_t *)&dev->si_drv1, 0, 1))
|
||||
return (EBUSY);
|
||||
else if (pt->pt_prison != td->td_ucred->cr_prison &&
|
||||
priv_check(td, PRIV_TTY_PRISON))
|
||||
return (EBUSY);
|
||||
if (tp->t_oproc) /* Ctrlr still around. */
|
||||
(void)ttyld_modem(tp, 1);
|
||||
while ((tp->t_state & TS_CARR_ON) == 0) {
|
||||
if (flag&FNONBLOCK)
|
||||
break;
|
||||
error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH,
|
||||
"ptsopn", 0);
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
error = ttyld_open(tp, dev);
|
||||
if (error == 0) {
|
||||
ptcwakeup(tp, FREAD|FWRITE);
|
||||
pt->pt_devs_open = 1;
|
||||
} else
|
||||
pty_maybe_destroy_slave(pt);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
ptsclose(struct cdev *dev, int flag, int mode, struct thread *td)
|
||||
{
|
||||
struct ptsc *pti;
|
||||
struct tty *tp;
|
||||
int err;
|
||||
/* Generate device name and create PTY. */
|
||||
u = dev2unit(dev);
|
||||
name[3] = u >> 8;
|
||||
name[4] = u;
|
||||
|
||||
tp = dev->si_tty;
|
||||
pti = dev->si_drv1;
|
||||
|
||||
KASSERT(dev == pti->devs, ("ptsclose: dev != pti->devs"));
|
||||
|
||||
err = ttyld_close(tp, flag);
|
||||
(void) tty_close(tp);
|
||||
|
||||
pti->pt_devs_open = 0;
|
||||
pty_maybe_destroy_slave(pti);
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
ptsread(struct cdev *dev, struct uio *uio, int flag)
|
||||
{
|
||||
struct tty *tp = dev->si_tty;
|
||||
int error = 0;
|
||||
|
||||
if (tp->t_oproc)
|
||||
error = ttyld_read(tp, uio, flag);
|
||||
ptcwakeup(tp, FWRITE);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write to pseudo-tty.
|
||||
* Wakeups of controlling tty will happen
|
||||
* indirectly, when tty driver calls ptsstart.
|
||||
*/
|
||||
static int
|
||||
ptswrite(struct cdev *dev, struct uio *uio, int flag)
|
||||
{
|
||||
struct tty *tp;
|
||||
|
||||
tp = dev->si_tty;
|
||||
if (tp->t_oproc == 0)
|
||||
return (EIO);
|
||||
return (ttyld_write(tp, uio, flag));
|
||||
}
|
||||
|
||||
/*
|
||||
* Start output on pseudo-tty.
|
||||
* Wake up process selecting or sleeping for input from controlling tty.
|
||||
*/
|
||||
static void
|
||||
ptsstart(struct tty *tp)
|
||||
{
|
||||
struct ptsc *pt = tp->t_sc;
|
||||
|
||||
if (tp->t_state & TS_TTSTOP)
|
||||
return;
|
||||
if (pt->pt_flags & PF_STOPPED) {
|
||||
pt->pt_flags &= ~PF_STOPPED;
|
||||
pt->pt_send = TIOCPKT_START;
|
||||
}
|
||||
ptcwakeup(tp, FREAD);
|
||||
}
|
||||
|
||||
static void
|
||||
ptcwakeup(struct tty *tp, int flag)
|
||||
{
|
||||
struct ptsc *pt = tp->t_sc;
|
||||
|
||||
if (flag & FREAD) {
|
||||
selwakeuppri(&pt->pt_selr, TTIPRI);
|
||||
wakeup(TSA_PTC_READ(tp));
|
||||
}
|
||||
if (flag & FWRITE) {
|
||||
selwakeuppri(&pt->pt_selw, TTOPRI);
|
||||
wakeup(TSA_PTC_WRITE(tp));
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
ptcopen(struct cdev *dev, int flag, int devtype, struct thread *td)
|
||||
{
|
||||
struct tty *tp;
|
||||
struct ptsc *pt;
|
||||
|
||||
if (!dev->si_drv1)
|
||||
ptyinit(dev, td);
|
||||
if (!dev->si_drv1)
|
||||
return(ENXIO);
|
||||
|
||||
pt = dev->si_drv1;
|
||||
/*
|
||||
* In case we have destroyed the struct tty at the last connect time,
|
||||
* we need to recreate it.
|
||||
*/
|
||||
if (pt->pt_tty == NULL) {
|
||||
tp = ttyalloc();
|
||||
mtx_lock(&ptyinit_lock);
|
||||
if (pt->pt_tty == NULL) {
|
||||
pt->pt_tty = tp;
|
||||
pt->pt_tty->t_sc = pt;
|
||||
dev->si_tty = pt->pt_tty;
|
||||
mtx_unlock(&ptyinit_lock);
|
||||
} else {
|
||||
mtx_unlock(&ptyinit_lock);
|
||||
ttyrel(tp);
|
||||
}
|
||||
}
|
||||
tp = dev->si_tty;
|
||||
|
||||
if (tp->t_oproc)
|
||||
return (EIO);
|
||||
tp->t_timeout = -1;
|
||||
tp->t_oproc = ptsstart;
|
||||
tp->t_stop = ptsstop;
|
||||
(void)ttyld_modem(tp, 1);
|
||||
tp->t_lflag &= ~EXTPROC;
|
||||
pt->pt_prison = td->td_ucred->cr_prison;
|
||||
pt->pt_flags = 0;
|
||||
pt->pt_send = 0;
|
||||
pt->pt_ucntl = 0;
|
||||
|
||||
if (!pt->devs)
|
||||
pty_create_slave(td->td_ucred, pt, minor(dev));
|
||||
pt->pt_devc_open = 1;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ptcclose(struct cdev *dev, int flags, int fmt, struct thread *td)
|
||||
{
|
||||
struct ptsc *pti = dev->si_drv1;
|
||||
struct tty *tp;
|
||||
|
||||
tp = dev->si_tty;
|
||||
(void)ttyld_modem(tp, 0);
|
||||
|
||||
/*
|
||||
* XXX MDMBUF makes no sense for ptys but would inhibit the above
|
||||
* l_modem(). CLOCAL makes sense but isn't supported. Special
|
||||
* l_modem()s that ignore carrier drop make no sense for ptys but
|
||||
* may be in use because other parts of the line discipline make
|
||||
* sense for ptys. Recover by doing everything that a normal
|
||||
* ttymodem() would have done except for sending a SIGHUP.
|
||||
*/
|
||||
if (tp->t_state & TS_ISOPEN) {
|
||||
tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED);
|
||||
tp->t_state |= TS_ZOMBIE;
|
||||
ttyflush(tp, FREAD | FWRITE);
|
||||
}
|
||||
|
||||
tp->t_oproc = 0; /* mark closed */
|
||||
pti->pt_devc_open = 0;
|
||||
pty_maybe_destroy_slave(pti);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ptcread(struct cdev *dev, struct uio *uio, int flag)
|
||||
{
|
||||
struct tty *tp = dev->si_tty;
|
||||
struct ptsc *pt = dev->si_drv1;
|
||||
char buf[BUFSIZ];
|
||||
int error = 0, cc;
|
||||
|
||||
/*
|
||||
* We want to block until the slave
|
||||
* is open, and there's something to read;
|
||||
* but if we lost the slave or we're NBIO,
|
||||
* then return the appropriate error instead.
|
||||
*/
|
||||
for (;;) {
|
||||
if (tp->t_state&TS_ISOPEN) {
|
||||
if (pt->pt_flags&PF_PKT && pt->pt_send) {
|
||||
error = ureadc((int)pt->pt_send, uio);
|
||||
if (error)
|
||||
return (error);
|
||||
if (pt->pt_send & TIOCPKT_IOCTL) {
|
||||
cc = min(uio->uio_resid,
|
||||
sizeof(tp->t_termios));
|
||||
uiomove(&tp->t_termios, cc, uio);
|
||||
}
|
||||
pt->pt_send = 0;
|
||||
return (0);
|
||||
}
|
||||
if (pt->pt_flags&PF_UCNTL && pt->pt_ucntl) {
|
||||
error = ureadc((int)pt->pt_ucntl, uio);
|
||||
if (error)
|
||||
return (error);
|
||||
pt->pt_ucntl = 0;
|
||||
return (0);
|
||||
}
|
||||
if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
|
||||
break;
|
||||
}
|
||||
if ((tp->t_state & TS_CONNECTED) == 0)
|
||||
return (0); /* EOF */
|
||||
if (flag & O_NONBLOCK)
|
||||
return (EWOULDBLOCK);
|
||||
error = tsleep(TSA_PTC_READ(tp), TTIPRI | PCATCH, "ptcin", 0);
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
if (pt->pt_flags & (PF_PKT|PF_UCNTL))
|
||||
error = ureadc(0, uio);
|
||||
while (uio->uio_resid > 0 && error == 0) {
|
||||
cc = q_to_b(&tp->t_outq, buf, min(uio->uio_resid, BUFSIZ));
|
||||
if (cc <= 0)
|
||||
break;
|
||||
error = uiomove(buf, cc, uio);
|
||||
}
|
||||
ttwwakeup(tp);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static void
|
||||
ptsstop(struct tty *tp, int flush)
|
||||
{
|
||||
struct ptsc *pt = tp->t_sc;
|
||||
int flag;
|
||||
|
||||
/* note: FLUSHREAD and FLUSHWRITE already ok */
|
||||
if (flush == 0) {
|
||||
flush = TIOCPKT_STOP;
|
||||
pt->pt_flags |= PF_STOPPED;
|
||||
} else
|
||||
pt->pt_flags &= ~PF_STOPPED;
|
||||
pt->pt_send |= flush;
|
||||
/* change of perspective */
|
||||
flag = 0;
|
||||
if (flush & FREAD)
|
||||
flag |= FWRITE;
|
||||
if (flush & FWRITE)
|
||||
flag |= FREAD;
|
||||
ptcwakeup(tp, flag);
|
||||
}
|
||||
|
||||
static int
|
||||
ptcpoll(struct cdev *dev, int events, struct thread *td)
|
||||
{
|
||||
struct tty *tp = dev->si_tty;
|
||||
struct ptsc *pt = dev->si_drv1;
|
||||
int revents = 0;
|
||||
int s;
|
||||
|
||||
if ((tp->t_state & TS_CONNECTED) == 0)
|
||||
return (events &
|
||||
(POLLHUP | POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM));
|
||||
|
||||
/*
|
||||
* Need to block timeouts (ttrstart).
|
||||
*/
|
||||
s = spltty();
|
||||
|
||||
if (events & (POLLIN | POLLRDNORM))
|
||||
if ((tp->t_state & TS_ISOPEN) &&
|
||||
((tp->t_outq.c_cc && (tp->t_state & TS_TTSTOP) == 0) ||
|
||||
((pt->pt_flags & PF_PKT) && pt->pt_send) ||
|
||||
((pt->pt_flags & PF_UCNTL) && pt->pt_ucntl)))
|
||||
revents |= events & (POLLIN | POLLRDNORM);
|
||||
|
||||
if (events & (POLLOUT | POLLWRNORM))
|
||||
if (tp->t_state & TS_ISOPEN &&
|
||||
(((tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG - 2) ||
|
||||
(tp->t_canq.c_cc == 0 && (tp->t_lflag & ICANON)))))
|
||||
revents |= events & (POLLOUT | POLLWRNORM);
|
||||
|
||||
if (events & POLLHUP)
|
||||
if ((tp->t_state & TS_CARR_ON) == 0)
|
||||
revents |= POLLHUP;
|
||||
|
||||
if (revents == 0) {
|
||||
if (events & (POLLIN | POLLRDNORM))
|
||||
selrecord(td, &pt->pt_selr);
|
||||
|
||||
if (events & (POLLOUT | POLLWRNORM))
|
||||
selrecord(td, &pt->pt_selw);
|
||||
}
|
||||
splx(s);
|
||||
|
||||
return (revents);
|
||||
}
|
||||
|
||||
static int
|
||||
ptcwrite(struct cdev *dev, struct uio *uio, int flag)
|
||||
{
|
||||
struct tty *tp = dev->si_tty;
|
||||
u_char *cp = 0;
|
||||
int cc = 0;
|
||||
u_char locbuf[BUFSIZ];
|
||||
int cnt = 0;
|
||||
int error = 0;
|
||||
|
||||
again:
|
||||
if ((tp->t_state&TS_ISOPEN) == 0)
|
||||
goto block;
|
||||
while (uio->uio_resid > 0 || cc > 0) {
|
||||
if (cc == 0) {
|
||||
cc = min(uio->uio_resid, BUFSIZ);
|
||||
cp = locbuf;
|
||||
error = uiomove(cp, cc, uio);
|
||||
if (error)
|
||||
return (error);
|
||||
/* check again for safety */
|
||||
if ((tp->t_state & TS_ISOPEN) == 0) {
|
||||
/* adjust for data copied in but not written */
|
||||
uio->uio_resid += cc;
|
||||
return (EIO);
|
||||
}
|
||||
}
|
||||
while (cc > 0) {
|
||||
if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
|
||||
(tp->t_canq.c_cc > 0 || !(tp->t_lflag&ICANON))) {
|
||||
wakeup(TSA_HUP_OR_INPUT(tp));
|
||||
goto block;
|
||||
}
|
||||
ttyld_rint(tp, *cp++);
|
||||
cnt++;
|
||||
cc--;
|
||||
}
|
||||
cc = 0;
|
||||
}
|
||||
return (0);
|
||||
block:
|
||||
/*
|
||||
* Come here to wait for slave to open, for space
|
||||
* in outq, or space in rawq, or an empty canq.
|
||||
*/
|
||||
if ((tp->t_state & TS_CONNECTED) == 0) {
|
||||
/* adjust for data copied in but not written */
|
||||
uio->uio_resid += cc;
|
||||
return (EIO);
|
||||
}
|
||||
if (flag & O_NONBLOCK) {
|
||||
/* adjust for data copied in but not written */
|
||||
uio->uio_resid += cc;
|
||||
if (cnt == 0)
|
||||
return (EWOULDBLOCK);
|
||||
return (0);
|
||||
}
|
||||
error = tsleep(TSA_PTC_WRITE(tp), TTOPRI | PCATCH, "ptcout", 0);
|
||||
if (error) {
|
||||
/* adjust for data copied in but not written */
|
||||
uio->uio_resid += cc;
|
||||
error = pts_alloc_external(fflags & (FREAD|FWRITE), td, fp, dev, name);
|
||||
if (error != 0) {
|
||||
destroy_dev_sched(dev);
|
||||
return (error);
|
||||
}
|
||||
goto again;
|
||||
|
||||
/* Raise a warning when a legacy PTY has been allocated. */
|
||||
if (pty_warningcnt > 0) {
|
||||
pty_warningcnt--;
|
||||
printf("pid %d (%s) is using legacy pty devices%s\n",
|
||||
td->td_proc->p_pid, td->td_name,
|
||||
pty_warningcnt ? "" : " - not logging anymore");
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
static int
|
||||
ptcioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
{
|
||||
struct tty *tp = dev->si_tty;
|
||||
struct ptsc *pt = dev->si_drv1;
|
||||
#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
|
||||
defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
|
||||
int ival;
|
||||
#endif
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
case TIOCGPGRP:
|
||||
/*
|
||||
* We avoid calling ttioctl on the controller since,
|
||||
* in that case, tp must be the controlling terminal.
|
||||
*/
|
||||
*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
|
||||
return (0);
|
||||
|
||||
case TIOCPKT:
|
||||
if (*(int *)data) {
|
||||
if (pt->pt_flags & PF_UCNTL)
|
||||
return (EINVAL);
|
||||
pt->pt_flags |= PF_PKT;
|
||||
} else
|
||||
pt->pt_flags &= ~PF_PKT;
|
||||
return (0);
|
||||
|
||||
case TIOCUCNTL:
|
||||
if (*(int *)data) {
|
||||
if (pt->pt_flags & PF_PKT)
|
||||
return (EINVAL);
|
||||
pt->pt_flags |= PF_UCNTL;
|
||||
} else
|
||||
pt->pt_flags &= ~PF_UCNTL;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* The rest of the ioctls shouldn't be called until
|
||||
* the slave is open.
|
||||
*/
|
||||
if ((tp->t_state & TS_ISOPEN) == 0)
|
||||
return (EAGAIN);
|
||||
|
||||
switch (cmd) {
|
||||
#ifdef COMPAT_43TTY
|
||||
case TIOCSETP:
|
||||
case TIOCSETN:
|
||||
#endif
|
||||
case TIOCSETD:
|
||||
case TIOCSETA:
|
||||
case TIOCSETAW:
|
||||
case TIOCSETAF:
|
||||
/*
|
||||
* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
|
||||
* ttywflush(tp) will hang if there are characters in
|
||||
* the outq.
|
||||
*/
|
||||
ndflush(&tp->t_outq, tp->t_outq.c_cc);
|
||||
break;
|
||||
|
||||
#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
|
||||
defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
|
||||
case _IO('t', 95):
|
||||
ival = IOCPARM_IVAL(data);
|
||||
data = (caddr_t)&ival;
|
||||
/* FALLTHROUGH */
|
||||
#endif
|
||||
case TIOCSIG:
|
||||
if (*(unsigned int *)data >= NSIG ||
|
||||
*(unsigned int *)data == 0)
|
||||
return(EINVAL);
|
||||
if ((tp->t_lflag&NOFLSH) == 0)
|
||||
ttyflush(tp, FREAD|FWRITE);
|
||||
if (tp->t_pgrp != NULL) {
|
||||
PGRP_LOCK(tp->t_pgrp);
|
||||
pgsignal(tp->t_pgrp, *(unsigned int *)data, 1);
|
||||
PGRP_UNLOCK(tp->t_pgrp);
|
||||
}
|
||||
if ((*(unsigned int *)data == SIGINFO) &&
|
||||
((tp->t_lflag&NOKERNINFO) == 0))
|
||||
ttyinfo(tp);
|
||||
return(0);
|
||||
}
|
||||
|
||||
return (ptsioctl(dev, cmd, data, flag, td));
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
static int
|
||||
ptsioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
{
|
||||
struct tty *tp = dev->si_tty;
|
||||
struct ptsc *pt = dev->si_drv1;
|
||||
u_char *cc = tp->t_cc;
|
||||
int stop, error;
|
||||
|
||||
if (cmd == TIOCEXT) {
|
||||
/*
|
||||
* When the EXTPROC bit is being toggled, we need
|
||||
* to send an TIOCPKT_IOCTL if the packet driver
|
||||
* is turned on.
|
||||
*/
|
||||
if (*(int *)data) {
|
||||
if (pt->pt_flags & PF_PKT) {
|
||||
pt->pt_send |= TIOCPKT_IOCTL;
|
||||
ptcwakeup(tp, FREAD);
|
||||
}
|
||||
tp->t_lflag |= EXTPROC;
|
||||
} else {
|
||||
if ((tp->t_lflag & EXTPROC) &&
|
||||
(pt->pt_flags & PF_PKT)) {
|
||||
pt->pt_send |= TIOCPKT_IOCTL;
|
||||
ptcwakeup(tp, FREAD);
|
||||
}
|
||||
tp->t_lflag &= ~EXTPROC;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
error = ttyioctl(dev, cmd, data, flag, td);
|
||||
if (error == ENOTTY) {
|
||||
if (pt->pt_flags & PF_UCNTL &&
|
||||
(cmd & ~0xff) == UIOCCMD(0)) {
|
||||
if (cmd & 0xff) {
|
||||
pt->pt_ucntl = (u_char)cmd;
|
||||
ptcwakeup(tp, FREAD);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
error = ENOTTY;
|
||||
}
|
||||
/*
|
||||
* If external processing and packet mode send ioctl packet.
|
||||
*/
|
||||
if ((tp->t_lflag&EXTPROC) && (pt->pt_flags & PF_PKT)) {
|
||||
switch(cmd) {
|
||||
case TIOCSETA:
|
||||
case TIOCSETAW:
|
||||
case TIOCSETAF:
|
||||
#ifdef COMPAT_43TTY
|
||||
case TIOCSETP:
|
||||
case TIOCSETN:
|
||||
case TIOCSETC:
|
||||
case TIOCSLTC:
|
||||
case TIOCLBIS:
|
||||
case TIOCLBIC:
|
||||
case TIOCLSET:
|
||||
#endif
|
||||
pt->pt_send |= TIOCPKT_IOCTL;
|
||||
ptcwakeup(tp, FREAD);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
|
||||
&& CCEQ(cc[VSTART], CTRL('q'));
|
||||
if (pt->pt_flags & PF_NOSTOP) {
|
||||
if (stop) {
|
||||
pt->pt_send &= ~TIOCPKT_NOSTOP;
|
||||
pt->pt_send |= TIOCPKT_DOSTOP;
|
||||
pt->pt_flags &= ~PF_NOSTOP;
|
||||
ptcwakeup(tp, FREAD);
|
||||
}
|
||||
} else {
|
||||
if (!stop) {
|
||||
pt->pt_send &= ~TIOCPKT_DOSTOP;
|
||||
pt->pt_send |= TIOCPKT_NOSTOP;
|
||||
pt->pt_flags |= PF_NOSTOP;
|
||||
ptcwakeup(tp, FREAD);
|
||||
}
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
static struct cdevsw ptydev_cdevsw = {
|
||||
.d_version = D_VERSION,
|
||||
.d_fdopen = ptydev_fdopen,
|
||||
.d_name = "ptydev",
|
||||
};
|
||||
|
||||
static void
|
||||
pty_clone(void *arg, struct ucred *cr, char *name, int namelen,
|
||||
struct cdev **dev)
|
||||
{
|
||||
char *cp;
|
||||
int u;
|
||||
|
||||
/* Cloning is already satisfied. */
|
||||
if (*dev != NULL)
|
||||
return;
|
||||
if (bcmp(name, "pty", 3) != 0)
|
||||
|
||||
/* Only catch /dev/ptyXX. */
|
||||
if (namelen != 5 || bcmp(name, "pty", 3) != 0)
|
||||
return;
|
||||
if (name[5] != '\0' || name[3] == '\0')
|
||||
|
||||
/* Only catch /dev/pty[l-sL-S]X. */
|
||||
if (!(name[3] >= 'l' && name[3] <= 's') &&
|
||||
!(name[3] >= 'L' && name[3] <= 'S'))
|
||||
return;
|
||||
cp = index(names, name[3]);
|
||||
if (cp == NULL)
|
||||
|
||||
/* Only catch /dev/pty[l-sL-S][0-9a-v]. */
|
||||
if (!(name[4] >= '0' && name[4] <= '9') &&
|
||||
!(name[4] >= 'a' && name[4] <= 'v'))
|
||||
return;
|
||||
u = (cp - names) * 32;
|
||||
if (name[4] >= '0' && name[4] <= '9')
|
||||
u += name[4] - '0';
|
||||
else if (name[4] >= 'a' && name[4] <= 'v')
|
||||
u += name[4] - 'a' + 10;
|
||||
else
|
||||
return;
|
||||
*dev = make_dev_credf(MAKEDEV_REF, &ptc_cdevsw, unit2minor(u), cr,
|
||||
UID_ROOT, GID_WHEEL, 0666, "pty%c%r", names[u / 32], u % 32);
|
||||
(*dev)->si_flags |= SI_CHEAPCLONE;
|
||||
return;
|
||||
|
||||
/* Create the controller device node. */
|
||||
u = (unsigned int)name[3] << 8 | name[4];
|
||||
*dev = make_dev_credf(MAKEDEV_REF, &ptydev_cdevsw, u,
|
||||
NULL, UID_ROOT, GID_WHEEL, 0666, name);
|
||||
}
|
||||
|
||||
static void
|
||||
ptc_drvinit(void *unused)
|
||||
pty_init(void *unused)
|
||||
{
|
||||
|
||||
EVENTHANDLER_REGISTER(dev_clone, pty_clone, 0, 1000);
|
||||
}
|
||||
|
||||
SYSINIT(ptcdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE,ptc_drvinit,NULL);
|
||||
SYSINIT(pty, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, pty_init, NULL);
|
||||
|
1131
sys/kern/tty_ttydisc.c
Normal file
1131
sys/kern/tty_ttydisc.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -4,14 +4,5 @@
|
||||
|
||||
KMOD= nmdm
|
||||
SRCS= nmdm.c
|
||||
SRCS+= opt_compat.h opt_tty.h vnode_if.h
|
||||
|
||||
.if !defined(KERNBUILDDIR)
|
||||
opt_compat.h:
|
||||
echo "#define COMPAT_43 1" >opt_compat.h
|
||||
|
||||
opt_tty.h:
|
||||
echo "#define TTYHOG 8192" >opt_tty.h
|
||||
.endif
|
||||
|
||||
.include <bsd.kmod.mk>
|
||||
|
@ -3,11 +3,6 @@
|
||||
.PATH: ${.CURDIR}/../../dev/rc
|
||||
|
||||
KMOD= rc
|
||||
SRCS= rc.c device_if.h bus_if.h isa_if.h opt_tty.h
|
||||
|
||||
.if !defined(KERNBUILDDIR)
|
||||
opt_tty.h:
|
||||
echo "#define TTYHOG 8192" >opt_tty.h
|
||||
.endif
|
||||
SRCS= rc.c device_if.h bus_if.h isa_if.h
|
||||
|
||||
.include <bsd.kmod.mk>
|
||||
|
@ -1110,7 +1110,7 @@ scterm_puts(scr_stat *scp, u_char *buf, int len)
|
||||
|
||||
static int
|
||||
scterm_ioctl(scr_stat *scp, struct tty *tp, u_long cmd, caddr_t data,
|
||||
int flag, struct thread *td)
|
||||
struct thread *td)
|
||||
{
|
||||
term_stat *tcp = scp->ts;
|
||||
vid_info_t *vi;
|
||||
|
@ -154,7 +154,7 @@ device cardbus # CardBus (32-bit) bus
|
||||
# Serial (COM) ports
|
||||
options COM_MULTIPORT
|
||||
#options COM_ESP # ESP98
|
||||
device sio # 8250, 16[45]50, 8251 based serial ports
|
||||
#device sio # 8250, 16[45]50, 8251 based serial ports
|
||||
|
||||
device mse
|
||||
#device joy
|
||||
@ -231,7 +231,7 @@ device loop # Network loopback
|
||||
device random # Entropy device
|
||||
device ether # Ethernet support
|
||||
device tun # Packet tunnel.
|
||||
device pty # Pseudo-ttys (telnet etc)
|
||||
device pty # BSD-style compatibility pseudo ttys
|
||||
device md # Memory "disks"
|
||||
device gif # IPv6 and IPv4 tunneling
|
||||
device faith # IPv6-to-IPv4 relaying (translation)
|
||||
|
@ -203,7 +203,7 @@ options BPF_JITTER
|
||||
# sio: serial ports (see sio(4)), including support for various
|
||||
# PC Card devices, such as Modem and NICs
|
||||
#
|
||||
device sio
|
||||
#device sio
|
||||
hint.sio.0.at="isa"
|
||||
hint.sio.0.port="0x3F8"
|
||||
hint.sio.0.flags="0x10"
|
||||
|
@ -117,7 +117,7 @@ device loop # Network loopback
|
||||
device random # Entropy device
|
||||
device ether # Ethernet support
|
||||
device tun # Packet tunnel.
|
||||
device pty # Pseudo-ttys (telnet etc)
|
||||
device pty # BSD-style compatibility pseudo ttys
|
||||
device md # Memory "disks"
|
||||
device ofwd # Open Firmware disks
|
||||
device gif # IPv6 and IPv4 tunneling
|
||||
|
@ -206,7 +206,7 @@ device loop # Network loopback
|
||||
device random # Entropy device
|
||||
device ether # Ethernet support
|
||||
device tun # Packet tunnel.
|
||||
device pty # Pseudo-ttys (telnet etc)
|
||||
device pty # BSD-style compatibility pseudo ttys
|
||||
device md # Memory "disks"
|
||||
device gif # IPv6 and IPv4 tunneling
|
||||
device faith # IPv6-to-IPv4 relaying (translation)
|
||||
|
@ -170,7 +170,7 @@ device loop # Network loopback
|
||||
device random # Entropy device
|
||||
device ether # Ethernet support
|
||||
device tun # Packet tunnel.
|
||||
device pty # Pseudo-ttys (telnet etc)
|
||||
device pty # BSD-style compatibility pseudo ttys
|
||||
device md # Memory "disks"
|
||||
device gif # IPv6 and IPv4 tunneling
|
||||
device faith # IPv6-to-IPv4 relaying (translation)
|
||||
|
@ -53,16 +53,14 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#define HVCN_POLL_FREQ 10
|
||||
|
||||
static tsw_open_t hvcn_open;
|
||||
static tsw_outwakeup_t hvcn_outwakeup;
|
||||
static tsw_close_t hvcn_close;
|
||||
|
||||
static d_open_t hvcn_open;
|
||||
static d_close_t hvcn_close;
|
||||
|
||||
static struct cdevsw hvcn_cdevsw = {
|
||||
.d_version = D_VERSION,
|
||||
.d_open = hvcn_open,
|
||||
.d_close = hvcn_close,
|
||||
.d_name = "hvcn",
|
||||
.d_flags = D_TTY | D_NEEDGIANT,
|
||||
static struct ttydevsw hvcn_class = {
|
||||
.tsw_open = hvcn_open,
|
||||
.tsw_outwakeup = hvcn_outwakeup,
|
||||
.tsw_close = hvcn_close,
|
||||
};
|
||||
|
||||
#define PCBURST 16
|
||||
@ -81,9 +79,6 @@ static struct callout_handle hvcn_timeouthandle
|
||||
static int alt_break_state;
|
||||
#endif
|
||||
|
||||
static void hvcn_tty_start(struct tty *);
|
||||
static int hvcn_tty_param(struct tty *, struct termios *);
|
||||
static void hvcn_tty_stop(struct tty *, int);
|
||||
static void hvcn_timeout(void *);
|
||||
|
||||
static cn_probe_t hvcn_cnprobe;
|
||||
@ -113,68 +108,28 @@ hv_cnputs(char *p)
|
||||
}
|
||||
|
||||
static int
|
||||
hvcn_open(struct cdev *dev, int flag, int mode, struct thread *td)
|
||||
hvcn_open(struct tty *tp)
|
||||
{
|
||||
struct tty *tp;
|
||||
int error, setuptimeout;
|
||||
|
||||
setuptimeout = 0;
|
||||
/*
|
||||
* Set up timeout to trigger fake interrupts to transmit
|
||||
* trailing data.
|
||||
*/
|
||||
polltime = hz / HVCN_POLL_FREQ;
|
||||
if (polltime < 1)
|
||||
polltime = 1;
|
||||
hvcn_timeouthandle = timeout(hvcn_timeout, tp, polltime);
|
||||
|
||||
if (dev->si_tty == NULL) {
|
||||
hvcn_tp = ttyalloc();
|
||||
dev->si_tty = hvcn_tp;
|
||||
hvcn_tp->t_dev = dev;
|
||||
}
|
||||
tp = dev->si_tty;
|
||||
|
||||
tp->t_oproc = hvcn_tty_start;
|
||||
tp->t_param = hvcn_tty_param;
|
||||
tp->t_stop = hvcn_tty_stop;
|
||||
|
||||
if ((tp->t_state & TS_ISOPEN) == 0) {
|
||||
tp->t_state |= TS_CARR_ON;
|
||||
ttyconsolemode(tp, 0);
|
||||
|
||||
setuptimeout = 1;
|
||||
} else if ((tp->t_state & TS_XCLUDE) && priv_check(td,
|
||||
PRIV_TTY_EXCLUSIVE)) {
|
||||
return (EBUSY);
|
||||
}
|
||||
|
||||
error = ttyld_open(tp, dev);
|
||||
#if defined(SIMULATOR) || 1
|
||||
if (error == 0 && setuptimeout) {
|
||||
int polltime;
|
||||
|
||||
polltime = hz / HVCN_POLL_FREQ;
|
||||
if (polltime < 1) {
|
||||
polltime = 1;
|
||||
}
|
||||
|
||||
hvcn_timeouthandle = timeout(hvcn_timeout, tp, polltime);
|
||||
}
|
||||
#endif
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
hvcn_close(struct cdev *dev, int flag, int mode, struct thread *td)
|
||||
{
|
||||
int unit;
|
||||
struct tty *tp;
|
||||
|
||||
unit = minor(dev);
|
||||
tp = dev->si_tty;
|
||||
|
||||
if (unit != 0)
|
||||
return (ENXIO);
|
||||
|
||||
untimeout(hvcn_timeout, tp, hvcn_timeouthandle);
|
||||
ttyld_close(tp, flag);
|
||||
tty_close(tp);
|
||||
buflen = 0;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
hvcn_close(struct tty *tp)
|
||||
{
|
||||
untimeout(hvcn_timeout, tp, hvcn_timeouthandle);
|
||||
}
|
||||
|
||||
static void
|
||||
hvcn_cnprobe(struct consdev *cp)
|
||||
@ -210,7 +165,8 @@ hvcn_cnprobe(struct consdev *cp)
|
||||
static void
|
||||
hvcn_cninit(struct consdev *cp)
|
||||
{
|
||||
sprintf(cp->cn_name, "hvcn");
|
||||
|
||||
strcpy(cp->cn_name, "hvcn");
|
||||
}
|
||||
|
||||
static int
|
||||
@ -295,64 +251,43 @@ hvcn_cnputc(struct consdev *cp, int c)
|
||||
} while (error == H_EWOULDBLOCK);
|
||||
}
|
||||
|
||||
static int
|
||||
hvcn_tty_param(struct tty *tp, struct termios *t)
|
||||
{
|
||||
tp->t_ispeed = t->c_ispeed;
|
||||
tp->t_ospeed = t->c_ospeed;
|
||||
tp->t_cflag = t->c_cflag;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
hvcn_tty_start(struct tty *tp)
|
||||
hvcn_outwakeup(struct tty *tp)
|
||||
{
|
||||
|
||||
if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
|
||||
tp->t_state |= TS_BUSY;
|
||||
for (;;) {
|
||||
/* Refill the input buffer. */
|
||||
if (buflen == 0) {
|
||||
buflen = ttydisc_getc(tp, buf, PCBURST);
|
||||
bufindex = 0;
|
||||
}
|
||||
|
||||
do {
|
||||
if (buflen == 0) {
|
||||
buflen = q_to_b(&tp->t_outq, buf, PCBURST);
|
||||
bufindex = 0;
|
||||
}
|
||||
while (buflen) {
|
||||
if (hv_cons_putchar(buf[bufindex]) == H_EWOULDBLOCK)
|
||||
goto done;
|
||||
bufindex++;
|
||||
buflen--;
|
||||
}
|
||||
} while (tp->t_outq.c_cc != 0);
|
||||
done:
|
||||
tp->t_state &= ~TS_BUSY;
|
||||
ttwwakeup(tp);
|
||||
/* Transmit the input buffer. */
|
||||
while (buflen) {
|
||||
if (hv_cons_putchar(buf[bufindex]) == H_EWOULDBLOCK)
|
||||
return;
|
||||
bufindex++;
|
||||
buflen--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
hvcn_tty_stop(struct tty *tp, int flag)
|
||||
{
|
||||
if ((tp->t_state & TS_BUSY) && !(tp->t_state & TS_TTSTOP))
|
||||
tp->t_state |= TS_FLUSH;
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
hvcn_intr(void *v)
|
||||
{
|
||||
struct tty *tp;
|
||||
struct tty *tp = v;
|
||||
int c;
|
||||
|
||||
tp = (struct tty *)v;
|
||||
tty_lock(tp);
|
||||
|
||||
/* Receive data. */
|
||||
while ((c = hvcn_cncheckc(NULL)) != -1)
|
||||
if (tp->t_state & TS_ISOPEN)
|
||||
ttyld_rint(tp, c);
|
||||
ttydisc_rint(tp, c, 0);
|
||||
ttydisc_rint_done(tp);
|
||||
|
||||
if (tp->t_outq.c_cc != 0 || buflen != 0)
|
||||
hvcn_tty_start(tp);
|
||||
/* Transmit trailing data. */
|
||||
hvcn_outwakeup(tp);
|
||||
tty_unlock(tp);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -381,7 +316,7 @@ static int
|
||||
hvcn_dev_attach(device_t dev)
|
||||
{
|
||||
|
||||
struct cdev *cdev;
|
||||
struct tty *tp;
|
||||
int error, rid;
|
||||
|
||||
/* belongs in attach - but attach is getting called multiple times
|
||||
@ -392,8 +327,9 @@ hvcn_dev_attach(device_t dev)
|
||||
hvcn_consdev.cn_name[0] == '\0')
|
||||
return (ENXIO);
|
||||
|
||||
cdev = make_dev(&hvcn_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "ttyv%r", 1);
|
||||
make_dev_alias(cdev, "hvcn");
|
||||
tp = tty_alloc(&hvcn_class, NULL, NULL);
|
||||
tty_makedev(tp, NULL, "v%r", 1);
|
||||
tty_makealias(tp, "hvcn");
|
||||
|
||||
rid = 0;
|
||||
|
||||
|
@ -46,7 +46,6 @@
|
||||
#include <sys/queue.h>
|
||||
#endif
|
||||
|
||||
struct tty;
|
||||
struct snapdata;
|
||||
struct devfs_dirent;
|
||||
struct cdevsw;
|
||||
@ -85,13 +84,11 @@ struct cdev {
|
||||
u_long si_usecount;
|
||||
u_long si_threadcount;
|
||||
union {
|
||||
struct tty *__sit_tty;
|
||||
struct snapdata *__sid_snapdata;
|
||||
} __si_u;
|
||||
char __si_namebuf[SPECNAMELEN + 1];
|
||||
};
|
||||
|
||||
#define si_tty __si_u.__sit_tty
|
||||
#define si_snapdata __si_u.__sid_snapdata
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
@ -62,6 +62,7 @@ struct socket;
|
||||
#define DTYPE_MQUEUE 7 /* posix message queue */
|
||||
#define DTYPE_SHM 8 /* swap-backed shared memory */
|
||||
#define DTYPE_SEM 9 /* posix semaphore */
|
||||
#define DTYPE_PTS 10 /* pseudo teletype master device */
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
|
@ -1,141 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* Copyright (c) 2004
|
||||
* Poul-Henning Kamp. All rights reserved.
|
||||
* (c) UNIX System Laboratories, Inc.
|
||||
* All or some portions of this file are derived from material licensed
|
||||
* to the University of California by American Telephone and Telegraph
|
||||
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
|
||||
* the permission of UNIX System Laboratories, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)conf.h 8.5 (Berkeley) 1/9/95
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _SYS_LINEDISC_H_
|
||||
#define _SYS_LINEDISC_H_
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
struct tty;
|
||||
|
||||
typedef int l_open_t(struct cdev *dev, struct tty *tp);
|
||||
typedef int l_close_t(struct tty *tp, int flag);
|
||||
typedef int l_read_t(struct tty *tp, struct uio *uio, int flag);
|
||||
typedef int l_write_t(struct tty *tp, struct uio *uio, int flag);
|
||||
typedef int l_ioctl_t(struct tty *tp, u_long cmd, caddr_t data,
|
||||
int flag, struct thread *td);
|
||||
typedef int l_rint_t(int c, struct tty *tp);
|
||||
typedef int l_start_t(struct tty *tp);
|
||||
typedef int l_modem_t(struct tty *tp, int flag);
|
||||
|
||||
/*
|
||||
* Line discipline switch table
|
||||
*/
|
||||
struct linesw {
|
||||
l_open_t *l_open;
|
||||
l_close_t *l_close;
|
||||
l_read_t *l_read;
|
||||
l_write_t *l_write;
|
||||
l_ioctl_t *l_ioctl;
|
||||
l_rint_t *l_rint;
|
||||
l_start_t *l_start;
|
||||
l_modem_t *l_modem;
|
||||
};
|
||||
|
||||
extern struct linesw *linesw[];
|
||||
extern int nlinesw;
|
||||
|
||||
int ldisc_register(int , struct linesw *);
|
||||
void ldisc_deregister(int);
|
||||
#define LDISC_LOAD -1 /* Loadable line discipline */
|
||||
|
||||
l_read_t l_noread;
|
||||
l_write_t l_nowrite;
|
||||
l_ioctl_t l_nullioctl;
|
||||
|
||||
static __inline int
|
||||
ttyld_open(struct tty *tp, struct cdev *dev)
|
||||
{
|
||||
|
||||
return ((*linesw[tp->t_line]->l_open)(dev, tp));
|
||||
}
|
||||
|
||||
static __inline int
|
||||
ttyld_close(struct tty *tp, int flag)
|
||||
{
|
||||
|
||||
return ((*linesw[tp->t_line]->l_close)(tp, flag));
|
||||
}
|
||||
|
||||
static __inline int
|
||||
ttyld_read(struct tty *tp, struct uio *uio, int flag)
|
||||
{
|
||||
|
||||
return ((*linesw[tp->t_line]->l_read)(tp, uio, flag));
|
||||
}
|
||||
|
||||
static __inline int
|
||||
ttyld_write(struct tty *tp, struct uio *uio, int flag)
|
||||
{
|
||||
|
||||
return ((*linesw[tp->t_line]->l_write)(tp, uio, flag));
|
||||
}
|
||||
|
||||
static __inline int
|
||||
ttyld_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
|
||||
struct thread *td)
|
||||
{
|
||||
|
||||
return ((*linesw[tp->t_line]->l_ioctl)(tp, cmd, data, flag, td));
|
||||
}
|
||||
|
||||
static __inline int
|
||||
ttyld_rint(struct tty *tp, int c)
|
||||
{
|
||||
|
||||
return ((*linesw[tp->t_line]->l_rint)(c, tp));
|
||||
}
|
||||
|
||||
static __inline int
|
||||
ttyld_start(struct tty *tp)
|
||||
{
|
||||
|
||||
return ((*linesw[tp->t_line]->l_start)(tp));
|
||||
}
|
||||
|
||||
static __inline int
|
||||
ttyld_modem(struct tty *tp, int flag)
|
||||
{
|
||||
|
||||
return ((*linesw[tp->t_line]->l_modem)(tp, flag));
|
||||
}
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#endif /* !_SYS_LINEDISC_H_ */
|
@ -57,7 +57,7 @@
|
||||
* is created, otherwise 1.
|
||||
*/
|
||||
#undef __FreeBSD_version
|
||||
#define __FreeBSD_version 800044 /* Master, propagated to newvers */
|
||||
#define __FreeBSD_version 800045 /* Master, propagated to newvers */
|
||||
|
||||
#ifndef LOCORE
|
||||
#include <sys/types.h>
|
||||
|
@ -72,10 +72,10 @@
|
||||
* (c) const until freeing
|
||||
*/
|
||||
struct session {
|
||||
int s_count; /* (m) Ref cnt; pgrps in session. */
|
||||
u_int s_count; /* Ref cnt; pgrps in session - atomic. */
|
||||
struct proc *s_leader; /* (m + e) Session leader. */
|
||||
struct vnode *s_ttyvp; /* (m) Vnode of controlling tty. */
|
||||
struct tty *s_ttyp; /* (m) Controlling tty. */
|
||||
struct tty *s_ttyp; /* (e) Controlling tty. */
|
||||
pid_t s_sid; /* (c) Session ID. */
|
||||
/* (m) Setlogin() name: */
|
||||
char s_login[roundup(MAXLOGNAME, sizeof(long))];
|
||||
@ -644,8 +644,6 @@ MALLOC_DECLARE(M_ZOMBIE);
|
||||
#define NO_PID 100000
|
||||
|
||||
#define SESS_LEADER(p) ((p)->p_session->s_leader == (p))
|
||||
#define SESSHOLD(s) ((s)->s_count++)
|
||||
#define SESSRELE(s) sessrele(s)
|
||||
|
||||
|
||||
#define STOPEVENT(p, e, v) do { \
|
||||
@ -807,7 +805,8 @@ void pstats_fork(struct pstats *src, struct pstats *dst);
|
||||
void pstats_free(struct pstats *ps);
|
||||
int securelevel_ge(struct ucred *cr, int level);
|
||||
int securelevel_gt(struct ucred *cr, int level);
|
||||
void sessrele(struct session *);
|
||||
void sess_hold(struct session *);
|
||||
void sess_release(struct session *);
|
||||
int setrunnable(struct thread *);
|
||||
void setsugid(struct proc *p);
|
||||
int sigonstack(size_t sp);
|
||||
|
@ -93,8 +93,9 @@ struct rusage {
|
||||
#define RLIMIT_SBSIZE 9 /* maximum size of all socket buffers */
|
||||
#define RLIMIT_VMEM 10 /* virtual process size (inclusive of mmap) */
|
||||
#define RLIMIT_AS RLIMIT_VMEM /* standard name for RLIMIT_VMEM */
|
||||
#define RLIMIT_NPTS 11 /* pseudo-terminals */
|
||||
|
||||
#define RLIM_NLIMITS 11 /* number of resource limits */
|
||||
#define RLIM_NLIMITS 12 /* number of resource limits */
|
||||
|
||||
#define RLIM_INFINITY ((rlim_t)(((uint64_t)1 << 63) - 1))
|
||||
/* XXX Missing: RLIM_SAVED_MAX, RLIM_SAVED_CUR */
|
||||
|
@ -91,6 +91,7 @@ struct uidinfo {
|
||||
LIST_ENTRY(uidinfo) ui_hash; /* (c) hash chain of uidinfos */
|
||||
long ui_sbsize; /* (b) socket buffer space consumed */
|
||||
long ui_proccnt; /* (b) number of processes */
|
||||
long ui_ptscnt; /* (b) number of pseudo-terminals */
|
||||
uid_t ui_uid; /* (a) uid */
|
||||
u_int ui_ref; /* (b) reference count */
|
||||
};
|
||||
@ -106,6 +107,7 @@ void calcru(struct proc *p, struct timeval *up, struct timeval *sp);
|
||||
int chgproccnt(struct uidinfo *uip, int diff, rlim_t maxval);
|
||||
int chgsbsize(struct uidinfo *uip, u_int *hiwat, u_int to,
|
||||
rlim_t maxval);
|
||||
int chgptscnt(struct uidinfo *uip, int diff, rlim_t maxval);
|
||||
int fuswintr(void *base);
|
||||
struct plimit
|
||||
*lim_alloc(void);
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* DO NOT EDIT-- this file is automatically generated.
|
||||
* $FreeBSD$
|
||||
* created from FreeBSD: src/sys/kern/syscalls.master,v 1.242 2008/03/31 12:06:55 kib Exp
|
||||
* created from FreeBSD: head/sys/kern/syscalls.master 178888 2008-05-09 23:03:00Z julian
|
||||
*/
|
||||
|
||||
#define SYS_syscall 0
|
||||
@ -419,4 +419,5 @@
|
||||
#define SYS_renameat 501
|
||||
#define SYS_symlinkat 502
|
||||
#define SYS_unlinkat 503
|
||||
#define SYS_MAXSYSCALL 504
|
||||
#define SYS_posix_openpt 504
|
||||
#define SYS_MAXSYSCALL 505
|
||||
|
@ -1,7 +1,7 @@
|
||||
# FreeBSD system call names.
|
||||
# DO NOT EDIT-- this file is automatically generated.
|
||||
# $FreeBSD$
|
||||
# created from FreeBSD: src/sys/kern/syscalls.master,v 1.242 2008/03/31 12:06:55 kib Exp
|
||||
# created from FreeBSD: head/sys/kern/syscalls.master 178888 2008-05-09 23:03:00Z julian
|
||||
MIASM = \
|
||||
syscall.o \
|
||||
exit.o \
|
||||
@ -367,4 +367,5 @@ MIASM = \
|
||||
readlinkat.o \
|
||||
renameat.o \
|
||||
symlinkat.o \
|
||||
unlinkat.o
|
||||
unlinkat.o \
|
||||
posix_openpt.o
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* DO NOT EDIT-- this file is automatically generated.
|
||||
* $FreeBSD$
|
||||
* created from FreeBSD: src/sys/kern/syscalls.master,v 1.242 2008/03/31 12:06:55 kib Exp
|
||||
* created from FreeBSD: head/sys/kern/syscalls.master 178888 2008-05-09 23:03:00Z julian
|
||||
*/
|
||||
|
||||
#ifndef _SYS_SYSPROTO_H_
|
||||
@ -1630,6 +1630,9 @@ struct unlinkat_args {
|
||||
char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)];
|
||||
char flag_l_[PADL_(int)]; int flag; char flag_r_[PADR_(int)];
|
||||
};
|
||||
struct posix_openpt_args {
|
||||
char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)];
|
||||
};
|
||||
int nosys(struct thread *, struct nosys_args *);
|
||||
void sys_exit(struct thread *, struct sys_exit_args *);
|
||||
int fork(struct thread *, struct fork_args *);
|
||||
@ -1987,6 +1990,7 @@ int readlinkat(struct thread *, struct readlinkat_args *);
|
||||
int renameat(struct thread *, struct renameat_args *);
|
||||
int symlinkat(struct thread *, struct symlinkat_args *);
|
||||
int unlinkat(struct thread *, struct unlinkat_args *);
|
||||
int posix_openpt(struct thread *, struct posix_openpt_args *);
|
||||
|
||||
#ifdef COMPAT_43
|
||||
|
||||
@ -2569,6 +2573,7 @@ int freebsd4_sigreturn(struct thread *, struct freebsd4_sigreturn_args *);
|
||||
#define SYS_AUE_renameat AUE_RENAMEAT
|
||||
#define SYS_AUE_symlinkat AUE_SYMLINKAT
|
||||
#define SYS_AUE_unlinkat AUE_UNLINKAT
|
||||
#define SYS_AUE_posix_openpt AUE_POSIXOPENPT
|
||||
|
||||
#undef PAD_
|
||||
#undef PADL_
|
||||
|
@ -83,10 +83,6 @@ typedef __pid_t pid_t;
|
||||
|
||||
#define _POSIX_VDISABLE 0xff
|
||||
|
||||
#ifndef _POSIX_SOURCE
|
||||
#define CCEQ(val, c) ((c) == (val) ? (val) != _POSIX_VDISABLE : 0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Input flags - software input processing
|
||||
*/
|
||||
@ -112,7 +108,12 @@ typedef __pid_t pid_t;
|
||||
#define OPOST 0x00000001 /* enable following output processing */
|
||||
#ifndef _POSIX_SOURCE
|
||||
#define ONLCR 0x00000002 /* map NL to CR-NL (ala CRMOD) */
|
||||
#define OXTABS 0x00000004 /* expand tabs to spaces */
|
||||
#define TABDLY 0x00000004 /* tab delay mask */
|
||||
#define TAB0 0x00000000 /* no tab delay and expansion */
|
||||
#define TAB3 0x00000004 /* expand tabs to spaces */
|
||||
#ifndef _KERNEL
|
||||
#define OXTABS TAB3
|
||||
#endif /* !_KERNEL */
|
||||
#define ONOEOT 0x00000008 /* discard EOT's (^D) on output) */
|
||||
#define OCRNL 0x00000010 /* map CR to NL on output */
|
||||
#define ONOCR 0x00000020 /* no CR output at column 0 */
|
||||
@ -143,7 +144,9 @@ typedef __pid_t pid_t;
|
||||
#define CDTR_IFLOW 0x00040000 /* DTR flow control of input */
|
||||
#define CDSR_OFLOW 0x00080000 /* DSR flow control of output */
|
||||
#define CCAR_OFLOW 0x00100000 /* DCD flow control of output */
|
||||
#define MDMBUF 0x00100000 /* old name for CCAR_OFLOW */
|
||||
#ifndef _KERNEL
|
||||
#define MDMBUF CCAR_OFLOW
|
||||
#endif /* !_KERNEL */
|
||||
#endif
|
||||
|
||||
|
||||
@ -230,6 +233,10 @@ struct termios {
|
||||
|
||||
#ifndef _KERNEL
|
||||
|
||||
#ifndef _POSIX_SOURCE
|
||||
#define CCEQ(val, c) ((c) != _POSIX_VDISABLE && (c) == (val))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Commands passed to tcsetattr() for setting the termios structure.
|
||||
*/
|
||||
|
@ -1,19 +1,9 @@
|
||||
/*-
|
||||
* Copyright (c) 1982, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* (c) UNIX System Laboratories, Inc.
|
||||
* All or some portions of this file are derived from material licensed
|
||||
* to the University of California by American Telephone and Telegraph
|
||||
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
|
||||
* the permission of UNIX System Laboratories, Inc.
|
||||
*
|
||||
* Copyright (c) 2002 Networks Associates Technologies, Inc.
|
||||
* Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions of this software were developed for the FreeBSD Project by
|
||||
* ThinkSec AS and NAI Labs, the Security Research Division of Network
|
||||
* Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
|
||||
* ("CBOSS"), as part of the DARPA CHATS research program.
|
||||
* Portions of this software were developed under sponsorship from Snow
|
||||
* B.V., the Netherlands.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -23,14 +13,11 @@
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
|
@ -73,7 +73,8 @@ struct winsize {
|
||||
/* 23-25 obsolete or unused */
|
||||
#define TIOCGETD _IOR('t', 26, int) /* get line discipline */
|
||||
#define TIOCSETD _IOW('t', 27, int) /* set line discipline */
|
||||
/* 28-69 free */
|
||||
#define TIOCPTMASTER _IO('t', 28) /* pts master validation */
|
||||
/* 29-69 free */
|
||||
/* 80-84 slip */
|
||||
#define TIOCGDRAINWAIT _IOR('t', 86, int) /* get ttywait timeout */
|
||||
#define TIOCSDRAINWAIT _IOW('t', 87, int) /* set ttywait timeout */
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user