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:
ed 2008-08-20 08:31:58 +00:00
parent b49301b5cd
commit cc3116a938
110 changed files with 6325 additions and 7142 deletions

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -40,6 +40,7 @@ default:\
:maxproc=unlimited:\
:sbsize=unlimited:\
:vmemoryuse=unlimited:\
:pseudoterminals=unlimited:\
:priority=0:\
:ignoretime@:\
:umask=022:

View File

@ -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 \

View File

@ -30,7 +30,6 @@ FBSD_1.0 {
suboptarg;
getsubopt;
grantpt;
posix_openpt;
ptsname;
unlockpt;
hcreate;

View File

@ -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
View 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);
}

View File

@ -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)

View File

@ -211,6 +211,7 @@ FBSD_1.0 {
pathconf;
pipe;
poll;
posix_openpt;
preadv;
profil;
ptrace;

View File

@ -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
View 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

View File

@ -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

View File

@ -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 }
};

View File

@ -279,6 +279,7 @@ MAN= aac.4 \
psm.4 \
pst.4 \
pt.4 \
pts.4 \
pty.4 \
puc.4 \
ral.4 \

View File

@ -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
View 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.

View File

@ -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.

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -511,4 +511,5 @@ const char *freebsd32_syscallnames[] = {
"renameat", /* 501 = renameat */
"symlinkat", /* 502 = symlinkat */
"unlinkat", /* 503 = unlinkat */
"posix_openpt", /* 504 = posix_openpt */
};

View File

@ -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 */
};

View File

@ -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); }

View File

@ -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)

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 *);

View File

@ -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)
{

View File

@ -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);

View File

@ -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);
}

View File

@ -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;

View File

@ -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) {

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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));
}
/*

View File

@ -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);

View File

@ -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;
}

View File

@ -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),

View File

@ -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);
}

View File

@ -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

View File

@ -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 *);

View File

@ -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

View File

@ -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;

View File

@ -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);
}

View File

@ -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)

View File

@ -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)

View File

@ -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;

View File

@ -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.

View File

@ -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.

View File

@ -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);
}

View File

@ -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;

View File

@ -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 */
};

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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 */
};

View File

@ -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

View File

@ -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;
};

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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);
}

View File

@ -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,

View File

@ -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
View 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
View 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);

File diff suppressed because it is too large Load Diff

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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>

View File

@ -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>

View File

@ -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;

View File

@ -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)

View File

@ -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"

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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_ */

View File

@ -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>

View File

@ -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);

View File

@ -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 */

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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_

View File

@ -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.
*/

View File

@ -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)

View File

@ -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