summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcvs2svn <cvs2svn@FreeBSD.org>1995-10-21 23:47:44 +0000
committercvs2svn <cvs2svn@FreeBSD.org>1995-10-21 23:47:44 +0000
commitc95f4bc5fb56d76b4914634e02589343e93c6362 (patch)
tree540a7f49494f77ad8bd171c19683bc8759629293
parentb08409b051b736e643fc491286c70cd852fd2215 (diff)
Notes
-rw-r--r--gnu/usr.bin/man/Makefile.shprog30
-rw-r--r--lib/libc/sys/semctl.2173
-rw-r--r--lib/libc/sys/semget.2137
-rw-r--r--lib/libc/sys/semop.2192
-rw-r--r--lib/libc/sys/shmat.2110
-rw-r--r--lib/libc/sys/shmctl.2136
-rw-r--r--lib/libc/sys/shmget.2138
-rw-r--r--release/MIRROR.SITES198
-rw-r--r--sbin/startslip/uucplock.c144
-rw-r--r--share/doc/handbook/crypt.sgml80
-rw-r--r--share/doc/handbook/dma.sgml105
-rw-r--r--share/doc/handbook/esdi.sgml421
-rw-r--r--share/doc/handbook/firewalls.sgml525
-rw-r--r--share/doc/handbook/kernelconfig.sgml1206
-rw-r--r--share/doc/handbook/printing.sgml3877
-rw-r--r--share/doc/handbook/routing.sgml279
-rw-r--r--share/doc/handbook/skey.sgml302
-rw-r--r--share/examples/sup/ports-supfile26
-rw-r--r--share/examples/sup/secure-stable-supfile2
-rw-r--r--share/examples/sup/secure-supfile2
-rw-r--r--share/examples/sup/stable-supfile15
-rw-r--r--share/examples/sup/standard-supfile15
-rw-r--r--share/man/man4/man4.i386/cy.4241
-rw-r--r--share/man/man4/man4.i386/dgb.4362
-rw-r--r--share/man/man4/man4.i386/si.4169
-rw-r--r--sys/i386/boot/kzipboot/tail.S12
-rw-r--r--sys/i386/isa/atapi.c856
-rw-r--r--sys/i386/isa/atapi.h215
-rw-r--r--sys/i386/isa/wcd.c984
-rw-r--r--usr.bin/ee/nls/de_DE.ISO_8859-1/ee.msg170
-rw-r--r--usr.sbin/sicontrol/sicontrol.8113
31 files changed, 11235 insertions, 0 deletions
diff --git a/gnu/usr.bin/man/Makefile.shprog b/gnu/usr.bin/man/Makefile.shprog
new file mode 100644
index 000000000000..665a194917ff
--- /dev/null
+++ b/gnu/usr.bin/man/Makefile.shprog
@@ -0,0 +1,30 @@
+# $Id$
+
+# This may become bsd.shprog.mk. The general version would have to handle:
+# - arbitrary sed substitutions.
+# - programs without man pages.
+# - programs with man pages in sections other than section 1.
+
+MAN1= ${SHPROG:S/$/.1/g}
+
+CLEANFILES+= ${SHPROG} ${MAN1}
+
+all: ${SHPROG}
+
+.sh:
+ sed -e 's,%libdir%,${libdir},' -e 's,%bindir%,${bindir},' \
+ -e 's,%pager%,${pager},' \
+ ${.ALLSRC} > ${.TARGET}
+
+.SUFFIXES: .man .1
+.man.1:
+ sed -e 's,%libdir%,${libdir},' -e 's,%bindir%,${bindir},' \
+ -e 's,%pager%,${pager},' -e 's,%troff%,${troff},' \
+ -e 's,%manpath_config_file%,${manpath_config_file},' \
+ ${.ALLSRC} > ${.TARGET}
+
+beforeinstall:
+ ${INSTALL} ${COPY} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${SHPROG} ${DESTDIR}${BINDIR}
+
+.include <bsd.prog.mk>
diff --git a/lib/libc/sys/semctl.2 b/lib/libc/sys/semctl.2
new file mode 100644
index 000000000000..fe60ce048443
--- /dev/null
+++ b/lib/libc/sys/semctl.2
@@ -0,0 +1,173 @@
+.\"
+.\" Copyright (c) 1995 David Hovemeyer <daveho@infocom.com>
+.\"
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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.
+.\"
+.\" $Id$
+.\"
+.Dd September 12, 1995
+.Dt SEMCTL 2
+.Os FreeBSD
+.Sh NAME
+.Nm semctl
+.Nd control operations on a semaphore set
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <sys/ipc.h>
+.Fd #include <sys/sem.h>
+.Ft int
+.Fn "semctl" "int semid" "int semnum" "int cmd" "union semun arg"
+.Sh DESCRIPTION
+.Fn Semctl
+performs the operation indicated by
+.Fa cmd
+on the semaphore set indicated by
+.Fa semid .
+For the commands that use the
+.Fa arg
+parameter,
+.Fa "union semun"
+is defined as follows:
+.Bd -literal
+.\"
+.\" From <sys/sem.h>:
+.\"
+union semun {
+ int val; /* value for SETVAL */
+ struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */
+ u_short *array; /* array for GETALL & SETALL */
+};
+.Ed
+.Pp
+Commands are performed as follows:
+.\"
+.\" This section based on Stevens, _Advanced Programming in the UNIX
+.\" Environment_.
+.\"
+.Bl -tag -width IPC_RMIDXXX
+.It Dv IPC_STAT
+Fetch the semaphore set's
+.Fa "struct semid_ds" ,
+storing it in the memory pointed to by
+.Fa arg.buf .
+.It Dv IPC_SET
+Changes the
+.Fa sem_perm.uid ,
+.Fa sem_perm.gid ,
+and
+.Fa sem_perm.mode
+members of the semaphore set's
+.Fa "struct semid_ds"
+to match those of the struct pointed to by
+.Fa arg.buf .
+The calling process's effective uid must
+match either
+.Fa sem_perm.uid
+or
+.Fa sem_perm.cuid ,
+or it must have superuser privileges.
+.It IPC_RMID
+Immediately removes the semaphore set from the system. The calling
+process's effictive uid must equal the semaphore set's
+.Fa sem_perm.uid
+or
+.Fa sem_perm.cuid ,
+or the process must have superuser priviliges.
+.It Dv GETVAL
+Return the value of semaphore number
+.Fa semnum .
+.It Dv SETVAL
+Set the value of semaphore number
+.Fa semnum
+to
+.Fa arg.val .
+.It Dv GETPID
+Return the pid of the last process to perform an operation on
+semaphore number
+.Fa semnum .
+.It Dv GETNCNT
+Return the number of processes waiting for semaphore number
+.Fa semnum Ns 's
+value to become greater than its current value.
+.It Dv GETZCNT
+Return the number of processes waiting for semaphore number
+.Fa semnum Ns 's
+value to become 0.
+.It Dv GETALL
+Fetch the value of all of the semaphores in the set into the
+array pointed to by
+.Fa arg.array .
+.It Dv SETALL
+Set the values of all of the semaphores in the set to the values
+in the array pointed to by
+.Fa arg.array .
+.El
+.Pp
+The
+.Fa "struct semid_ds"
+is defined as follows:
+.Bd -literal
+.\"
+.\" Taken straight from <sys/sem.h>.
+.\"
+struct semid_ds {
+ struct ipc_perm sem_perm; /* operation permission struct */
+ struct sem *sem_base; /* pointer to first semaphore in set */
+ u_short sem_nsems; /* number of sems in set */
+ time_t sem_otime; /* last operation time */
+ long sem_pad1; /* SVABI/386 says I need this here */
+ time_t sem_ctime; /* last change time */
+ /* Times measured in secs since */
+ /* 00:00:00 GMT, Jan. 1, 1970 */
+ long sem_pad2; /* SVABI/386 says I need this here */
+ long sem_pad3[4]; /* SVABI/386 says I need this here */
+};
+.Ed
+.Sh RETURN VALUES
+On success, when
+.Fa cmd
+is one of GETVAL, GETNCNT, or GETZCNT,
+.Fn semctl
+returns the corresponding value; otherwise, 0 is returned.
+On failure, -1 is returned, and
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+.Fn Semctl
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+No semaphore set corresponds to
+.Fa semid .
+.It Bq Er EINVAL
+.Fa semnum
+is not in the range of valid semaphores for given semaphore set.
+.It Bq Er EPERM
+The calling process's effective uid does not match the uid of
+the semaphore set's owner or creator.
+.It Bq Er EACCES
+Permission denied due to mismatch between operation and mode of
+semaphore set.
+.Sh SEE ALSO
+.Xr semget 2 ,
+.Xr semop 2
diff --git a/lib/libc/sys/semget.2 b/lib/libc/sys/semget.2
new file mode 100644
index 000000000000..323aef47043d
--- /dev/null
+++ b/lib/libc/sys/semget.2
@@ -0,0 +1,137 @@
+.\"
+.\" Copyright (c) 1995 David Hovemeyer <daveho@infocom.com>
+.\"
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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.
+.\"
+.\" $Id$
+.\"
+.Dd September 12, 1995
+.Dt SEMGET 2
+.Os FreeBSD
+.Sh NAME
+.Nm semget
+.Nd obtain a semaphore id
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <sys/ipc.h>
+.Fd #include <sys/sem.h>
+.Ft int
+.Fn "semget" "key_t key" "int nsems" "int flag"
+.Sh DESCRIPTION
+Based on the values of
+.Fa key
+and
+.Fa flag ,
+.Fn semget
+returns the identifier of a newly created or previously existing
+set of semaphores.
+.\"
+.\" This is copied verbatim from the shmget manpage. Perhaps
+.\" it should go in a common manpage, such as .Xr ipc 2
+.\"
+The key
+is analogous to a filename: it provides a handle that names an
+IPC object. There are three ways to specify a key:
+.Bl -bullet
+.It
+IPC_PRIVATE may be specified, in which case a new IPC object
+will be created.
+.It
+An integer constant may be specified. If no IPC object corresponding
+to
+.Fa key
+is specified and the IPC_CREAT bit is set in
+.Fa flag ,
+a new one will be created.
+.It
+.Fn ftok
+may be used to generate a key from a pathname. See
+.Xr ftok 3 .
+.El
+.\"
+.\" Likewise for this section, except SHM_* becomes SEM_*.
+.\"
+.Pp
+The mode of a newly created IPC object is determined by
+.Em OR Ns 'ing
+the following constants into the
+.Fa flag
+parameter:
+.Bl -tag -width XSEM_WXX6XXX
+.It Dv SEM_R
+Read access for user.
+.It Dv SEM_W
+Write access for user.
+.It Dv (SEM_R>>3)
+Read access for group.
+.It Dv (SEM_W>>3)
+Write access for group.
+.It Dv (SEM_R>>6)
+Read access for other.
+.It Dv (SEM_W>>6)
+Write access for other.
+.El
+.Pp
+If a new set of semaphores is being created,
+.Fa nsems
+is used to indicate the number of semaphores the set should contain.
+Otherwise,
+.Fa nsems
+may be specified as 0.
+.Sh RETURN VALUES
+.Fn Semget
+returns the id of a semaphore set if successful; otherwise, -1
+is returned and
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+.Fn Semget
+will fail if:
+.Bl -tag -width Er
+.\" ipcperm could fail (we're opening to read and write, as it were)
+.It Bq Er EACCES
+Access permission failure.
+.\"
+.\" sysv_sem.c is quite explicit about these, so I'm pretty sure
+.\" this is accurate
+.\"
+.It Bq Er EEXIST
+IPC_CREAT and IPC_EXCL were specified, and a semaphore set
+corresponding to
+.Fa key
+already exists.
+.It Bq Er EINVAL
+The number of semaphores requested exceeds the system imposed maximum
+per set.
+.It Bq Er ENOSPC
+Insufficiently many semaphores are available.
+.It Bq Er ENOSPC
+The kernel could not allocate a
+.Fa "struct semid_ds" .
+.It Bq Er ENOENT
+No semaphore set was found corresponding to
+.Fa key ,
+and IPC_CREAT was not specified.
+.Sh SEE ALSO
+.Xr semctl 2 ,
+.Xr semop 2
diff --git a/lib/libc/sys/semop.2 b/lib/libc/sys/semop.2
new file mode 100644
index 000000000000..74fa01bc7f03
--- /dev/null
+++ b/lib/libc/sys/semop.2
@@ -0,0 +1,192 @@
+.\"
+.\" Copyright (c) 1995 David Hovemeyer <daveho@infocom.com>
+.\"
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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.
+.\"
+.\" $Id$
+.\"
+.Dd September 22, 1995
+.Dt SEMOP 2
+.Os FreeBSD
+.Sh NAME
+.Nm semop
+.Nd atomic array of operations on a semaphore set
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <sys/ipc.h>
+.Fd #include <sys/sem.h>
+.Ft int
+.Fn "semop" "int semid" "struct sembuf array[]" "unsigned nops"
+.Sh DESCRIPTION
+.Fn Semop
+atomically performs the array of operations indicated by
+.Fa array
+on the semaphore set indicated by
+.Fa semid .
+The length of
+.Fa array
+is indicated by
+.Fa nops .
+Each operation is encoded in a
+.Fa "struct sembuf" ,
+which is defined as follows:
+.Bd -literal
+.\"
+.\" From <sys/sem.h>
+.\"
+struct sembuf {
+ u_short sem_num; /* semaphore # */
+ short sem_op; /* semaphore operation */
+ short sem_flg; /* operation flags */
+};
+.Ed
+.Pp
+For each element in
+.Fa array ,
+.Fa sem_op
+and
+.Fa sem_flg
+determine an operation to be performed on semaphore number
+.Fa sem_num
+in the set. The values SEM_UNDO and IPC_NOWAIT may be
+.Em OR Ns 'ed
+into the
+.Fa sem_flg
+member in order to modify the behavior of the given operation.
+.Pp
+The operation performed depends as follows on the value of
+.Fa sem_op :
+.\"
+.\" This section is based on the description of semop() in
+.\" Stevens, _Advanced Programming in the UNIX Environment_.
+.\"
+.Bl -bullet
+.It
+When
+.Fa sem_op
+is positive, the semaphore's value is incremented by
+.Fa sem_op Ns 's
+value. If SEM_UNDO is specified, the semaphore's adjust on exit
+value is decremented by
+.Fa sem_op Ns 's
+value. A positive value for
+.Fa sem_op
+generally corresponds to a process releasing a resource
+associated with the semaphore.
+.It
+The behavior when
+.Fa sem_op
+is negative depends on the current value of the semaphore:
+.Bl -bullet
+.It
+If the current value of the semaphore is greater than or equal to
+the absolute value of
+.Fa sem_op ,
+then the value is decremented by the absolute value of
+.Fa sem_op .
+If SEM_UNDO is specified, the semaphore's adjust on exit
+value is incremented by the absolute value of
+.Fa sem_op .
+.It
+If the current value of the semaphore is less than
+.Fa sem_op Ns 's
+value, one of the following happens:
+.\" XXX a *second* sublist?
+.Bl -bullet
+.It
+If IPC_NOWAIT was specifed, then
+.Fn semop
+returns immediately with a return value of EAGAIN.
+.It
+If some other process has removed the semaphore with the IPC_RMID
+option of
+.Fn semctl ,
+then
+.Fn semop
+returns immediately with a return value of EINVAL.
+.It
+Otherwise, the calling process is put to sleep until the semaphore's
+value is greater than or equal to the absolute value of
+.Fa sem_op .
+When this condition becomes true, the semaphore's value is decremented
+by the absolute value of
+.Fa sem_op ,
+and the semaphore's adjust on exit value is incremented by the
+absolute value of
+.Fa sem_op .
+.El
+.Pp
+A negative value for
+.Fa sem_op
+generally means that a process is waiting for a resource to become
+available.
+.El
+.Pp
+.It
+When
+.Fa sem_op
+is zero, the process waits for the semaphore's value to become zero.
+If it is already zero, the call to
+.Fn semop
+can return immediately. Otherwise, the calling process is put to
+sleep until the semaphore's value becomes zero.
+.El
+.Pp
+For each semaphore a process has in use, the kernel maintains an
+`adjust on exit' value, as alluded to earlier. When a process
+exits, either voluntarily or involuntarily, the adjust on exit value
+for each semaphore is added to the semaphore's value. This can
+be used to insure that a resource is released if a process terminates
+unexpectedly.
+.Sh RETURN VALUES
+On success,
+.Fn semop
+returns 0; otherwise, -1 is returned and
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+.Fn Semop
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+No semaphore set corresponds to
+.Fa semid .
+.It Bq Er EACCES
+Permission denied due to mismatch between operation and mode of
+semaphore set.
+.It Bq Er EAGAIN
+The semaphore's value was less than
+.Fa sem_op ,
+and IPC_NOWAIT was specified.
+.It Bq Er E2BIG
+Too many operations were specified.
+.It Bq Er EFBIG
+.\"
+.\" I'd have thought this would be EINVAL, but the source says
+.\" EFBIG.
+.\"
+.Fa sem_num
+was not in the range of valid semaphores for the set.
+.Sh SEE ALSO
+.Xr semget 2 ,
+.Xr semctl 2
diff --git a/lib/libc/sys/shmat.2 b/lib/libc/sys/shmat.2
new file mode 100644
index 000000000000..587eebc6cb1d
--- /dev/null
+++ b/lib/libc/sys/shmat.2
@@ -0,0 +1,110 @@
+.\"
+.\" Copyright (c) 1995 David Hovemeyer <daveho@infocom.com>
+.\"
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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.
+.\"
+.\" $Id$
+.\"
+.Dd August 2, 1995
+.Dt SHMAT 2
+.Os FreeBSD
+.Sh NAME
+.Nm shmat ,
+.Nm shmdt
+.Nd attach or detach shared memory
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <sys/ipc.h>
+.Fd #include <sys/shm.h>
+.Ft void *
+.Fn "shmat" "int shmid" "void *addr" "int flag"
+.Ft int
+.Fn "shmdt" "void *addr"
+.Sh DESCRIPTION
+.Fn Shmat
+attaches the shared memory segment identifed by
+.Fa shmid
+to the calling process's address space. The address where the segment
+is attached is determined as follows:
+.\"
+.\" These are cribbed almost exactly from Stevens, _Advanced Programming in
+.\" the UNIX Environment_.
+.\"
+.Bl -bullet
+.It
+If
+.Fa addr
+is 0, the segment is attached at an address selected by the
+kernel.
+.It
+If
+.Fa addr
+is nonzero and SHM_RND is not specifed in
+.Fa flag ,
+the segment is attached the specified address.
+.It
+If
+.Fa addr
+is specified and SHM_RND is specified,
+.Fa addr
+is rounded down to the nearest multiple of SHMLBA.
+.El
+.Pp
+.Fn Shmdt
+detaches the shared memory segment at the address specified by
+.Fa addr
+from the calling process's address space.
+.Sh RETURN VALUES
+Upon success,
+.Fn shmat
+returns the address where the segment is attached; otherwise, -1
+is returned and
+.Va errno
+is set to indicate the error.
+.Pp
+Upon success,
+.Fn shmdt
+returns 0; otherwise, -1 is returned and
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+.Fn Shmat
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+No shared memory segment was found corresponding to
+.Fa shmid .
+.It Bq Er EINVAL
+.Fa addr
+was not an acceptable address.
+.El
+.Pp
+.Fn Shmdt
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+.Fa addr
+does not point to a shared memory segment.
+.Sh "SEE ALSO"
+.Xr shmget 2 ,
+.Xr shmctl 2
diff --git a/lib/libc/sys/shmctl.2 b/lib/libc/sys/shmctl.2
new file mode 100644
index 000000000000..b1c5a4bdf6b2
--- /dev/null
+++ b/lib/libc/sys/shmctl.2
@@ -0,0 +1,136 @@
+.\"
+.\" Copyright (c) 1995 David Hovemeyer <daveho@infocom.com>
+.\"
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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.
+.\"
+.\" $Id$
+.\"
+.Dd July 17, 1995
+.Dt SHMCTL 2
+.Os FreeBSD
+.Sh NAME
+.Nm shmctl
+.Nd shared memory control
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <sys/ipc.h>
+.Fd #include <sys/shm.h>
+.Ft int
+.Fn "shmctl" "int shmid" "int cmd" "struct shmid_ds *buf"
+.Sh DESCRIPTION
+Performs the action specified by
+.Fa cmd
+on the shared memory segment identified by
+.Fa shmid :
+.Bl -tag -width SHM_UNLOCKX
+.It Dv IPC_STAT
+Fetch the segment's
+.Fa "struct shmid_ds" ,
+storing it in the memory pointed to by
+.Fa buf .
+.\"
+.\" XXX need to make sure that this is correct for FreeBSD
+.\"
+.It Dv IPC_SET
+Changes the
+.Fa shm_perm.uid ,
+.Fa shm_perm.gid ,
+and
+.Fa shm_perm.mode
+members of the segment's
+.Fa "struct shmid_ds"
+to match those of the struct pointed to by
+.Fa buf .
+The calling process's effective uid must
+match either
+.Fa shm_perm.uid
+or
+.Fa shm_perm.cuid ,
+or it must have superuser privileges.
+.It Dv IPC_RMID
+Removes the segment from the system. The removal will not take
+effect until all processes having attached the segment have exited;
+however, once the IPC_RMID operation has taken place, no further
+processes will be allowed to attach the segment. For the operation
+to succeed, the calling process's effective uid must match
+.Fa shm_perm.uid
+or
+.Fa shm_perm.cuid ,
+or the process must have superuser privilges.
+.\" .It Dv SHM_LOCK
+.\" Locks the segment in memory. The calling process must have
+.\" superuser privileges. Not implemented in FreeBSD.
+.\" .It Dv SHM_UNLOCK
+.\" Unlocks the segment from memory. The calling process must
+.\" have superuser priviliges. Not implemented in FreeBSD.
+.El
+.Pp
+The
+.Fa "shmid_ds"
+struct is defined as follows:
+.\"
+.\" I fiddled with the spaces a bit to make it fit well when viewed
+.\" with nroff, but otherwise it's straight from sys/shm.h
+.\"
+.Bd -literal
+struct shmid_ds {
+ struct ipc_perm shm_perm; /* operation permission structure */
+ int shm_segsz; /* size of segment in bytes */
+ pid_t shm_lpid; /* process ID of last shared memory op */
+ pid_t shm_cpid; /* process ID of creator */
+ short shm_nattch; /* number of current attaches */
+ time_t shm_atime; /* time of last shmat() */
+ time_t shm_dtime; /* time of last shmdt() */
+ time_t shm_ctime; /* time of last change by shmctl() */
+ void *shm_internal; /* sysv stupidity */
+};
+.Ed
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn shmctl
+returns 0. Otherwise, it returns -1 and
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+.Fn Shmctl
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Invalid operation, or
+no shared memory segment was found corresponding to
+.Fa shmid .
+.\"
+.\" XXX I think the following is right: ipcperm() only returns EPERM
+.\" when an attempt is made to modify (IPC_M) by a non-creator
+.\" non-owner
+.It Bq Er EPERM
+The calling process's effective uid does not match the uid of
+the shared memory segment's owner or creator.
+.It Bq Er EACCES
+Permission denied due to mismatch between operation and mode of
+shared memory segment.
+.Sh "SEE ALSO"
+.Xr shmget 2 ,
+.Xr shmat 2 ,
+.Xr shmdt 2 ,
+.Xr ftok 3
diff --git a/lib/libc/sys/shmget.2 b/lib/libc/sys/shmget.2
new file mode 100644
index 000000000000..3df3272131cd
--- /dev/null
+++ b/lib/libc/sys/shmget.2
@@ -0,0 +1,138 @@
+.\"
+.\" Copyright (c) 1995 David Hovemeyer <daveho@infocom.com>
+.\"
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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.
+.\"
+.\" $Id$
+.\"
+.Dd July 3, 1995
+.Dt SHMGET 2
+.Os FreeBSD
+.Sh NAME
+.Nm shmget
+.Nd obtain a shared memory identifier
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <sys/ipc.h>
+.Fd #include <sys/shm.h>
+.Ft int
+.Fn "shmget" "key_t key" "int size" "int flag"
+.Sh DESCRIPTION
+Based on the values of
+.Fa key
+and
+.Fa flag ,
+.Fn shmget
+returns the identifier of a newly created or previously existing shared
+memory segment.
+.\"
+.\" The following bit about keys and modes also applies to semaphores
+.\" and message queues.
+.\"
+The key
+is analogous to a filename: it provides a handle that names an
+IPC object. There are three ways to specify a key:
+.Bl -bullet
+.It
+IPC_PRIVATE may be specified, in which case a new IPC object
+will be created.
+.It
+An integer constant may be specified. If no IPC object corresponding
+to
+.Fa key
+is specified and the IPC_CREAT bit is set in
+.Fa flag ,
+a new one will be created.
+.It
+.Fn ftok
+may be used to generate a key from a pathname. See
+.Xr ftok 3 .
+.El
+.Pp
+The mode of a newly created IPC object is determined by
+.Em OR Ns 'ing
+the following constants into the
+.Fa flag
+parameter:
+.Bl -tag -width XSHM_WXX6XXX
+.It Dv SHM_R
+Read access for user.
+.It Dv SHM_W
+Write access for user.
+.It Dv (SHM_R>>3)
+Read access for group.
+.It Dv (SHM_W>>3)
+Write access for group.
+.It Dv (SHM_R>>6)
+Read access for other.
+.It Dv (SHM_W>>6)
+Write access for other.
+.El
+.\"
+.\" XXX - we should also mention how uid, euid, and gid affect ownership
+.\" and use
+.\"
+.\" end section about keys and modes
+.\"
+.Pp
+When creating a new shared memory segment,
+.Fa size
+indicates the desired size of the new segment in bytes. The size
+of the segment may be rounded up to a multiple convenient to the
+kernel (i.e., the page size).
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn shmget
+returns the positive integer identifier of a shared memory segment.
+Otherwise, -1 is returned and
+.Va errno
+set to indicate the error.
+.Sh ERRORS
+.Fn Shmget
+will fail if:
+.Bl -tag -width Er
+.\"
+.\" XXX What about ipcperm failing?
+.\"
+.It Bq Er EINVAL
+Size specified is greater than the size of the previously existing segment.
+Size specified is less than the system imposed minumum, or greater than
+the system imposed maximum.
+.It Bq Er ENOENT
+No shared memory segment was found matching
+.Fa key ,
+and IPC_CREAT was not specified.
+.It Bq Er ENOSPC
+The kernel was unable to allocate enough memory to
+satisfy the request.
+.It Bq Er EEXIST
+IPC_CREAT and IPC_EXCL were specified, and a shared memory segment
+corresponding to
+.Fa key
+already exists.
+.Pp
+.Sh "SEE ALSO"
+.Xr shmctl 2 ,
+.Xr shmat 2 ,
+.Xr shmdt 2 ,
+.Xr ftok 3
diff --git a/release/MIRROR.SITES b/release/MIRROR.SITES
new file mode 100644
index 000000000000..cc817e45b88b
--- /dev/null
+++ b/release/MIRROR.SITES
@@ -0,0 +1,198 @@
+$Id$
+
+Obtaining FreeBSD
+
+ The official sources for FreeBSD available via anonymous FTP from:
+
+ ftp://ftp.FreeBSD.org/pub/FreeBSD
+
+ and on CD-ROM from Walnut Creek CDROM:
+
+ Walnut Creek CDROM
+ 1547 Palos Verdes Mall, Suite 260
+ Walnut Creek CA 94596 USA
+ Phone: +1 510 674-0783
+ Fax: +1 510 674-0821
+ Email: info@cdrom.com
+ WWW: http://www.cdrom.com/
+
+
+ Additionally, FreeBSD is available via anonymous FTP from the
+ following mirror sites. If you choose to obtain FreeBSD via anonymous
+ FTP, please try to use a site near you.
+
+ Australia
+
+ + ftp://ftp.physics.usyd.edu.au/FreeBSD
+ Contact: dawes@xfree86.org.
+
+ + ftp://minnie.cs.adfa.oz.au/FreeBSD
+ Contact: wkt@dolphin.cs.adfa.oz.au.
+
+ Canada
+
+ + ftp://ftp.synapse.net/contrib/FreeBSD
+ Contact: evanc@synapse.net.
+
+ Finland
+
+ + ftp://nic.funet.fi/pub/unix/FreeBSD
+ Contact: count@nic.funet.fi.
+
+ France
+
+ + ftp://ftp.ibp.fr/pub/FreeBSD
+ Contact: Remy.Card@ibp.fr.
+
+ Germany
+
+ + ftp://ftp.fb9dv.uni-duisburg.de/pub/unix/FreeBSD
+ Contact: ftp@ftp.fb9dv.uni-duisburg.de.
+
+ + ftp://gil.physik.rwth-aachen.de/pub/FreeBSD
+ Contact: kuku@gil.physik.rwth-aachen.de.
+
+ + ftp://ftp.uni-paderborn.de/freebsd
+ Contact: ftp@uni-paderborn.de.
+
+ + ftp://ftp.leo.org/pub/comp/os/bsd/FreeBSD
+ Contact: bsd@leo.org.
+
+ + ftp://ftp.tu-dresden.de/pub/soft/unix/bsd/FreeBSD
+ Contact: pdsowner@rcs1.urz.tu-dresden.de.
+
+ Ireland
+
+ + ftp://ftp.internet-eireann.ie/pub/FreeBSD
+ Contact: ftpadmin@internet-eireann.ie.
+
+ Israel
+
+
+ + ftp://orgchem.weizmann.ac.il/pub/FreeBSD
+ Contact: serg@klara.weizmann.ac.il.
+
+ Hong Kong
+
+ + ftp://ftp.hk.super.net/pub/FreeBSD
+ Contact: ftp-admin@HK.Super.NET.
+
+ Korea
+
+ + ftp://ftp.cau.ac.kr/pub/FreeBSD
+ Contact: ftpadm@ftp.cau.ac.kr.
+
+ Netherlands
+
+ + ftp://ftp.nl.net/pub/os/FreeBSD
+ Contact: archive@nl.net.
+
+ Russia
+
+ + ftp://ftp.kiae.su/FreeBSD
+ Contact: ftp@ftp.kiae.su.
+
+ Sweden
+
+ + ftp://ftp.luth.se/pub/FreeBSD
+ Contact: ragge@ludd.luth.se.
+
+ Taiwan
+
+ + ftp://NCTUCCCA.edu.tw/Operating-Systems/FreeBSD
+ Contact: freebsd@NCTUCCCA.edu.tw.
+
+ + ftp://netbsd.csie.nctu.edu.tw/pub/FreeBSD
+ Contact: ftp@netbsd.csie.nctu.edu.tw.
+
+ Thailand
+
+ + ftp://ftp.nectec.or.th/pub/FreeBSD
+ Contact: ftpadmin@ftp.nectec.or.th.
+
+ USA
+
+ + ftp://gatekeeper.dec.com/pub/BSD/FreeBSD
+ Contact: hubbard@gatekeeper.dec.com.
+
+ + ftp://ftp.cybernetics.net/pub/FreeBSD
+ Contact: michael@Cybernetics.NET.
+
+ + ftp://ftp.neosoft.com/systems/FreeBSD
+ Contact: smace@NeoSoft.COM.
+
+ + ftp://kryten.atinc.com/pub/FreeBSD
+ Contact: jmb@kryten.atinc.com.
+
+ + ftp://ftp.dataplex.net/pub/FreeBSD
+ Contact: rkw@dataplex.net.
+
+ + ftp://ftp.cps.cmich.edu/pub/ftp.freebsd.org
+ Contact: ftpadmin@cps.cmich.edu.
+
+ + ftp://ftp.cslab.vt.edu/pub/FreeBSD
+ Contact: ftp@ftp.cslab.vt.edu.
+
+ Japan
+
+ + ftp://ftp.tokyonet.ad.jp/pub/FreeBSD
+ Contact: ftpadmin@TokyoNet.AD.JP.
+
+ + ftp://ftp.tut.ac.jp/FreeBSD
+ Contact: ashida@ftp.tut.ac.jp.
+
+ + ftp://ftp.sra.co.jp/pub/os/FreeBSD
+ Contact: ftp-admin@sra.co.jp.
+
+ + ftp://ftp.ee.uec.ac.jp/pub/os/mirror/ftp.freebsd.org
+ Contact: ftp-admin@ftp.ee.uec.ac.jp.
+
+ + ftp://ftp.mei.co.jp/free/PC-UNIX/FreeBSD
+ Contact: tanig@isl.mei.co.jp.
+
+ + ftp://ftp.waseda.ac.jp/pub/FreeBSD
+ Contact: ftp-admin@waseda.ac.jp.
+
+ + ftp://ftp.pu-toyama.ac.jp/pub/FreeBSD
+ Contact: Yoshihiko USUI usui@pu-toyama.ac.jp.
+
+ + ftp://ftpsv1.u-aizu.ac.jp/pub/os/FreeBSD
+ Contact: ftp-admin@u-aizu.ac.jp.
+
+ UK
+
+ + ftp://src.doc.ic.ac.uk/packages/unix/FreeBSD
+ Contact: wizards@doc.ic.ac.uk.
+
+ + ftp://unix.hensa.ac.uk/pub/walnut.creek/FreeBSD
+ Contact: archive-admin@unix.hensa.ac.uk.
+
+ + ftp://ftp.demon.co.uk/pub/BSD/FreeBSD
+ Contact: uploads@demon.net.
+
+
+
+ The latest versions of export-restricted code for FreeBSD (2.0C or
+ later) (eBones and secure) are being made available at the following
+ locations. If you are outside the U.S. or Canada, please get secure
+ (DES) and eBones (Kerberos) from one of the following foreign
+ distribution sites:
+
+ SouthAfrica
+
+ + ftp://ftp.internat.freebsd.org/pub/FreeBSD
+ Contact: Mark Murray mark@grondar.za.
+
+ + ftp://storm.sea.uct.ac.za/pub/FreeBSD
+ Contact: Shaun Courtney ftp@storm.sea.uct.ac.za.
+
+ Brazil
+
+ + ftp://ftp.iqm.unicamp.br/pub/FreeBSD
+ Contact: Pedro A M Vazquez vazquez@iqm.unicamp.br.
+
+ Finland
+
+ + ftp://nic.funet.fi/pub/unix/FreeBSD/eurocrypt
+ Contact: count@nic.funet.fi.
+
diff --git a/sbin/startslip/uucplock.c b/sbin/startslip/uucplock.c
new file mode 100644
index 000000000000..20a823915da9
--- /dev/null
+++ b/sbin/startslip/uucplock.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 1988, 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)uucplock.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/dir.h>
+#include <errno.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <paths.h>
+
+#define LOCKFMT "LCK..%s"
+
+/* Forward declarations */
+static int put_pid (int fd, pid_t pid);
+static pid_t get_pid (int fd);
+
+/*
+ * uucp style locking routines
+ * return: 0 - success
+ * -1 - failure
+ */
+
+int uu_lock (char *ttyname)
+{
+ int fd;
+ pid_t pid;
+ char tbuf[MAXNAMLEN];
+
+ (void)sprintf(tbuf, _PATH_UUCPLOCK LOCKFMT, ttyname);
+ fd = open(tbuf, O_RDWR|O_CREAT|O_EXCL, 0660);
+ if (fd < 0) {
+ /*
+ * file is already locked
+ * check to see if the process holding the lock still exists
+ */
+ fd = open(tbuf, O_RDWR, 0);
+ if (fd < 0) {
+ syslog(LOG_ERR, "lock open: %m");
+ return(-1);
+ }
+ if ((pid = get_pid (fd)) == -1) {
+ syslog(LOG_ERR, "lock read: %m");
+ (void)close(fd);
+ return(-1);
+ }
+
+ if (kill(pid, 0) == 0 || errno != ESRCH) {
+ (void)close(fd); /* process is still running */
+ return(-1);
+ }
+ /*
+ * The process that locked the file isn't running, so
+ * we'll lock it ourselves
+ */
+ if (lseek(fd, 0L, L_SET) < 0) {
+ syslog(LOG_ERR, "lock lseek: %m");
+ (void)close(fd);
+ return(-1);
+ }
+ /* fall out and finish the locking process */
+ }
+ pid = getpid();
+ if (!put_pid (fd, pid)) {
+ syslog(LOG_ERR, "lock write: %m");
+ (void)close(fd);
+ (void)unlink(tbuf);
+ return(-1);
+ }
+ (void)close(fd);
+ return(0);
+}
+
+int uu_unlock (char *ttyname)
+{
+ char tbuf[MAXNAMLEN];
+
+ (void)sprintf(tbuf, _PATH_UUCPLOCK LOCKFMT, ttyname);
+ return(unlink(tbuf));
+}
+
+static int put_pid (int fd, pid_t pid)
+{
+ char buf [32];
+ int len;
+
+ len = sprintf (buf, "%10ld\n", pid);
+ return write (fd, buf, len) == len;
+}
+
+static pid_t get_pid (int fd)
+{
+ int bytes_read;
+ char buf [32];
+ pid_t pid;
+
+ bytes_read = read (fd, buf, sizeof (buf) - 1);
+ if (bytes_read > 0) {
+ buf [bytes_read] = '\0';
+ pid = strtol (buf, (char **) NULL, 10);
+ }
+ else
+ pid = -1;
+ return pid;
+}
+
+/* end of uucplock.c */
diff --git a/share/doc/handbook/crypt.sgml b/share/doc/handbook/crypt.sgml
new file mode 100644
index 000000000000..2efe3504cdaa
--- /dev/null
+++ b/share/doc/handbook/crypt.sgml
@@ -0,0 +1,80 @@
+<!-- $Id$ -->
+<!-- The FreeBSD Documentation Project -->
+
+<sect><heading>DES, MD5, and Crypt<label id="crypt"></heading>
+
+<p><em>Contributed by &a.wollman;<newline>24 September 1995.</em>
+
+<p><bf>History</bf>
+
+<p>In order to protect the security of passwords on UN*X systems from
+being easily exposed, passwords have traditionally been scrambled in
+some way. Starting with Bell Labs' Seventh Edition Unix, passwords
+were encrypted using what the security people call a ``one-way hash
+function''. That is to say, the password is transformed in such a way
+that the original password cannot be regained except by brute-force
+searching the space of possible passwords. Unfortunately, the only
+secure method that was available to the AT&amp;T researchers at the
+time was based on DES, the Data Encryption Standard. This causes only
+minimal difficulty for commercial vendors, but is a serious problem
+for an operating system like FreeBSD where all the source code is
+freely available, because national governments in many places like to
+place restrictions on cross-border transport of DES and other
+encryption software.
+
+<p>So, the FreeBSD team was faced with a dilemma: how could we provide
+compatibility with all those UNIX systems out there while still not
+running afoul of the law? We decided to take a dual-track approach:
+we would make distributions which contained only a non-regulated
+password scrambler, and then provide as a separate add-on library the
+DES-based password hash. The password-scrambling function was moved
+out of the C library to a separate library, called `<tt>libcrypt</tt>'
+because the name of the C function to implement it is
+`<tt>crypt</tt>'. In FreeBSD 1.x and some pre-release 2.0 snapshots,
+the non-regulated scrambler uses an insecure function written by Nate
+Williams; in subsequent releases this was replaced by a mechanism
+using the RSA Data Security, Inc., MD5 one-way hash function. Because
+neither of these functions involve encryption, they are believed to be
+exportable from the US and importable into many other countries.
+
+<p>Meanwhile, work was also underway on the DES-based password hash
+function. First, a version of the `<tt>crypt</tt>' function which was
+written outside the US was imported, thus synchronizing the US and
+non-US code. Then, the library was modified and split into two; the
+DES `<tt>libcrypt</tt>' contains only the code involved in performing
+the one-way password hash, and a separate `<tt>libcipher</tt>' was
+created with the entry points to actually perform encryption. The
+code was partitioned in this way to make it easier to get an export
+license for the compiled library.
+
+<p><bf>Recognizing your `<tt>crypt</tt>' mechanism</bf>
+
+<p>It is fairly easy to recognize whether a particular password
+string was created using the DES- or MD5-based hash function.
+MD5 password strings always begin with the characters
+`<tt>&dollar;1&dollar;</tt>'. DES password strings do not have
+any particular identifying characteristics, but they are shorter
+than MD5 passwords, and are coded in a 64-character alphabet
+which does not include the `<tt>&dollar;</tt>' character, so a
+relatively short string which doesn't begin with a dollar sign is
+very likely a DES password.
+
+<p>Determining which library is being used on your system is fairly
+easy for most programs, except for those like `<tt>init</tt>' which
+are statically linked. (For those programs, the only way is to try
+them on a known password and see if it works.) Programs which use
+`<tt>crypt</tt>' are linked against `<tt>libcrypt</tt>', which for
+each type of library is a symbolic link to the appropriate
+implementation. For example, on a system using the DES versions:
+
+<tscreen><verb>
+$ cd /usr/lib
+$ ls -l /usr/lib/libcrypt*
+lrwxr-xr-x 1 bin bin 13 Sep 5 12:50 libcrypt.a -> libdescrypt.a
+lrwxr-xr-x 1 bin bin 18 Sep 5 12:50 libcrypt.so.2.0 -> libdescrypt.so.2.0
+lrwxr-xr-x 1 bin bin 15 Sep 5 12:50 libcrypt_p.a -> libdescrypt_p.a
+</verb></tscreen>
+
+On a system using the MD5-based libraries, the same links will be
+present, but the target will be `<tt>libscrypt</tt>' rather than
+`<tt>libdescrypt</tt>'.
diff --git a/share/doc/handbook/dma.sgml b/share/doc/handbook/dma.sgml
new file mode 100644
index 000000000000..a6628f42e9c1
--- /dev/null
+++ b/share/doc/handbook/dma.sgml
@@ -0,0 +1,105 @@
+<!-- $Id$ -->
+<!-- The FreeBSD Documentation Project -->
+
+<sect><heading>PC DMA<label id="dma"></heading>
+
+<p><em>Contributed by &a.uhclem;.<newline>
+ 31 August 1995.</em>
+
+Posted to <htmlurl url="mailto:hackers@freebsd.org"
+ name="freebsd-hackers@freebsd.org">:
+<quote>
+<p><em>Yes, as long as `single mode' is appropriate for you, there's no need
+to worry about TC. TC is intented for continuous mode. Well, i've
+just noticed that the PC DMAC cannot even generate an interrupt when
+ready... hmm, go figure, the Z80 DMAC did it.</em>
+<p><em>And yes, for `single mode', the masking trick will do it. The
+peripheral device will issue a DRQ signal for each transfered
+byte/word, and masking would prevent the DMAC from accepting new DRQs
+for this channel. Aborting a continuous mode transfer would not be so
+easy (or even impossible at all).</em>
+</quote>
+
+Actually, masking is the correct procedure for all transfer modes on the
+8237, even autoinit mode, which is frequently used for audio operations
+since it allows seamless DMA transfers with no under/overruns.
+
+You are generally correct about TC. All the TC signal does is
+when the counter on any channel in the DMA controller goes from
+one to zero, TC is asserted. What the peripherals are supposed
+to if they want to generate an interrupt when the transfer is
+through, is that peripheral device is supposed to look at
+<tt>(-DACK%d &amp;&amp; TC &amp;&amp; DEVICE_DMA_ACTIVE)</tt> and then
+latch an <tt>IRQ%d</tt> for the 8259 interrupt controller. Since there is
+only one TC signal, it is important that only the peripheral who
+is transferring data at that moment honor the TC signal.
+
+The host CPU will eventually investigate the interrupt by having some driver
+poll the hardware associated with the peripheral, NOT the DMA controller.
+If a peripheral doesn't want an interrupt associated with the DMA counter
+reaching zero, it doesn't implement the circuitry to monitor TC.
+
+Some sound cards realize that when the TC hits zero it means the DMA
+is now idle and that is really too late, so they don't use TC and
+instead allow the driver to program in a local counter value, which
+is usually set lower than the value programmed into the DMA. This means
+the peripheral can interrupt the CPU in advance of the DMA "running dry",
+allowing the CPU to be ready to reprogram the DMA the instant it finishes
+what it is doing, rather than incurring the latency later.
+
+This also means that two or more different devices could share a
+DMA channel, by tristating <tt>DRQ%d</tt> when idle and only
+honoring <tt>-DACK%d</tt> when the device knows it is expecting
+the DMA to go active. (Iomega PC2B boards forgot this minor
+point and will transfer data even if they are not supposed to.)
+
+
+So, if you want to abort a 8237 DMA transfer of any kind, simply mask the
+bit for that DMA channel in the 8237. Note: You can't interrupt an individual
+transfer (byte or burst) in progress. Think about it... if the DMA is
+running, how is your OUT instruction going to be performed?
+The CPU has to be bus master for the OUT to be performed.
+
+Since the 8237 DMA re-evaluates DMA channel priorities constantly, even if
+the DMA had already asserted HOLD (to request the bus from the CPU) when
+the OUT actually took place, the processor would still grant the bus to the
+DMA controller. The DMA controller would look for the highest-priority
+DMA source remaining (your interrupt is masked now) at that instant,
+and if none remained, the DMA will release HOLD and the processor will
+get the bus back after a few clocks.
+
+There is a deadly race condition in this area, but if I remember right,
+you can't get into it via mis-programming the DMA, UNLESS you cause the DMA
+controller to be RESET. You should not do this. Effectively the CPU
+can give up the bus and the DMA doesn't do anything, including giving the
+bus back. Very annoying and after 16msec or so, all is over since
+refresh on main memory has started failing.
+
+So, mask the DMA controller, then go do what you have to do to get the
+transfer aborted in the peripheral hardware. In some extremely stupid
+hardware (I could mention a few), you may have to program the DMA to
+transfer one more byte to a garbage target to get the peripheral hardware
+to go back to an idle state. Most hardware these days isn't that
+stupid.
+
+Technically, you are supposed to mask the DMA channel, program the other
+settings (direction, address, length, etc), issue commands to the
+peripheral and then unmask the DMA channel once the peripheral commands have
+been accepted. The last two steps can be done out of order without
+harm, but you must always program the DMA channel while it is masked to
+avoid spraying data all over the place in the event the peripheral
+unexpected asserts <tt>DRQ%d</tt>.
+
+If you need to pad-out an aborted buffer, once you have masked the
+DMA, you can ask it how many bytes it still had to go and what
+address it was to write to next. Your driver can then fill in the
+remaining area or do what needs to be done.
+
+
+Don't forget that the 8237 was designed for use with the 8085 and
+really isn't suited to the job that IBM gave it in the original PC.
+That's why the upper eight bits of DMA addressing appear to be lashed-on.
+They are. Look at the schematics of the original PC and you will
+the upper bits are kept in external latches that are enabled whenever
+the DMA is too. Very kludgy.
+
diff --git a/share/doc/handbook/esdi.sgml b/share/doc/handbook/esdi.sgml
new file mode 100644
index 000000000000..6d2c3dee5df4
--- /dev/null
+++ b/share/doc/handbook/esdi.sgml
@@ -0,0 +1,421 @@
+<!-- $Id: esdi.sgml,v 1.1 1995/09/25 04:53:30 jfieber Exp $ -->
+<!-- The FreeBSD Documentation Project -->
+
+<!--
+ <title>An introduction to ESDI hard disks and their use with FreeBSD</title>
+ <author>(c) 1995, Wilko Bulte, <tt/wilko@yedi.iaf.nl/
+ <date>Tue Sep 12 20:48:44 MET DST 1995</date>
+
+ Copyright 1995, Wilko C. Bulte, Arnhem, The Netherlands
+
+ <abstract>
+ This document describes the use of ESDI disks in combination
+ with the FreeBSD operating system. Contrary to popular
+ belief, this is possible and people are using ESDI based
+ systems succesfully! This document tries to explain you
+ how to do this.
+
+ If you find something missing, plain wrong or have useful
+ comments on how to improve
+ the document please send mail to <tt/wilko@yedi.iaf.nl/
+ </abstract>
+-->
+
+ <sect><heading>ESDI hard disks and FreeBSD<label id="esdi"></heading>
+
+ <p><em>Copyright &copy; 1995, &a.wilko;.<newline>24 September 1995.</em>
+
+ ESDI is an acronym that means Enhanced Small Device Interface.
+ It is loosely based on the good old ST506/412 interface originally
+ devised by Seagate Technology, the makers of the first affordable
+ 5.25" winchester disk.
+
+ The acronym says Enhanced, and rightly so. In the first place
+ the speed of the interface is higher, 10 or 15 Mbits/second
+ instead of the 5 Mbits/second of ST412 interfaced drives.
+ Secondly some higher level commands are added, making the ESDI
+ interface somewhat 'smarter' to the operating system driver
+ writers. It is by no means as smart as SCSI by the way. ESDI
+ is standardised by ANSI.
+
+ Capacities of the drives are boosted by putting more sectors
+ on each track. Typical is 35 sectors per track, high capacity
+ drives I've seen were up to 54 sectors/track.
+
+ Although ESDI has been largely obsoleted by IDE and SCSI interfaces,
+ the availability of free or cheap surplus drives makes them
+ ideal for low (or now) budget systems.
+
+ <sect1><heading>Concepts of ESDI</heading>
+ <p>
+ <sect2><heading>Physical connections</heading>
+ <p>
+ The ESDI interface uses two cables connected to each drive.
+ One cable is a 34 pin flatcable edge connector that carries
+ the command and status signals from the controller to the
+ drive and viceversa. The command cable is daisy chained
+ between all the drives. So, it forms a bus onto which all
+ drives are connected.
+
+ The second cable is a a 20 pin flatcable edge connector that
+ carries the data to and from the drive. This cable is radially
+ connected, so each drive has it's own direct connection to the
+ controller.
+
+ To the best of my knowledge PC ESDI controllers are limited
+ to using a maximum of 2 drives per controller. This is
+ compatibility feature(?) left over from the WD1003 standard
+ that reserves only a single bit for device addressing.
+
+ <sect2><heading>Device addressing</heading>
+ <p>
+ On each command cable a maximum of 7 devices and 1 controller
+ can be present. To enable the controller to uniquely
+ identify which drive it addresses, each ESDI device is equipped
+ with jumpers or switches to select the devices address.
+
+ On PC type controllers the first drive is set to address 0,
+ the second disk to address 1. <it>Always make sure</it> you
+ set each disk to an unique address! So, on a PC with it's
+ two drives/controller maximum the first drive is drive 0, the
+ second is drive 1.
+
+ <sect2><heading>Termination</heading>
+ <p>
+ The daisy chained command cable (the 34 pin cable remember?)
+ needs to be terminated at the last drive on the chain.
+ For this purpose ESDI drives come with a termination resistor
+ network that can be removed or disabled by a jumper when it
+ is not used.
+
+ So, one and <it>only</it> one drive, the one at
+ the fartest end of the command
+ cable has it's terminator installed/enabled. The controller
+ automatically terminates the other end of the cable.
+ Please note that this implies that the controller must be
+ at one end of the cable and <it>not</it> in the middle.
+
+ <sect1><heading>Using ESDI disks with FreeBSD</heading>
+ <p>
+ Why is ESDI such a pain to get working in the first place?
+
+ People who tried ESDI disks with FreeBSD are known to have
+ developed a profound sense of frustration. A combination of
+ factors works against you to produce effects that are
+ hard to understand when you have never seen them before.
+
+ This has also led to the popular legend ESDI and FreeBSD
+ is a plain NO-GO.
+ The following sections try to list all the pitfalls and
+ solutions.
+
+ <sect2><heading>ESDI speed variants</heading>
+ <p>
+ As briefly mentioned before, ESDI comes in two speed flavours.
+ The older drives and controllers use a 10 Mbits/second
+ data transfer rate. Newer stuff uses 15 Mbits/second.
+
+ It is not hard to imagine that 15 Mbits/second drive cause
+ problems on controllers laid out for 10 Mbits/second.
+ As always, consult your controller <it>and</it> drive
+ documentation to see if things match.
+
+ <sect2><heading>Stay on track</heading>
+ <p>
+ Mainstream ESDI drives use 34 to 36 sectors per track.
+ Most (older) controllers cannot handle more than this
+ number of sectors.
+ Newer, higher capacity, drives use higher numbers of sectors
+ per track. For instance, I own a 670 Mb drive that has
+ 54 sectors per track.
+
+ In my case, the controller could not handle this number
+ of sectors. It proved to work well except that it only
+ used 35 sectors on each track. This meant losing a
+ lot of diskspace.
+
+ Once again, check the documentation of your hardware for
+ more info. Going out-of-spec like in the example might
+ or might not work. Give it a try or get another more
+ capable controller.
+
+ <sect2><heading>Hard or soft sectoring</heading>
+ <p>
+ Most ESDI drives allow hard or soft sectoring to be
+ selected using a jumper. Hard sectoring means that the
+ drive will produce a sector pulse on the start of each
+ new sector. The controller uses this pulse to tell when
+ it should start to write or read.
+
+ Hard sectoring allows a selection of sector size (normally
+ 256, 512 or 1024 bytes per formatted sector). FreeBSD uses
+ 512 byte sectors. The number of sectors per track also varies
+ while still using the same number of bytes per formatted sector.
+ The number of <em>unformatted</em> bytes per sector varies,
+ dependent on your controller it needs more or less overhead
+ bytes to work correctly. Pushing more sectors on a track
+ of course gives you more usable space, but might give
+ problems if your controller needs more bytes than the
+ drive offers.
+
+ In case of soft sectoring, the controller itself determines
+ where to start/stop reading or writing. For ESDI
+ hard sectoring is the default (at least on everything
+ I came across). I never felt the urge to try soft sectoring.
+
+ In general, experiment with sector settings before you install
+ FreeBSD because you need to re-run the low-level format
+ after each change.
+
+ <sect2><heading>Low level formatting</heading>
+ <p>
+ ESDI drives need to be low level formatted before they
+ are usable. A reformat is needed whenever you figgle
+ with the number of sectors/track jumpers or the
+ physical orientation of the drive (horizontal, vertical).
+ So, first think, then format.
+ The format time must not be underestimated, for big
+ disks it can take hours.
+
+ After a low level format, a surface scan is done to
+ find and flag bad sectors. Most disks have a
+ manufacturer bad block list listed on a piece of paper
+ or adhesive sticker. In addition, on most disks the
+ list is also written onto the disk.
+ Please use the manufacturer's list. It is much easier
+ to remap a defect now than after FreeBSD is installed.
+
+ Stay away from low-level formatters that mark all
+ sectors of a track as bad as soon as they find one
+ bad sector. Not only does this waste space, it also
+ and more importantly causes you grief with bad144
+ (see the section on bad144).
+
+ <sect2><heading>Translations</heading>
+ <p>
+ Translations, although not exclusively a ESDI-only problem,
+ might give you real trouble.
+ Translations come in multiple flavours. Most of them
+ have in common that they attempt to work around the
+ limitations posed upon disk geometries by the original
+ IBM PC/AT design (thanks IBM!).
+
+ First of all there is the (in)famous 1024 cylinder limit.
+ For a system to be able to boot, the stuff (whatever
+ operating system) must be in the first 1024 cylinders
+ of a disk. Only 10 bits are available to encode the
+ cylinder number. For the number of sectors the limit
+ is 64 (0-63).
+ When you combine the 1024 cylinder limit with the 16 head
+ limit (also a design feature) you max out at fairly limited
+ disk sizes.
+
+ To work around this problem, the manufacturers of ESDI
+ PC controllers added a BIOS prom extension on their boards.
+ This BIOS extension handles disk I/O for booting (and for
+ some operating systems <it>all</it> disk I/O) by using
+ translation. For instance, a big drive might be presented
+ to the system as having 32 heads and 64 sectors/track.
+ The result is that the number of cylinders is reduced to
+ something below 1024 and is therefore usable by the system
+ without problems.
+ It is noteworthy to know that FreeBSD after it's kernel has
+ started no longer uses the BIOS. More on this later.
+
+ A second reason for translations is the fact that most
+ older system BIOSes could only handle drives with 17 sectors
+ per track (the old ST412 standard). Newer system BIOSes
+ usually have a user-defined drive type (in most cases this is
+ drive type 47).
+
+ <em>Whatever you do to translations after reading this document,
+ keep in mind that if you have multiple operating systems on the
+ same disk, all must use the same translation</em>
+
+ While on the subject of translations, I've seen one controller
+ type (but there are probably more like this) offer the option
+ to logically split a drive in multiple partitions as a BIOS
+ option. I had select 1 drive == 1 partition because this
+ controller wrote this info onto the disk. On powerup it
+ read the info and presented itself to the system based on
+ the info from the disk.
+
+ <sect2><heading>Spare sectoring</heading>
+ <p>
+ Most ESDI controllers offer the possibility to remap bad sectors.
+ During/after the low-level format of the disk bad sectors are
+ marked as such, and a replacement sector is put in place
+ (logically of course) of the bad one.
+
+ In most cases the remapping is done by using N-1 sectors on
+ each track for actual datastorage, and sector N itself is
+ the spare sector. N is the total number of sectors physically
+ available on the track.
+ The idea behind this is that the operating system sees
+ a 'perfect' disk without bad sectors. In the case of
+ FreeBSD this concept is not usable.
+
+ The problem is that the translation from <it>bad</it> to <it>good</it>
+ is performed by the BIOS of the ESDI controller. FreeBSD,
+ being a true 32 bit operating system, does not use the BIOS
+ after it has been booted. Instead, it has device drivers that
+ talk directly to the hardware.
+
+ <em>So: don't use spare sectoring, bad block remapping or
+ whatever it may be called by the controller manufacturer when you
+ want to use the disk for FreeBSD.</em>
+
+ <sect2><heading>Bad block handling</heading>
+ <p>
+ The preceding section leaves us with a problem. The controller's
+ bad block handling is not usable and still FreeBSD's filesystems
+ assume perfect media without any flaws.
+ To solve this problem, FreeBSD use the <it>bad144</it> tool.
+ Bad144 (named after a Digital Equipment standard for bad block
+ handling) scans a FreeBSD slice for bad blocks. Having found
+ these bad blocks, it writes a table with the offending block
+ numbers to the end of the FreeBSD slice.
+
+ When the disk is in operation, the diskaccesses are checked
+ against the table read from the disk. Whenever a blocknumber
+ is requested that is in the bad144 list, a replacement block
+ (also from the end of the FreeBSD slice) is used.
+ In this way, the bad144 replacement scheme presents 'perfect'
+ media to the FreeBSD filesystems.
+
+ There are a number of potential pitfalls associated with
+ the use of bad144.
+ First of all, the slice cannot have more than 126 bad sectors.
+ If your drive has a high number of bad sectors, you might need
+ to divide it into multiple FreeBSD slices each containing less
+ than 126 bad sectors. Stay away from low-level format programs
+ that mark <em>every</em> sector of a track as bad when
+ they find a flaw on the track. As you can imagine, the
+ 126 limit is quickly reached when the low-level format is done
+ this way.
+
+ Second, if the slice contains the root filesystem, the slice
+ should be within the 1024 cylinder BIOS limit. During the
+ boot process the bad144 list is read using the BIOS and this
+ only succeeds when the list is within the 1024 cylinder limit.
+ <em>Note</em> that the restriction is not that only the root
+ <em>filesystem</em> must be within the 1024 cylinder limit, but
+ rather the entire <em>slice</em> that contains the root filesystem.
+
+
+ <sect2><heading>Kernel configuration</heading>
+ <p>
+ ESDI disks are handled by the same <it>wd</it>driver as
+ IDE and ST412 MFM disks. The <it>wd</it> driver should work
+ for all WD1003 compatible interfaces.
+
+ Most hardware is jumperable for one of two different I/O
+ address ranges and IRQ lines. This allows you to have
+ two wd type controllers in one system.
+
+ When your hardware allows non-standard strappings, you
+ can use these with FreeBSD as long as you enter the
+ correct info into the kernel config file.
+ An example from the kernel config file (they live in
+ <tt>/sys/i386/conf</tt> BTW).
+
+<tscreen><verb>
+# First WD compatible controller
+controller wdc0 at isa? port "IO_WD1" bio irq 14 vector wdintr
+disk wd0 at wdc0 drive 0
+disk wd1 at wdc0 drive 1
+
+# Second WD compatible controller
+controller wdc1 at isa? port "IO_WD2" bio irq 15 vector wdintr
+disk wd2 at wdc1 drive 0
+disk wd3 at wdc1 drive 1
+</verb></tscreen>
+
+<!--
+ <sect2><heading>Tuning your ESDI kernel setup</heading>
+ <p>
+-->
+
+ <sect1><heading>Particulars on ESDI hardware</heading>
+ <p>
+ <sect2><heading>Adaptec 2320 controllers</heading>
+ <p>
+ I succesfully installed FreeBSD onto a ESDI disk controlled by a
+ ACB-2320. No other operating system was present on the disk.
+
+ To do so I low level formatted the disk using NEFMT.EXE
+ (<it>ftp</it>able from <it>www.adaptec.com</it>) and answered NO
+ to the question whether the disk should be formatted with a
+ spare sector on each track. The BIOS on the ACD-2320 was
+ disabled. I used the 'free configurable' option in the system
+ BIOS to allow the BIOS to boot it.
+
+ Before using NEFMT.EXE I tried to format the disk using the
+ ACB-2320 BIOS builtin formatter. This proved to be a showstopper,
+ because it didn't give me an option to disable spare sectoring.
+ With spare sectoring enabled the FreeBSD installation
+ process broke down on the bad144 run.
+
+ Please check carefully which ACB-232xy variant you have. The
+ x is either 0 or 2, indicating a controller without or with
+ a floppy controller on board.
+
+ The y is more interesting. It can either be a blank,
+ a "A-8" or a "D". A blank indicates a plain 10 Mbits/second
+ controller. An "A-8" indicates a 15 Mbits/second controller
+ capable of handling 52 sectors/track.
+ A "D" means a 15 Mbits/second controller that can also
+ handle drives with > 36 sectors/track (also 52 ?).
+
+ All variations should be capable of using 1:1 interleaving. Use 1:1,
+ FreeBSD is fast enough to handle it.
+
+ <sect2><heading>Western Digital WD1007 controllers</heading>
+ <p>
+ I succesfully installed FreeBSD onto a ESDI disk controlled by a
+ WD1007 controller. To be precise, it was a WD1007-WA2. Other
+ variations of the WD1007 do exist.
+
+ To get it to work, I had to disable the sector translation and
+ the WD1007's onboard BIOS. This implied I could not use
+ the low-level formatter built into this BIOS. Instead, I grabbed
+ WDFMT.EXE from www.wdc.com Running this formatted my drive
+ just fine.
+
+ <sect2><heading>Ultrastor U14F controllers</heading>
+ <p>
+ According to multiple reports from the net, Ultrastor ESDI
+ boards work OK with FreeBSD. I lack any further info on
+ particular settings.
+
+<!--
+
+ <sect1><heading>Tracking down problems</heading>
+ <p>
+-->
+
+ <sect1><heading>Further reading<label id="esdi:further-reading"></>
+ <p>
+ If you intend to do some serious ESDI hacking, you might want to
+ have the official standard at hand:
+
+ The latest ANSI X3T10 committee document is:
+ <itemize>
+<item>Enhanced Small Device Interface (ESDI) &lsqb;X3.170-1990/X3.170a-1991&rsqb;
+ &lsqb;X3T10/792D Rev 11&rsqb;
+ </itemize>
+ On Usenet the newsgroup <htmlurl url="news:comp.periphs"
+ name="comp.periphs"> is a noteworthy place to look
+ for more info.
+
+ The World Wide Web (WWW) also proves to be a very handy info source:
+ For info on Adaptec ESDI controllers see <htmlurl
+ url="http://www.adaptec.com/">.
+ For info on Western Digital controllers see <htmlurl
+ url="http://www.wdc.com/">.
+
+ <sect1>Thanks to...
+ <p>
+ Andrew Gordon for sending me an Adaptec 2320 controller and ESDI disk
+ for testing.
+
diff --git a/share/doc/handbook/firewalls.sgml b/share/doc/handbook/firewalls.sgml
new file mode 100644
index 000000000000..6a63a53bf853
--- /dev/null
+++ b/share/doc/handbook/firewalls.sgml
@@ -0,0 +1,525 @@
+<!-- $Id$ -->
+<!-- The FreeBSD Documentation Project -->
+
+<sect><heading>Firewalls<label id="firewalls"></heading>
+
+<p><em>Contributed by &a.gpalmer;.<newline>4th of October 1995</em>
+
+Firewalls are an area of increasing interest for people who are
+connected to the Internet, and are even finding applications on
+private networks to provide enhanced security. This section will
+hopefully explain what firewalls are, how to use them, and how to use
+the facilities provided in the FreeBSD kernel to impliment them.
+
+<quote><bf>Note</bf>: People often think that having a firewall between
+your companies internal network and the ``Big Bad Internet'' will
+solve all your security problems. It may help, but a poorly setup
+firewall system is more of a security risk than not having one at all.
+A firewall can only add another layer of security to your systems, but
+they will not be able to stop a really determined hacker from
+penetrating your internal network. If you let internal security lapse
+because you believe your firewall to be impenetrable, you have just
+made the hackers job that bit easier.</quote>
+
+<sect1><heading>What is a firewall?</heading>
+
+<p>There are currently two distinct types of firewalls in common
+use on the Internet today. The first type is more properly called
+a <bf>packet filtering router</bf>, where the kernel on a
+multi-homed machine chooses whether to forward or block packets
+based on a set of rules. The second type, known as <bf>proxy
+servers</bf>, rely on daemons to provide authentication and to
+forward packets, possibly on a multi-homed machine which has
+kernel packet forwarding disabled.
+
+<p>Sometimes sites combine the two types of firewalls, so that only a
+certain machine (known as a <bf>bastion host</bf>) is allowed to send
+packets through a packet filtering router onto an internal
+network. Proxy services are run on the bastion host, which are
+generally more secure than normal authentication mechanisms.
+
+<p>FreeBSD comes with a kernel packet filter (known as <tt>IPFW</tt>),
+which is what the rest of this section will concentrate on. Proxy
+servers can be built on FreeBSD from third party software, but there
+is such a vareity of proxy servers available that it would be
+impossible to cover them in this document.
+
+<sect2><heading>Packet filtering routers<label id="firewalls:packet_filters"></heading>
+
+<p>A router is a machine which forwards packets between two or more
+networks. A packet filtering router has an extra piece of code in it's
+kernel, which compares each packet to a list of rules before deciding
+if it should be forwarded or not. Most modern IP routing software has
+packet filtering code in it, which defaults to forwarding all
+packets. To enable the filters, you need to define a set of rules for
+the filtering code, so that it can decide if the packet should be
+allowed to pass or not.
+
+<p>To decide if a packet should be passed on or not, the code looks
+through it's set of rules for a rule which matches the contents of
+this packets headers. Once a match is found, the rule action is
+obeyed. The rule action could be to drop the packet, to forward the
+packet, or even to send an ICMP message back to the originator. Only
+the first match counts, as the rules are searched in order. Hence, the
+list of rules can be referred to as a ``rule chain''.
+
+<p>The packet matching criteria varies depending on the software used,
+but typically you can specify rules which depend on the source IP
+address of the packet, the destination IP address, the source port
+number, the destination port number (for protocols which support
+ports), or even the packet type (UDP, TCP, ICMP, etc).
+
+<sect2><heading>Proxy servers<label id="firewalls:proxy_servers"></heading>
+
+<p>Proxy servers are machines which have had the normal system daemons
+(telnetd, ftpd, etc) replaced with special servers. These servers are
+called <bf>proxy servers</bf> as they normally only allow onward
+connections to be made. This enables you to run (for example) a proxy
+telnet server on your firewall host, and people can telnet in to your
+firewall from the outside, go through some authentication mechanism,
+and then gain access to the internal network (alternatively, proxy
+servers can be used for signals coming from the internal network and
+heading out).
+
+<p>Proxy servers are normally more secure than normal servers, and
+often have a wider variety of authentication mechanisms available,
+including ``one-shot'' password systems so that even if someone
+manages to discover what password you used, they will not be able to use
+it to gain access to your systems as the password instantly
+expires. As they do not actually give users access to the host machine,
+it becomes a lot more difficult for someone to install backdoors
+around your security system.
+
+<p>Proxy servers often have ways of restricting access further, so
+that only certain hosts can gain access to the servers, and often they
+can be set up so that you can limit which users can talk to which
+destination machine. Again, what facilities are available depends
+largely on what proxy software you choose.
+
+<sect1><heading>What does <tt>IPFW</tt> allow me to do?</heading>
+
+<p><tt>IPFW</tt>, the software supplied with FreeBSD, is a packet
+filtering and accounting system which resides in the kernel, and has a
+user-land control utility, <tt>ipfw(8)</tt>. Together, they
+allow you to define and query the rules currently used by the kernel
+in its routing decisions.
+
+<p>There are two related parts to <tt>IPFW</tt>. The firewall section
+allows you to perform packet filtering. There is also an IP accounting
+section which allows you to track usage of your router, based on
+similar rules to the firewall section. This allows you to see (for
+example) how much traffic your router is getting from a certain
+machine, or how much WWW (World Wide Web) traffic it is forwarding.
+
+<p>As a result of the way that <tt>IPFW</tt> is designed, you can use
+<tt>IPFW</tt> on non-router machines to perform packet filtering on
+incoming and outgoing connections. This is a special case of the more
+general use of <tt>IPFW</tt>, and the same commands and techniques
+should be used in this situation.
+
+<sect1><heading>Enabling <tt>IPFW</tt> on FreeBSD</heading>
+
+<p>As the main part of the <tt>IPFW</tt> system lives in the kernel, you will
+need to add one or more options to your kernel configuration
+file, depending on what facilities you want, and recompile your kernel. See
+<ref id="kernelconfig" name="reconfiguring the kernel"> for more
+details on how to recompile your kernel.
+
+<p>There are currently three kernel configuration options
+relevant to IPFW:
+
+<descrip>
+<tag/options IPFIREWALL/ Compiles into the kernel the code for packet
+filtering.
+
+<tag/options IPFIREWALL_VERBOSE/ Enables code to allow logging of
+packets through <tt>syslogd</tt>. Without this option, even if you
+specify that packets should be logged in the filter rules, nothing
+will happen.
+
+<tag/options IPACCT/ Turns on the IP accounting facilities.
+
+</descrip>
+
+<sect1><heading>Configuring <tt>IPFW</tt></heading>
+
+<p>The configuration of the <tt>IPFW</tt> software is done through the
+<tt>ipfw(8)</tt> utility. The syntax for this command looks
+quite complicated, but it is relatively simple once you understand
+it's structure.
+
+<p>There are currently two different command line formats for the
+utility, depending on what you are doing. The first form is used when
+adding/deleting entries from the firewall or accounting chains, or
+when clearing the counters for an entry on the accounting chain. The
+second form is used for more general actions, such as flushing the
+rule chains, listing the rule chains or setting the default policy.
+
+<sect2><heading>Altering the <tt>IPFW</tt> rules</heading>
+
+<p>The syntax for this form of the command is:
+<tscreen>
+ipfw [-n] <em>command</em> <em>action</em> <em>protocol</em> <em>addresses</em>
+</tscreen>
+
+<p>There is one valid flag when using this form of the command:
+
+<descrip>
+<tag/-n/Do not attempt to resolve given addresses.
+</descrip>
+
+The <em>command</em> given can be shortened to the shortest unique
+form. The valid <em>commands</em> are:
+
+<descrip>
+
+<tag/addfirewall/Add an entry to the firewall rule list
+
+<tag/delfirewall/Delete an entry from the firewall rule list
+
+<tag/addaccounting/Add an entry to the accounting rule list
+
+<tag/delaccounting/Delete an entry from the accounting rule list
+
+<tag/clraccounting/Clear the counters for an accounting rule entry.
+
+</descrip>
+
+If no command is given, it will default <bf>addfirewall</bf> or
+<bf>addaccounting</bf> depending on the arguments given.
+
+<p>Currently, the firewall support in the kernel applies a set of
+weights to the rule being added. This means that the rules will
+<em>not</em> be evaluated in the order that they are given to the
+system. The weighting system is designed so that rules which are very
+specific are evaluated first, and rules which cover very large ranges
+are evaluated last. In other words, a rule which applies to a specific
+port on a specific host will have a higher priority than a rule which
+applies to that same port, but on a range of hosts, or that host on a
+range of ports.
+
+<p>The weighting system is not perfect, however, and can lead to
+problems. The best way to see what order it has put your rules in is
+to use the <bf>list</bf> command, as that command lists the rules in
+the order that they are evaluated, not the order that they were fed to
+the system.
+
+<p>The <em>actions</em> available depend on which rule chain the
+entry is destined for. For the firewall chain, valid
+<em>actions</em> are:
+
+<descrip>
+
+<tag/reject/Drop the packet, and send an ICMP HOST_UNREACHABLE packet
+to the source.
+
+<tag/lreject/As <bf>reject</bf>, but also log the packet details.
+
+<tag/deny/Drop the packet.
+
+<tag/ldeny/As <bf>deny</bf>, but also log the packet details.
+
+<tag/log/Log the packets details and pass it on as normal.
+
+<tag/accept/Pass the packet on as normal.
+
+<tag/pass/Synonym for <bf>accept</bf>.
+
+</descrip>
+
+For the accounting chain, valid <em>actions</em> are:
+
+<descrip>
+
+<tag/single/Count packets matching the address specifier.
+
+<tag/bidirectional/Count packets matching the address specifier, and
+also packets travelling in the opposite direction (i.e. those going
+from ``destination'' to ``source'').
+
+</descrip>
+
+<p>Each <em>action</em> will be recognized by the shortest unambigious
+prefix.
+
+The <em>protocols</em> which can be specified are:
+
+<descrip>
+
+<tag/all/Matches any IP packet
+
+<tag/icmp/Matches ICMP packets
+
+<tag/tcp/Matches TCP packets
+
+<tag/udp/Matches UDP packets
+
+<tag/syn/Matches the TCP SYN (synchronization) packet used during TCP
+connection negotiation. You can use this to block ``incoming'' TCP
+connections, but allow ``outgoing'' TCP connections.
+</descrip>
+
+<p>The <em>address</em> specification is:
+<tscreen>
+&lsqb;<bf>from</bf> &lt;<em>address/mask</em>&gt;&lsqb;<em>port</em>&rsqb;&rsqb; &lsqb;<bf>to</bf>
+ &lt;<em>address/mask</em>&gt;&lsqb;<em>port</em>&rsqb;&rsqb; &lsqb;<bf>via</bf> &lt;<em>interface</em>&gt;&rsqb;
+</tscreen>
+
+<p>You can only specify <em>port</em> in conjunction with
+<em>protocols</em> which support ports (UDP, TCP and SYN).
+
+<p>The order of the <bf>from</bf>, <bf>to</bf>, and
+<bf>via</bf> keywords is unimportant. Any of them can be omitted,
+in which case a default entry for that keyword will be supplied which
+matches everything.
+
+<p>The <bf>via</bf> is optional and may specify the IP address or
+domain name of a local IP interface, or an interface name (e.g.
+<tt>ed0</tt>) to match only packets coming through this interface. The
+keyword <bf>via</bf> can be substituted by <bf>on</bf>, for
+readability reasons.
+
+<p>The syntax used to specify an <tt>&lt;address/mask&gt;</tt> is:
+<tscreen>
+&lt;address&gt;
+</tscreen>
+or
+<tscreen>
+&lt;address&gt;/mask-bits
+</tscreen>
+or
+<tscreen>
+&lt;address&gt;:mask-pattern
+</tscreen>
+
+<p>A valid hostname may be specified in place of the IP
+address. <tt>mask-bits</tt> is a decimal number representing how many
+bits in the address mask should be set. e.g. specifying
+<tscreen>
+192.216.222.1/24
+</tscreen>
+will create a mask which will allow any address in a class C subnet
+(in this case, 192.216.222) to be matched. <tt>mask-pattern</tt> is an IP
+address which will be logically AND'ed with the address given. The
+keyword <tt>any</tt> may be used to specify ``any IP address''.
+<p>The port numbers to be blocked are specified as:
+<tscreen>
+port&lsqb;,port&lsqb;,port&lsqb;...&rsqb;&rsqb;&rsqb;
+</tscreen>
+to specify either a single port or a list of ports, or
+<tscreen><verb>
+port:port
+</verb></tscreen>
+to specify a range of ports. The name of a service (from
+<em>/etc/services</em>) can be used instead of a numeric port value.
+
+<sect2><heading>Listing/flushing the <tt>IPFW</tt> rules</heading>
+
+<p>The syntax for this form of the command is:
+<tscreen>
+ipfw &lsqb;-ans&rsqb; <em>command</em> &lsqb;<em>argument</em>&rsqb;
+</tscreen>
+
+<p>There are three valid flags when using this form of the command:
+
+<descrip>
+
+<tag/-a/While listing, show counter values. This option is the only
+way to see accounting counters. Works only with <bf>-s</bf>.
+
+<tag/-n/Do not attempt to resolve given addresses.
+
+<tag/-s/Use short listing form. This should be used with <bf>-a</bf>
+to see accounting counters. The short form listing is incompatible
+with the input syntax used by the <tt>ipfw(8)</tt> utility.
+
+</descrip>
+
+The <em>command</em> given can be shortened to the shortest unique
+form. The valid <em>commands</em> are:
+
+<descrip>
+
+<tag/list/List the chain rule entries. Unless the <bf>-s</bf> flag is
+given, the format is compatable with the command line syntax.
+
+<tag/flush/Flush the chain rule entries.
+
+<tag/zero/Clear counters for the entire accounting chain.
+
+<tag/policy/Set or display the default policy for the firewall
+code. Without an argument, the current policy will be displayed.
+
+</descrip>
+
+The <bf>list</bf> and <bf>flush</bf> commands may optionally be passed
+an <em>argument</em> to specify which chain to flush. Valid arguments are:
+
+<descrip>
+
+<tag/firewall/The packet filter chain.
+
+<tag/accounting/The accounting chain.
+
+</descrip>
+
+<p>The <bf>policy</bf> command can be given one of two arguments:
+
+<descrip>
+
+<tag/accept/If a packet is not matched by any rule, pass it on.
+
+<tag/deny/If a packet is not matched by any rule, do not pass it on.
+
+</descrip>
+
+As usual, the arguments can be shortened to the shortest unique form
+(in this case, the first letter).
+
+<sect1><heading>Example commands for ipfw</heading>
+
+<p>This command will deny all packets from the host
+<bf>evil.hacker.org</bf> to the telnet port of the host
+<bf>nice.people.org</bf> by being forwarded by the router:
+
+<tscreen><verb>
+ipfw addf deny tcp from evil.hacker.org to nice.people.org telnet
+</verb></tscreen>
+
+<p>The next example denies and logs any TCP traffic from the entire
+<bf>hacker.org</bf> network (a class C) to the <bf>nice.people.org</bf>
+machine (any port).
+
+<tscreen><verb>
+ipfw addf ldeny tcp from evil.hacker.org/24 to nice.people.org
+</verb></tscreen>
+
+If you do not want people sending X sessions to your internal network
+(a subnet of a class C), the following command will do the necessary
+filtering:
+
+<tscreen><verb>
+ipfw addf deny syn to my.org/28 6000
+</verb></tscreen>
+
+To allow access to the SUP server on <bf>sup.FreeBSD.ORG</bf>, use the
+following command:
+
+<tscreen><verb>
+ipfw addf accept syn to sup.FreeBSD.ORG supfilesrv
+</verb></tscreen>
+
+To see the accounting records:
+<tscreen><verb>
+ipfw -sa list accounting
+</verb></tscreen>
+or in the short form
+<tscreen><verb>
+ipfw -sa l a
+</verb></tscreen>
+
+<sect1><heading>Building a packet filtering firewall</heading>
+
+<p><quote><bf>Note:</bf> The following suggestions are just that:
+suggestions. The requirements of each firewall are different and I
+cannot tell you how to build a firewall to meet your particular
+requirements.</quote>
+
+<p>When initially setting up your firewall, unless you have a test
+bench setup where you can configure your firewall host in a controlled
+environment, I strongly recommend you use the logging version of the
+commands and enable logging in the kernel. This will allow you to
+quickly identify problem areas and cure them without too much
+disruption. Even after the initial setup phase is complete, I
+recommend using the logging for of `deny' as it allows tracing of
+possible attacks and also modification of the firewall rules if your
+requirements alter.
+
+<quote><bf>Note:</BF> If you use the logging versions of the
+<bf>accept</bf> command, it can generate <em>large</em> ammounts
+of log data as one log line will be generated for every packet
+that passes through the firewall, so large ftp/http transfers,
+etc, will really slow the system down. It also increases the
+latencies on those packets as it requires more work to be done by
+the kernel before the packet can be passed on. syslogd with also
+start using up a lot more processor time as it logs all the extra
+data to disk, and it could quite easily fill the partition
+<tt>/var/log</tt> is located on.</quote>
+
+<p>As currently supplied, FreeBSD does not have the ability to
+load firewall rules at boot time. My suggestion is to put a call
+to a shell script in the <tt>/etc/netstart</tt> script. Put the
+call early enough in the netstart file so that the firewall is
+configured before any of the IP interfaces are configured. This
+means that there is no window during which time your network is
+open.
+
+<p>The actual script used to load the rules is entirely up to
+you. There is currently no support in the <tt>ipfw</tt> utility for
+loading multiple rules in the one command. The system I use is to use
+the command:
+
+<tscreen><verb>
+# ipfw list
+</verb></tscreen>
+
+to write a list of the current rules out to a file, and then use a
+text editor to prepend ``<tt>ipfw </tt>'' before all the lines. This
+will allow the script to be fed into /bin/sh and reload the rules into
+the kernel. Perhaps not the most efficient way, but it works.
+
+<p>The next problem is what your firewall should actually <bf>DO</bf>!
+This is largely dependant on what access to your network you want to
+allow from the outside, and how much access to the outside world you
+want to allow from the inside. Some general rules are:
+
+<itemize>
+
+ <item>Block all incoming access to ports below 1000 for TCP. This is
+where most of the security sensitive services are, like finger, smtp
+(mail) and telnet.
+
+ <item>Block incoming SYN connections to ports between 1001 and 1024
+(this will allow internal users to rsh/rlogin to the outside). If you
+do not want to allow rsh/rlogin connections from the inside to the
+outside, then extend the above suggestion to cover ports 1-1024.
+
+ <item>Block <bf>all</bf> incoming UDP traffic. There are very few
+useful services that travel over UDP, and what useful traffic there is
+is normally a security threat (e.g. Suns RPC and NFS protocols). This
+has its disadvantages also, since UDP is a connectionless protocol,
+denying incoming UDP traffic also blocks the replies to outoing UDP
+traffic. This can cause a problem for people (on the inside)
+using external archie (prospero) servers. If you want to allow access
+to archie, you'll have to allow packets coming from ports 191 and 1525
+to any internal UDP port through the firewall. ntp is another service
+you may consider allowing through, which comes from port 123.
+
+ <item>Block traffic to port 6000 from the outside. Port 6000 is the
+port used for access to X11 servers, and can be a security threat
+(especially if people are in the habbit of doing <tt>xhost +</tt> on
+their workstations). X11 can actually use a range of ports starting at
+6000, the upper limit being how many X displays you can run on the
+machine. The upper limit as defined by RFC 1700 (Assigned Numbers) is
+6063.
+
+ <item>Check what ports any internal servers use (e.g. SQL servers,
+etc). It's probably a good idea to block those as well, as they
+normally fall outside the 1-1024 range specified above.
+
+</itemize>
+
+<p>Of course, if you want to make sure that no un-authorised traffic
+gets through the firewall, change the default policy to ``deny''. This
+will mean that any traffic which is allowed through has to be
+specified explicitly in an ``accept'' or ``allow'' filter rule. Which
+ports you allow through is again something that you will have to
+decide for yourself. If you do set the default policy to be deny, you
+will probably want to install proxy servers, as no traffic will be
+able to get OUT either unless you allow TCP SYN connections going form
+the inside out.
+
+<p>As I said above, these are only <em>guidelines</em>. You will have
+to decide what filter rules you want to use on your firewall
+yourself. I cannot accept ANY responsibility if someone breaks into
+your network, even if you follow the advice given above.
diff --git a/share/doc/handbook/kernelconfig.sgml b/share/doc/handbook/kernelconfig.sgml
new file mode 100644
index 000000000000..bb8cc08f13de
--- /dev/null
+++ b/share/doc/handbook/kernelconfig.sgml
@@ -0,0 +1,1206 @@
+<!-- $Id: kernelconfig.sgml,v 0.99 1995/10/05 20:14:15 jehamby Exp $ -->
+<!-- The FreeBSD Documentation Project -->
+<!-- <!DOCTYPE linuxdoc PUBLIC '-//FreeBSD//DTD linuxdoc//EN'> -->
+ <chapt><heading>Configuring the FreeBSD Kernel<label id="kernelconfig"></heading>
+
+ <p><em>Contributed by &a.jehamby;.<newline>6 October 1995.</em>
+
+ This large section of the handbook discusses the basics of
+ building your own custom kernel for FreeBSD. This section
+ is appropriate for both novice system administrators and
+ those with advanced Unix experience.
+
+ <sect><heading>Why build a custom kernel?</heading>
+
+ <p>Building a custom kernel is one of the most important
+ rites of passage every Unix system administrator must
+ learn. This process, while time-consuming, will provide
+ many benefits to your FreeBSD system. Unlike the GENERIC
+ kernel, which must support every possible SCSI and
+ network card, along with tons of other rarely used
+ hardware support, a custom kernel only contains support
+ for <em>your</em> PC's hardware. This has a number of
+ benefits:
+
+ <itemize>
+
+ <item>It will take less time to boot because it does not
+ have to spend time probing for hardware which you
+ do not have.
+
+ <item>A custom kernel often uses less memory, which is
+ important because the kernel is the one process which
+ must always be present in memory, and so all of that
+ unused code ties up pages of RAM that your programs
+ would otherwise be able to use. Therefore, on a
+ system with limited RAM, building a custom kernel is
+ of critical importance.
+
+ <item>Finally, there are several kernel options which
+ you can tune to fit your needs, and device driver
+ support for things like sound cards which you can
+ include in your kernel but are <em>not</em> present
+ in the GENERIC kernel.
+
+ </itemize></p>
+
+ <sect><heading>Building and Installing a Custom Kernel</heading>
+
+ <p>First, let us take a quick tour of the kernel build
+ directory. All directories mentioned will be relative to
+ the main <tt>/usr/src/sys</tt> directory, which is also
+ accessible through <tt>/sys</tt>. There are a number of
+ subdirectories here representing different parts of the
+ kernel, but the most important, for our purposes, are
+ <tt>i386/conf</tt>, where you will edit your custom
+ kernel configuration, and <tt>compile</tt>, which is the
+ staging area where your kernel will be built. Notice the
+ logical organization of the directory tree, with each
+ supported device, filesystem, and option in its own
+ subdirectory. Also, anything inside the <tt>i386</tt>
+ directory deals with PC hardware only, while everything
+ outside the <tt>i386</tt> directory is common to all
+ platforms which FreeBSD could potentially be ported to.
+
+ <quote><em/Note:/ If there is <em>not</em> a
+ <tt>/usr/src/sys</tt> directory on your system, then the
+ kernel source has not been been installed. Follow the
+ instructions for installing packages to add this package
+ to your system.</quote>
+
+ Next, move to the <tt>i386/conf</tt> directory and copy
+ the GENERIC configuration file to the name you want to
+ give your kernel. For example:
+<tscreen><verb>
+# cd /usr/src/sys/i386/conf
+# cp GENERIC MYKERNEL
+</verb></tscreen>
+ Traditionally, this name is in all capital letters and,
+ if you are maintaining multiple FreeBSD machines with
+ different hardware, it's a good idea to name it after
+ your machine's hostname. We will call it MYKERNEL for
+ the purpose of this example.
+
+ <quote><em/Note:/ You must execute these and all of the
+ following commands under the root account or you will get
+ ``permission denied'' errors.</quote>
+
+ Now, edit MYKERNEL with your favorite text editor. If
+ you're just starting out, the only editor available will
+ probably be <tt>vi</tt>, which is too complex to explain
+ here, but is covered well in many books in the <ref
+ id="bibliography" name="bibliography">. Feel free to change the comment
+ lines at the top to reflect your configuration or the
+ changes you've made to differentiate it from GENERIC.
+
+ If you've build a kernel under SunOS or some other BSD
+ operating system, much of this file will be very familiar
+ to you. If you're coming from some other operating
+ system such as DOS, on the other hand, the GENERIC
+ configuration file might seem overwhelming to you, so
+ follow the descriptions in the <ref
+ id="kernelconfig:config" name="Configuration File">
+ section slowly and carefully.
+
+ When you're finished, type the following to compile and
+ install your kernel:
+<tscreen><verb>
+# /usr/sbin/config MYKERNEL
+# cd ../../compile/MYKERNEL
+# make
+# make install
+</verb></tscreen>
+ The new kernel will be copied to the root directory as
+ <tt>/kernel</tt> and the old kernel will be moved to
+ <tt>/kernel.old</tt>. Now, shutdown the system and
+ reboot to use your kernel. In case something goes wrong,
+ there are some <ref id="kernelconfig:trouble" name=
+ "troubleshooting"> instructions at the end of this
+ document. Be sure to read the section which explains how
+ to recover in case your new kernel <ref
+ id="kernelconfig:noboot" name="does not boot">.
+
+ <quote><em/Note:/ If you've added any new devices (such
+ as sound cards) you may have to add some <ref
+ id="kernelconfig:nodes" name="device nodes"> to your
+ <tt>/dev</tt> directory before you can use them.</quote>
+
+ <sect><heading>The Configuration File<label id="kernelconfig:config"></heading>
+
+ <p>The general format of a configuration file is quite
+ simple. Each line contains a keyword and one or more
+ arguments. For simplicity, most lines only contain one
+ argument. Anything following a <tt>#</tt> is considered
+ a comment and ignored. The following sections describe
+ each keyword, generally in the order they are listed in
+ GENERIC, although some related keywords have been grouped
+ together in a single section (such as Networking) even
+ though they are actually scattered throughout the GENERIC
+ file. An exhaustive list of options is present in the
+ LINT configuration file, located in the same directory as
+ GENERIC.
+
+ <sect1><heading>Mandatory Keywords</heading>
+
+ <p>These keywords are required in every kernel you build.
+
+ <descrip>
+
+ <tag>machine ``i386''</tag>
+
+ <p>The first keyword is <tt>machine</tt>, which,
+ since FreeBSD only runs on Intel 386 and compatible
+ chips, is i386.
+
+ <quote><em>Note:</em> that any keyword which
+ contains numbers used as text must be enclosed in
+ quotation marks, otherwise <tt>config</tt> gets
+ confused and thinks you mean the actual number
+ 386.</quote>
+
+ <tag>cpu ``<em>cpu_type</em>''</tag>
+
+ <p>The next keyword is <tt>cpu</tt>, which includes
+ support for each CPU supported by FreeBSD. The
+ possible values of <tt><em>cpu_type</em></tt>
+ include:
+ <itemize>
+ <item>I386_CPU
+ <item>I486_CPU
+ <item>I586_CPU
+ </itemize>
+ and multiple instances of the <tt>cpu</tt> line may
+ be present with different values of
+ <tt><em>cpu_type</em></tt> as are present in the
+ GENERIC kernel. For a custom kernel, it is best to
+ specify only the cpu you have. If, for example,
+ you have an Intel Pentium, use <tt>I586_CPU</tt>
+ for <tt><em>cpu_type</em></tt>.
+
+ <tag>ident <em>machine_name</em></tag>
+
+ <p>Next, we have <tt>ident</tt>, which is the
+ identification of the kernel. You should change
+ this from GENERIC to whatever you named your
+ kernel, in this example, MYKERNEL. The value you
+ put in <tt>ident</tt> will print when you boot up
+ the kernel, so it's useful to give a kernel a
+ different name if you want to keep it separate from
+ your usual kernel (if you want to build an
+ experimental kernel, for example). Note that, as
+ with <tt>machine</tt> and <tt> cpu</tt>, enclose
+ your kernel's name in quotation marks if it
+ contains any numbers.
+
+ <tag>maxusers <em>number</em></tag>
+
+ <p>This file sets the size of a number of important
+ system tables. This number is supposed to be
+ roughly equal to the number of simultaneous users
+ you expect to have on your machine. However, under
+ normal circumstances, you will want to set
+ <tt>maxusers</tt> to at least four, especially if
+ you're using X Windows or compiling software. The
+ reason is that the most important table set by
+ <tt>maxusers</tt> is the maximum number of
+ processes, which is set to <bf><tt>20 + 16 *
+ maxusers</tt></bf>, so if you set <tt>maxusers</tt>
+ to one, then you can only have 36 simultaneous
+ processes, including the 18 or so that the system
+ starts up at boot time, and the 15 or so you will
+ probably create when you start X Windows. Even a
+ simple task like reading a <tt>man</tt> page will
+ start up nine processes to filter, decompress, and
+ view it. Setting <tt>maxusers</tt> to 4 will allow
+ you to have up to 84 simultaneous processes, which
+ should be enough for anyone. If, however, you see
+ the dreaded ``proc table full'' error when trying
+ to start another program, or are running a server
+ with a large number of simultaneous users (like
+ Walnut Creek CDROM's FTP site!), you can always
+ increase this number and rebuild.
+
+ <quote><em/Note:/ <tt>maxuser</tt> does
+ <em>not</em> limit the number of users which can
+ log into your machine. It simply sets various
+ table sizes to reasonable values considering the
+ maximum number of users you will likely have on
+ your system and how many processes each of them
+ will be running. One keyword which
+ <em>does</em> limit the number of simultaneous
+ <em>remote logins</em> is <ref
+ id="kernelconfig:ptys" name="pseudo-device pty
+ 16">.</quote>
+
+ <tag>config <em>kernel_name</em> root on <em>root_device</em></tag>
+
+ <p>This line specifies the location and name of the
+ kernel. Traditionally the kernel is called
+ <tt>vmunix</tt> but in FreeBSD, it is aptly named
+ <tt>kernel</tt>. You should always use
+ <tt>kernel</tt> for <em>kernel_name</em> because
+ changing it will render numerous system utilities
+ inoperative. The second part of the line specifies
+ the disk and partition where the root filesystem
+ and kernel can be found. Typically this will be
+ <tt>wd0</tt> for systems with non-SCSI drives, or
+ <tt>sd0</tt> for systems with SCSI drives.
+
+ </descrip>
+
+ <sect1><heading>General Options</heading>
+
+ <p>These lines provide kernel support for various
+ filesystems and other options.
+
+ <descrip>
+
+ <label id="kernelconfig:mathemu">
+
+ <tag>options MATH_EMULATE</tag>
+
+ <p>This line allows the kernel to simulate a math
+ coprocessor if your computer does not have one (386
+ or 486SX). If you have a Pentium, a 486DX, or a
+ 386 or 486SX with a separate 387 or 487 chip, you
+ can comment this line out.
+
+ <quote><em>Note:</em> The normal math coprocessor
+ emulation routines that come with FreeBSD are
+ <em>not</em> very accurate. If you do not have a
+ math coprocessor, and you need the best accuracy,
+ I recommend that you change this option to
+ <tt>GPL_MATH_EMULATE</tt> to use the superior GNU
+ math support, which is not included by default
+ for licensing reasons.</quote>
+
+ <tag>options ``COMPAT_43''</tag>
+
+ <p>Compatibility with BSD 4.3. Leave this in; some
+ programs will act strangely if you comment this
+ out.
+
+ <tag>options BOUNCE_BUFFERS</tag>
+
+ <p>ISA devices and EISA devices operating in an ISA
+ compatibilty mode can only perform DMA (Direct
+ Memory Access) to memory below 16 megabytes. This
+ option enables such devices to work in systems with
+ more than 16 megabytes of memory.
+
+ <tag>options UCONSOLE</tag>
+
+ <p>Allow users to grab the console, useful for X
+ Windows. For example, you can create a console
+ xterm by typing <tt>xterm -C</tt>, which will
+ display any `write', `talk', and other messages you
+ receive.
+
+ <tag>options SYSVSHM</tag>
+
+ <p>This option
+ provides for System V shared memory. The most
+ common use of this is the XSHM extension in X
+ Windows, which many graphics-intensive programs
+ (such as the movie player XAnim, and Linux DOOM)
+ will automatically take advantage of for extra
+ speed. If you use X Windows, you'll definitely
+ want to include this.
+
+ <tag>options SYSVSEM</tag>
+
+ <p>Support for System V
+ semaphores. Less commonly used but only adds a few
+ hundred bytes to the kernel.
+
+ <tag>options SYSVMSG</tag>
+
+ <p>Support for System V
+ messages. Again, only adds a few hundred bytes to
+ the kernel.
+
+ <quote><em/Note:/ The <tt>ipcs(1)</tt> command will
+ tell will list any processes using using each of
+ these System V facilities.</quote>
+
+ </descrip>
+
+ <sect1><heading>Filesystem Options</heading>
+
+ <p>These options add support for various filesystems.
+ You must include at least one of these to support the
+ device you boot from; typically this will be
+ <tt>FFS</tt> if you boot from a hard drive, or
+ <tt>NFS</tt> if you are booting a diskless workstation
+ from Ethernet. You can include other commonly-used
+ filesystems in the kernel, but feel free to comment out
+ support for filesystems you use less often (perhaps the
+ MS-DOS filesystem?), since they will be dynamically
+ loaded from the Loadable Kernel Module directory
+ <tt>/lkm</tt> the first time you mount a partition of
+ that type.
+
+ <descrip>
+
+ <tag>options FFS</tag>
+
+ <p>The basic hard drive
+ filesystem; leave it in if you boot from the hard
+ disk.
+
+ <tag>options NFS</tag>
+
+ <p>Network Filesystem. Unless
+ you plan to mount partitions from a Unix file
+ server over Ethernet, you can comment this out.
+
+ <tag>options MSDOSFS</tag>
+
+ <p>MS-DOS Filesystem. Unless
+ you plan to mount a DOS formatted hard drive
+ partition at boot time, you can safely comment this
+ out. It will be automatically loaded the first
+ time you mount a DOS partition, as described above.
+ Also, the excellent <tt>mtools</tt> software (in
+ the ports collection) allows you to access DOS
+ floppies without having to mount and unmount them
+ (and does not require MSDOSFS at all).
+
+ <tag>options ``CD9660''</tag>
+
+ <p>ISO 9660 filesystem for
+ CD-ROMs. Comment it out if you do not have a
+ CD-ROM drive or only mount data CD's occasionally
+ (since it will be dynamically loaded the first time
+ you mount a data CD). Audio CD's do not need this
+ filesystem.
+
+ <tag>options PROCFS</tag>
+
+ <p>Process filesystem. This
+ is a pretend filesystem mounted on /proc which
+ allows programs like <tt>ps(1)</tt> to give you
+ more information on what processes are running.
+ Leave it in.
+
+ <tag>options MFS</tag>
+
+ <p>Memory-mapped file system.
+ This is basically a RAM disk for fast storage of
+ temporary files, useful if you have a lot of swap
+ space that you want to take advantage of. A
+ perfect place to mount an MFS partition is on the
+ <tt>/tmp</tt> directory, since many programs store
+ temporary data here. To mount an MFS RAM disk on
+ <tt>/tmp</tt>, add the following line to
+ <tt>/etc/fstab</tt> and then reboot or type
+ <tt>mount /tmp</tt>:
+<tscreen><verb>
+/dev/wd1s2b /tmp mfs rw 0 0
+</verb></tscreen>
+
+ <quote><em/Note:/ Replace the <tt>/dev/wd1s2b</tt>
+ with the name of your swap partition, which will
+ be listed in your <tt>/etc/fstab</tt> as follows:
+<tscreen><verb>
+/dev/wd1s2b none swap sw 0 0
+</verb></tscreen>
+ </quote>
+
+ <quote><em/Note:/ <!-- MFS is currently a bit
+ limited (for example, I noticed that two programs
+ ca not access the <tt>/tmp</tt> device
+ simultaneously). As such, you may want to avoid
+ it for now. --> Also, the <tt>MFS</tt> filesystem
+ can <em>not</em> be dynamically loaded, so you
+ <em>must</em> compile it into your kernel if you
+ want to experiment with it.</quote>
+
+ <tag>options QUOTA</tag>
+
+ <p>Enable disk quotas. If you
+ have a public access system, and do not want users
+ to be able to overflow the <tt>/home</tt>
+ partition, you can establish disk quotas for each
+ user. This code is a little buggy, so do not
+ enable it unless you have to. View the manual page
+ for <tt>quota(1)</tt> to learn more about disk
+ quotas.
+
+ </descrip>
+
+ <sect1><heading>Basic Controllers and Devices</heading>
+
+ <p>These sections describe the basic disk, tape, and
+ CD-ROM controllers supported by FreeBSD. There are
+ separate sections for <ref id="kernelconfig:scsi"
+ name="SCSI"> controllers and <ref
+ id="kernelconfig:network" name="network"> cards.
+
+ <descrip>
+
+ <tag>controller isa0</tag>
+
+ <p>All PC's supported by
+ FreeBSD have one of these. If you have an IBM PS/2
+ (Micro Channel Architecture), then you cannot run
+ FreeBSD at this time.
+
+ <tag>controller pci0</tag>
+
+ <p>Include this if you have a
+ PCI motherboard. This enables auto-detection of
+ PCI cards and gatewaying from the PCI to the ISA
+ bus.
+
+ <tag>controller fdc0</tag>
+
+ <p>Floppy drive controller:
+ <tt>fd0</tt> is the ``A:'' floppy drive, and
+ <tt>fd1</tt> is the ``B:'' drive. <tt>ft0</tt> is
+ a QIC-80 tape drive attached to the floppy
+ controller. Comment out any lines corresponding to
+ devices you do not have.
+
+ <quote><em/Note:/ QIC-80 tape support requires a
+ separate filter program called <tt>ft(8)</tt>, see
+ the manual page for details.</quote>
+
+ <tag>controller wdc0</tag>
+
+ <p>This is the primary IDE
+ controller. <tt>wd0</tt> and <tt>wd1</tt> are the
+ master and slave hard drive, respectively.
+ <tt>wdc1</tt> is a secondary IDE controller where
+ you might have a third or fourth hard drive, or an
+ IDE CD-ROM. Comment out the lines which do not
+ apply (if you have a SCSI hard drive, you'll
+ probably want to comment out all six lines, for
+ example).
+
+ <tag>controller wcd0<label id="kernelconfig:atapi"></tag>
+
+ <p>This device
+ provides IDE CD-ROM support. Be sure to leave
+ <tt>wdc1</tt> uncommented if your CD-ROM is on
+ its own controller card. To use this, you must
+ also include the line <tt>options ATAPI</tt>.
+
+ <tag>device npx0 at isa? port ``IO_NPX'' irq 13 vector npxintr</tag>
+
+ <p><tt>npx0</tt> is the interface to the
+ math coprocessor. If you have one then make sure
+ you've commented out <ref id="kernelconfig:mathemu"
+ name="MATH_EMULATE"> above. If you do not have a
+ math coprocessor, you can comment this out.
+
+ <tag>device wt0 at isa? port 0x300 bio irq 5 drq 1 vector wtintr</tag>
+
+ <p>Wangtek and Archive
+ QIC-02/QIC-36 tape drive support
+
+ <tag>Proprietary CD-ROM support</tag>
+
+ <p>The following
+ drivers are for the so-called <em>proprietary</em>
+ CD-ROM drives. These drives have their own
+ controller card or might plug into a sound card
+ such as the Soundblaster 16. They are <em>not</em>
+ IDE or SCSI. Most older single-speed and
+ double-speed CD-ROMs use these interfaces, while
+ newer quad-speeds are likely to be <ref
+ id="kernelconfig:atapi" name="IDE"> or <ref
+ id="kernelconfig:scsi" name="SCSI">.
+
+ <descrip>
+
+ <tag>device mcd0 at isa? port 0x300 bio irq 10 vector mcdintr</tag>
+
+ <p>Mitsumi CD-ROM (LU002,
+ LU005, FX001D).
+
+ <tag>device scd0 at isa? port 0x230 bio</tag>
+
+ <p>Sony CD-ROM (CDU31, CDU33A).
+
+ <tag>controller matcd0 at isa? port ? bio</tag>
+
+ <p>Matsushita/Panasonic CD-ROM (sold by Creative
+ Labs for Soundblaster).
+
+ </descrip>
+
+ </descrip>
+
+ <sect1><heading>SCSI Device Support<label id="kernelconfig:scsi"></heading>
+
+ <p>This section describes the various SCSI controllers
+ and devices supported by FreeBSD.
+
+ <descrip>
+
+ <tag>SCSI Controllers</tag>
+
+ <p>The next ten or so lines include support for
+ different kinds of SCSI controllers. Comment out
+ all except for the one(s) you have:
+
+ <descrip>
+
+ <tag>controller bt0 at isa? port ``IO_BT0'' bio irq ? vector btintr</tag>
+
+ <p>Most Buslogic controllers
+
+ <tag>controller uha0 at isa? port ``IO_UHA0'' bio irq ? drq 5 vector uhaintr</tag>
+
+ <p>UltraStor 14F and 34F
+
+ <tag>controller ahc0</tag>
+
+ <p>Adaptec 274x/284x/294x
+
+ <tag>controller ahb0 at isa? bio irq ? vector ahbintr</tag>
+
+ <p>Adaptec 174x
+
+ <tag>controller aha0 at isa? port ``IO_AHA0'' bio irq ? drq 5 vector ahaintr</tag>
+
+ <p>Adaptec 154x
+
+ <tag>controller aic0 at isa? port 0x340 bio irq 11 vector aicintr
+</tag>
+
+ <p>Adaptec 152x and sound cards using Adaptec AIC-6360 (slow!)
+
+ <tag>controller nca0 at isa? port 0x1f88 bio irq 10 vector ncaintr
+</tag>
+
+ <p>ProAudioSpectrum cards using NCR 5380 or Trantor T130
+
+ <tag>controller sea0 at isa? bio irq 5 iomem 0xc8000 iosiz 0x2000 vector seaintr</tag>
+
+ <p>Seagate ST01/02 8 bit controller (slow!)
+
+ <tag>controller wds0 at isa? port 0x350 bio irq 15 drq 6 vector wdsintr</tag>
+
+ <p>Western Digital WD7000 controller
+
+ <tag>controller ncr0</tag>
+
+ <p>NCR 53C810 and 53C825 PCI SCSI controller
+
+ </descrip>
+
+ <tag>options ``SCSI_DELAY=15''</tag>
+
+ <p>This causes the
+ kernel to pause 15 seconds before probing each SCSI
+ device in your system. If you only have IDE hard
+ drives, you can ignore this, otherwise you'll
+ probably want to lower this number, perhaps to 5
+ seconds, to speed up booting. Of course if you do
+ this, and FreeBSD has trouble recognizing your SCSI
+ devices, you'll have to raise it back up.
+
+ <tag>controller scbus0</tag>
+
+ <p>If you have any SCSI
+ controllers, this line provides generic SCSI
+ support. If you do not have SCSI, you can comment
+ this, and the following three lines, out.
+
+ <tag>device sd0</tag>
+
+ <p>Support for SCSI hard
+ drives.
+
+ <tag>device st0</tag>
+
+ <p>Support for SCSI tape
+ drives.
+
+ <tag>device cd0</tag>
+
+ <p>Support for SCSI CD-ROM
+ drives.
+
+ </descrip>
+
+ <sect1><heading>Console, Bus Mouse, and X Server Support</heading>
+
+ <p>You must choose one of these two console types, and, if you plan
+ to use X Windows, enable the XSERVER option and optionally, a bus
+ mouse or PS/2 mouse device.
+
+ <descrip>
+
+ <tag>device sc0 at isa? port ``IO_KBD' tty irq 1 vector scintr</tag>
+
+ <p><tt>sc0</tt> is the default
+ console driver, which resembles an SCO console.
+ Since most full-screen programs access the console
+ through a terminal database library like
+ <em>termcap</em>, it should not matter much whether
+ you use this or <tt>vt0</tt>, the VT220 compatible
+ console driver. When you log in, set your TERM
+ variable to ``scoansi'' if full-screen programs
+ have trouble running under this console.
+
+ <tag>device vt0 at isa? port ``IO_KBD'' tty irq 1 vector pcrint</tag>
+
+ <p>This is a VT220-compatible
+ console driver, backwards compatible to VT100/102.
+ It works well on some laptops which have hardware
+ incompatibilities with <tt>sc0</tt>. Also, set
+ your TERM variable to ``vt220'' when you log in if
+ full-screen programs do not run correctly on this
+ console.
+
+ <descrip>
+
+ <tag>options ``PCVT_FREEBSD=210''</tag>
+
+ <p>Required
+ with the <tt>vt0</tt> console driver.
+
+ <tag>options XSERVER</tag>
+
+ <p>This includes code
+ required to run the <tt>XFree86</tt> X Window
+ Server.
+
+ </descrip>
+
+ <tag>device mse0 at isa? port 0x23c tty irq 5 vector ms</tag>
+
+ <p>Use this device if you have a Logitech or
+ ATI InPort bus mouse card.
+
+ <quote><em/Note:/ If you have a serial mouse,
+ ignore these two lines, and instead, make sure
+ the appropriate <ref id="kernelconfig:serial"
+ name="serial"> port is enabled (probably
+ COM1).</quote>
+
+ <tag>device psm0 at isa? port ``IO_KBD'' conflicts tty irq 12 vector psmintr</tag>
+
+ <p>Use this device if your
+ mouse plugs into the PS/2 mouse port.
+
+ </descrip>
+
+ <sect1><heading>Serial and Parallel Ports</heading>
+
+ <p>Nearly all systems have these. If you are attaching a
+ printer to one of these ports, the <ref id="printing"
+ name="Printing"> section of the handbook is very
+ useful. If you are using modem, <ref id="dialup"
+ name="Dialup access"> provides extensive detail on
+ serial port configuration for use with such devices.
+
+ <descrip>
+
+ <tag>device sio0 at isa? port ``IO_COM1'' tty irq 4 vector siointr<label id="kernelconfig:serial"></tag>
+
+ <p><tt>sio0</tt>
+ through <tt>sio3</tt> are the four serial ports
+ referred to as COM1 through COM4 in the MS-DOS
+ world. Note that if you have an internal modem on
+ COM4 and a serial port at COM2 you will have to
+ change the IRQ of the modem to 2 (for obscure
+ technical reasons IRQ 2 = IRQ 9) in order to access
+ it from FreeBSD. If you have a multiport serial
+ card, check the manual page for <tt>sio(4)</tt> for
+ more information on the proper values for these
+ lines.
+
+ <tag>device lpt0 at isa? port? tty irq 7 vector lptintr</tag>
+
+ <p><tt>lpt0</tt> through <tt>lpt2</tt>
+ are the three printer ports you could conceivably
+ have. Most people just have one, though, so feel
+ free to comment out the other two lines if you do
+ not have them.
+
+ </descrip>
+
+ <sect1><heading>Networking<label id="kernelconfig:network"></heading>
+
+ <p>FreeBSD, as with Unix in general, places a
+ <em>big</em> emphasis on networking. Therefore, even
+ if you do not have an Ethernet card, pay attention to
+ the mandatory options and the dial-up networking
+ support.
+
+ <descrip>
+
+ <tag>options INET</tag>
+ Networking support. Leave it in even if you do not plan
+ to be connected to a network. Most programs require at least
+ loopback networking (i.e. making network connections within your
+ PC) so this is essentially mandatory.
+
+ <tag>Ethernet cards</tag>
+
+ <p>The next lines enable support for various Ethernet
+ cards. If you do not have a network card, you can
+ comment out all of these lines. Otherwise, you'll
+ want to leave in support for your particular
+ Ethernet card(s):
+
+ <descrip>
+
+ <tag>device de0</tag>
+
+ <p>Digital Equipment DC21040 PCI Ethernet adapter
+
+ <tag>device cx0 at isa? port 0x240 net irq 15 drq 7 vector cxintr</tag>
+
+ <p>Cronyx/Sigma multiport
+ sync/async (with Cisco or PPP framing)
+
+ <tag>device ed0 at isa? port 0x280 net irq 5 iomem 0xd8000 vector edintr</tag>
+
+ <p>Western Digital and SMC 80xx; Novell NE1000
+ and NE2000; 3Com 3C503
+
+ <tag>device el0 at isa? port 0x300 net irq 9 vector elintr</tag>
+
+ <p>3Com 3C501 (slow!)
+
+ <tag>device eg0 at isa? port 0x310 net irq 5 vector egintr</tag>
+
+ <p>3Com 3C505
+
+ <tag>device ep0 at isa? port 0x300 net irq 10 vector epintr</tag>
+
+ <p>3Com 3C509 (buggy)
+
+ <tag>device fe0 at isa? port 0x240 net irq ? vector feintr</tag>
+
+ <p>Fujitsu MB86960A/MB86965A Ethernet
+
+ <tag>device fea0 at isa? net irq ? vector feaintr</tag>
+
+ <p>DEC DEFEA EISA FDDI adapter
+
+ <tag>device ie0 at isa? port 0x360 net irq 7 iomem 0xd0000 vector ieintr</tag>
+
+ <p>AT&amp;T StarLAN 10 and EN100; 3Com 3C507;
+ unknown NI5210
+
+ <tag>device ix0 at isa? port 0x300 net irq 10 iomem 0xd0000 iosiz 32768 vector ixintr</tag>
+
+ <p>Intel EtherExpress 16
+
+ <tag>device le0 at isa? port 0x300 net irq 5 iomem 0xd0000 vector le_intr</tag>
+
+ <p>Digital Equipment EtherWorks 2 and EtherWorks
+ 3 (DEPCA, DE100, DE101, DE200, DE201, DE202,
+ DE203, DE204, DE205, DE422)
+
+ <tag>device lnc0 at isa? port 0x300 net irq 10 drq 0 vector lncintr</tag>
+
+ <p>Lance/PCnet cards (Isolan, Novell NE2100,
+ NE32-VL)
+
+ <tag>device ze0 at isa? port 0x300 net irq 5 iomem 0xd8000 vector zeintr</tag>
+
+ <p>IBM/National Semiconductor PCMCIA ethernet
+ controller.
+
+ <tag>device zp0 at isa? port 0x300 net irq 10 iomem 0xd8000 vector zpintr</tag>
+
+ <p>3Com PCMCIA Etherlink III
+
+ </descrip>
+
+ <quote><em/Note:/ With certain cards (notably the
+ NE2000) you'll have to change the port and/or IRQ
+ since there is no ``standard'' location for these
+ cards.</quote>
+
+ <tag>pseudo-device loop</tag>
+
+ <p><tt>loop</tt> is the
+ generic loopback device for TCP/IP. If you telnet
+ or FTP to <em>localhost</em>
+ (a.k.a. <tt>127.0.0.1</tt>) it will come back at
+ you through this pseudo-device. Mandatory.
+
+ <tag>pseudo-device ether</tag>
+
+ <p><tt>ether</tt> is only
+ needed if you have an Ethernet card and includes
+ generic Ethernet protocol code.
+
+ <tag>pseudo-device sl <em>number</em></tag>
+
+ <p><tt>sl</tt> is for SLIP (Serial Line Internet
+ Protocol) support. This has been almost entirely
+ supplanted by PPP, which is easier to set up,
+ better suited for modem-to-modem connections, as
+ well as more powerful. The <em>number</em> after
+ <tt>sl</tt> specifies how many simultaneous SLIP
+ sessions to support. This handbook has more
+ information on setting up a SLIP <ref id="slipc"
+ name="client"> or <ref id="slips" name="server">.
+
+ <tag>pseudo-device ppp <em>number</em></tag>
+
+ <p><tt>ppp</tt> is for kernel-mode PPP (Point-to-Point
+ Protocol) support for dial-up Internet connections.
+ There is also version of PPP implemented as a user
+ application that uses the <tt>tun</tt> and offers
+ more flexibility and features such as demand
+ dialing. If you still want to use this PPP driver,
+ read the <ref id="ppp" name="kernel-mode PPP">
+ section of the handbook. As with the <tt>sl</tt>
+ device, <em>number</em> specifies how many
+ simultaneous PPP connections to support.
+
+ <tag>pseudo-device tun <em>number</em></tag>
+
+ <p><tt>tun</tt> is used by the user-mode PPP software.
+ This program is easy to set up and very fast. It
+ also has special features such as automatic
+ dial-on-demand. The number after <tt>tun</tt>
+ specifies the number of simultaneous PPP sessions
+ to support. See the <ref id="userppp"
+ name="user-mode PPP"> section of the handbook for
+ more information.
+
+ <tag>pseudo-device bpfilter <em>number</em></tag>
+
+ <p>Berkeley packet filter. This pseudo-device allows
+ network interfaces to be placed in promiscuous
+ mode, capturing every packet on a broadcast network
+ (e.g. an ethernet). These packets can be captured
+ to disk and/or examined with the
+ <tt>tcpdump(1)</tt> program. Note that
+ implementation of this capability can seriously
+ compromise your overall network security.
+ The <em>number</em> after bpfilter is the number of
+ interfaces that can be examined
+ simultaneously. Optional, not recommended except
+ for those who are fully aware of the potential
+ pitfalls. Not all network cards support this
+ capability.
+
+ </descrip>
+
+ <sect1><heading>Sound cards</heading>
+
+ <p>This is the first section containing lines that are
+ not in the GENERIC kernel. To include sound card
+ support, you'll have to copy the appropriate lines from
+ the LINT kernel (which contains support for
+ <em>every</em> device) as follows:
+
+ <descrip>
+
+ <tag>controller snd0</tag>
+
+ <p>Generic sound driver code.
+ Required for all of the following sound cards
+ except <tt>pca</tt>.
+
+ <tag>device pas0 at isa? port 0x388 irq 10 drq 6 vector pasintr</tag>
+
+ <p>ProAudioSpectrum digital audio and MIDI.
+
+ <tag>device sb0 at isa? port 0x220 irq 7 conflicts drq 1 vector sbintr</tag>
+
+ <p>SoundBlaster digital audio.
+
+ <quote><em/Note:/ If your Soundblaster is on a
+ different IRQ (such as 5), change <tt>irq 7</tt>
+ to, for example, <tt>irq 5</tt> and remove the
+ <tt>conflicts</tt> keyword. Also, you must add
+ the line: <tt>options ``SBC_IRQ=5''</tt></quote>
+
+ <tag>device sbxvi0 at isa? drq 5</tag>
+
+ <p>SoundBlaster 16 digital 16-bit audio.
+
+ <quote><em/Note:/ If your SB16 is on a different
+ 16-bit DMA channel (such as 6 or 7), change the
+ <tt>drq 5</tt> keyword appropriately, and then
+ add the line: <tt>options
+ "SB16_DMA=6"</tt></quote>
+
+ <tag>device sbmidi0 at isa? port 0x330</tag>
+
+ <p>SoundBlaster 16 MIDI interface. If you have a
+ SoundBlaster 16, you must include this line, or the
+ kernel will not compile.
+
+ <tag>device gus0 at isa? port 0x220 irq 10 drq 1 vector gusintr</tag>
+
+ <p>Gravis Ultrasound.
+
+ <tag>device mss0 at isa? port 0x530 irq 10 drq 1 vector adintr</tag>
+
+ <p>Microsoft Sound System.
+
+ <tag>device opl0 at isa? port 0x388 conflicts</tag>
+
+ <p>AdLib FM-synthesis audio. Include this line for
+ AdLib, SoundBlaster, and ProAudioSpectrum users, if
+ you want to play MIDI songs with a program such as
+ <tt>playmidi</tt> (in the ports collection).
+
+ <tag>device mpu0 at isa? port 0x330 irq 6 drq 0</tag>
+
+ <p>Roland MPU-401 stand-alone card.
+
+ <tag>device uart0 at isa? port 0x330 irq 5 vector ``m6850intr''</tag>
+
+ <p>Stand-alone 6850 UART for MIDI.
+
+ <tag>device pca0 at isa? port ``IO_TIMER1'' tty</tag>
+
+ <p>Digital audio through PC speaker. This is going to
+ be very poor sound quality and quite CPU-intensive,
+ so you have been warned (but it does not require a
+ sound card)!
+
+ </descrip>
+
+ <quote><em/Note:/ There is some additional
+ documentation in
+ <tt>/usr/src/sys/i386/isa/sound/sound.doc</tt>.
+ Also, if you add any of these devices, be sure to
+ create the sound <ref id="kernelconfig:nodes"
+ name="device nodes">.</quote>
+
+ <sect1><heading>Pseudo-devices</heading>
+
+ <p>Pseudo-device drivers are parts of the kernel that act
+ like device drivers but do not correspond to any actual
+ hardware in the machine. The <ref
+ id="kernelconfig:network" name="network-related">
+ pseudo-devices are in that section, while the remainder
+ are here.
+
+ <descrip>
+
+ <tag>pseudo-device gzip</tag>
+
+ <p><tt>gzip</tt> allows you to run FreeBSD programs
+ that have been compressed with <tt>gzip</tt>. This
+ is really only useful when you need to compress
+ FreeBSD programs to fit on a boot floppy. You will
+ probably never need to compress programs on your
+ hard drive in this fashion, so you'll probably want
+ to comment out this line.
+ <tag>pseudo-device log</tag>
+
+ <p><tt>log</tt> is used for logging of kernel error
+ messages. Mandatory.
+
+
+ <tag>pseudo-device pty <em>number</em><label id="kernelconfig:ptys"></tag>
+
+ <p><tt>pty</tt> is a ``pseudo-terminal'' or simulated
+ login port. It's used by incoming <bf>telnet</bf>
+ and <bf>rlogin</bf> sessions, xterm, and some other
+ applications such as emacs. The <em>number</em>
+ indicates the number of <tt>pty</tt>s to create.
+ If you need more than GENERIC default of 16
+ simultaneous xterm windows and/or remote logins, be
+ sure to increase this number accordingly, up to a
+ maximum of 64.
+
+ <tag>pseudo-device snp <em>number</em></tag>
+
+ <p>Snoop device. This pseudo-device allows one
+ terminal session to watch another using the
+ <tt>watch(8)</tt> command. Note that
+ implementation of this capability has important
+ security and privacy implications. The
+ <em>number</em> after snp is the total number of
+ simultaneous snoop sessions. Optional.
+
+ <tag>pseudo-device vn</tag>
+
+ <p>Vnode driver. Allows a file to be treated as a
+ device after being set up with the
+ <tt>vnconfig(8)</tt> command. This driver can be
+ useful for manipulating floppy disk images and
+ using a file as a swap device (e.g. an MS Windows
+ swap file). Optional.
+
+ </descrip>
+
+ <sect1><heading>Joystick, PC Speaker, Miscellaneous</heading>
+
+ <p>This section describes some miscellaneous hardware
+ devices supported by FreeBSD. Note that none of these
+ lines are included in the GENERIC kernel, you'll have
+ to copy them from this handbook or the LINT kernel
+ (which contains support for <em>every</em> device):
+
+ <descrip>
+
+ <tag>device joy0 at isa? port ``IO_GAME''</tag>
+
+ <p>PC joystick device.
+
+ <tag>pseudo-device speaker</tag>
+
+ <p>Supports IBM BASIC-style noises through the PC
+ speaker. Some fun programs which use this are
+ <tt>/usr/sbin/spkrtest</tt>, which is a shell
+ script that plays some simple songs, and
+ <tt>/usr/games/piano</tt> which lets you play songs
+ using the keyboard as a simple piano (this file
+ only exists if you've installed the <em>games</em>
+ package). Also, the excellent text role-playing
+ game NetHack (in the ports collection) can be
+ configured to use this device to play songs when
+ you play musical instruments in the game.
+
+ </descrip>
+
+ <sect><heading>Making Device Nodes<label id="kernelconfig:nodes"></heading>
+
+ <p>Almost every device in the kernel has a corresponding
+ ``node'' entry in the <tt>/dev</tt> directory. These
+ nodes look like regular files, but are actually special
+ entries into the kernel which programs use to access the
+ device. The shell script <tt>/dev/MAKEDEV</tt>, which is
+ executed when you first install the operating system,
+ creates nearly all of the device nodes supported.
+ However, it does not create <em>all</em> of them, so when
+ you add support for a new device, it pays to make sure
+ that the appropriate entries are in this directory, and
+ if not, add them. Here is a simple example:
+
+ Suppose you add the IDE CD-ROM support to the kernel.
+ The line to add is:
+<tscreen><verb>
+controller wcd0
+</verb></tscreen>
+ This means that you should look for some entries that
+ start with <tt>wcd0</tt> in the <tt>/dev</tt> directory,
+ possibly followed by a letter, such as `c', or preceded
+ by the letter 'r', which means a `raw' device. It turns
+ out that those files are not there, so I must change to
+ the <tt>/dev</tt> directory and type:
+<tscreen><verb>
+# sh MAKEDEV wcd0
+</verb></tscreen>
+ When this script finishes, you will find that there are
+ now <tt>wcd0c</tt> and <tt>rwcd0c</tt> entries in
+ <tt>/dev</tt> so you know that it executed correctly.
+
+ For sound cards, the command:
+<tscreen><verb>
+# sh MAKEDEV snd0
+</verb></tscreen>
+ creates the appropriate entries. Follow this simple
+ procedure for any other non-GENERIC devices which do not
+ have entries.
+
+ <quote><em/Note:/ All SCSI controllers use the same set
+ of <tt>/dev</tt> entries, so you do not need to create
+ these. Also, network cards and SLIP/PPP pseudo-devices
+ do not have entries in <tt>/dev</tt> at all, so you do
+ not have to worry about these either.</quote>
+
+<sect><heading>If Something Goes Wrong<label id="kernelconfig:trouble"></heading>
+
+ <p>There are four categories of trouble that can occur when
+ building a custom kernel. They are:
+
+ <descrip>
+
+ <tag>Config command fails</tag>
+
+ <p>If the <tt>config</tt>
+ command fails when you give it your kernel
+ description, you've probably made a simple error
+ somewhere. Fortunately, <tt>config</tt> will print
+ the line number that it had trouble with, so you can
+ quickly skip to it with <tt>vi</tt>. For example, if
+ you see:
+<tscreen><verb>
+config: line 17: syntax error
+</verb></tscreen>
+ you can skip to the problem in <tt>vi</tt> by typing
+ ``17G'' in command mode. Make sure the keyword is
+ typed correctly, by comparing it to the GENERIC
+ kernel or another reference.
+
+ <tag>Make command fails</tag>
+
+ <p>If the <tt>make</tt>
+ command fails, it usually signals an error in your
+ kernel description, but not severe enough for
+ <tt>config</tt> to catch it. Again, look over your
+ configuration, and if you still cannot resolve the
+ problem, send mail to <tt><htmlurl
+ url="mailto:questions@freebsd.org"
+ name="questions@FreeBSD.ORG"></tt> with your kernel
+ configuration, and it should be diagnosed very
+ quickly.
+
+ <tag>Kernel will not boot<label id="kernelconfig:noboot"></tag>
+
+ <p>If your new kernel
+ does not boot, or fails to recognize your devices,
+ do not panic! Fortunately, BSD has an excellent
+ mechanism for recovering from incompatible kernels.
+ Simply type the name of the kernel you want to boot
+ from (i.e. ``kernel.old'') at the FreeBSD boot
+ prompt instead of pressing return. When
+ reconfiguring a kernel, it is always a good idea to
+ keep a kernel that is known to work on hand.
+
+ After booting with a good kernel you can check over
+ your configuration file and try to build it again.
+ One helpful resource is the
+ <tt>/var/log/messages</tt> file which records, among
+ other things, all of the kernel messages from every
+ successful boot. Also, the <tt>dmesg(8)</tt> command
+ will print the kernel messages from the current boot.
+
+ <quote><em/Note:/ If you are having trouble building
+ a kernel, make sure to keep a GENERIC, or some
+ other kernel that is known to work on hand as a
+ different name that will not get erased on the next
+ build. You cannot rely on <tt>kernel.old</tt>
+ because when installing a new kernel,
+ <tt>kernel.old</tt> is overwritten with the last
+ installed kernel which may be non-functional.
+ Also, as soon as possible, move the working kernel
+ to the proper ``kernel'' location or commands such
+ as <tt>ps(1)</tt> will not work properly. The
+ proper command to ``unlock'' the kernel file that
+ <tt>make</tt> installs (in order to move another
+ kernel back permanently) is:
+<tscreen><verb>
+# chflags noschg /kernel
+</verb></tscreen>
+ And, if you want to ``lock'' your new kernel into place, or any file
+ for that matter, so that it cannot be moved or tampered with:
+<tscreen><verb>
+# chflags schg /kernel
+</verb></tscreen>
+ </quote>
+
+ <tag>Kernel works, but <tt>ps</tt> does not work any more!</tag>
+
+ <p>If you've installed a different version
+ of the kernel from the one that the system utilities
+ have been built with, for example, an experimental
+ ``2.2.0'' kernel on a 2.1.0-RELEASE system, many
+ system-status commands like <tt>ps(1)</tt> and
+ <tt>vmstat(8)</tt> will not work any more. You must
+ recompile the <tt>libkvm</tt> library as well as
+ these utilities. This is one reason it is not
+ normally a good idea to use a different version of
+ the kernel from the rest of the operating system.
+
+ </descrip>
diff --git a/share/doc/handbook/printing.sgml b/share/doc/handbook/printing.sgml
new file mode 100644
index 000000000000..fd6d75bd0b7f
--- /dev/null
+++ b/share/doc/handbook/printing.sgml
@@ -0,0 +1,3877 @@
+<!-- This is an SGML document in the linuxdoc DTD describing
+ Printing with FreeBSD. By Sean Kelly, 1995.
+
+ $Id: printing.sgml,v 1.1 1995/10/01 04:43:13 jfieber Exp $
+
+ The FreeBSD Documentation Project
+
+<!DOCTYPE linuxdoc PUBLIC "-//FreeBSD//DTD linuxdoc//EN">
+
+ <article>
+ <title> Printing with FreeBSD
+ <author> Sean Kelly <tt/kelly@fsl.noaa.gov/
+ <date> 30 September 1995, (c) 1995
+
+ <abstract> This document describes printing with FreeBSD. It
+ tells how to set up printer hardware, how to configure FreeBSD
+ to use printers, and how to control the print queue and print
+ a variety of file formats. </abstract>
+
+ <toc>
+-->
+
+ <chapt><heading>Printing<label id="printing"></heading>
+
+ <p><em>Contributed by &a.kelly;<newline>30 September 1995</em>
+
+ In order to use printers with FreeBSD, you'll need to set
+ them up to work with the Berkeley line printer spooling
+ system, also known as the LPD spooling system. It's the
+ standard printer control system in FreeBSD. This section
+ introduces the LPD spooling system, often simply called LPD.
+
+ If you're already familiar with LPD or another printer
+ spooling system, you may wish to skip to section <ref
+ id="printing:intro:setup" name="Setting up the spooling
+ system">.
+
+ <sect><heading>What the Spooler Does<label
+ id="printing:intro:spooler"></heading>
+
+ <p> LPD controls everything about a host's printers. It's
+ responsible for a number of things:
+
+ <itemize>
+ <item>It controls access to attached printers and
+ printers attached to other hosts on the network.
+
+ <item>It enables users to submit files to be printed;
+ these submissions are known as <em/jobs/.
+
+ <item>It prevents multiple users from accessing a printer
+ at the same time by maintaining a <em/queue/ for each
+ printer.
+
+ <item>It can print <em/header pages/ (also known as
+ <em/banner/ or <em/burst/ pages) so users can easily
+ find jobs they've printed in a stack of printouts.
+
+ <item>It takes care of communications parameters for
+ printers connected on serial ports.
+
+ <item>It can send jobs over the network to another LPD
+ spooler on another host.
+
+ <item>It can run special filters to format jobs to be
+ printed for various printer languages or printer
+ capabilities.
+
+ <item>It can account for printer usage.
+ </itemize>
+
+ Through a configuration file, and by providing the special
+ filter programs, you can enable the LPD system to do all or
+ some subset of the above for a great variety of printer
+ hardware.
+
+ <sect><heading>Why You Should Use the Spooler<label
+ id="printing:intro:why"></heading>
+
+ <p> If you're the sole user of your system, you may be
+ wondering why you should bother with the spooler when you
+ don't need access control, header pages, or printer
+ accounting. While it's possible to enable direct access to
+ a printer, you should use the spooler anyway since
+
+ <itemize>
+ <item>LPD prints jobs in the background; you don't have
+ to wait for data to be copied to the printer.
+
+ <item>LPD can conveniently run a job to be printed
+ through filters to add date/time headers or convert a
+ special file format (such as a TeX DVI file) into a
+ format the printer will understand. You won't have to do
+ these steps manually.
+
+ <item>Many free and commercial programs that provide a
+ print feature usually expect to talk to the spooler on
+ your system. By setting up the spooling system, you'll
+ more easily support other software you may later add or
+ already have.
+ </itemize>
+
+ <sect><heading>Setting Up the Spooling System<label
+ id="printing:intro:setup"></heading>
+
+ <p> To use printers with the LPD spooling system, you'll need
+ to set up both your printer hardware and the LPD software.
+ This document describes two levels of setup:
+
+ <itemize>
+ <item>See section <ref name="Simple Printer Setup"
+ id="printing:simple"> to learn how to connect a
+ printer, tell LPD how to communicate with it, and
+ print plain text files to the printer.
+
+ <item>See section <ref name="Advanced Printer Setup"
+ id="printing:advanced"> to find out how to print a
+ variety of special file formats, to print header
+ pages, to print across a network, to control access to
+ printers, and to do printer accounting.
+ </itemize>
+
+
+ <sect><heading>Simple Printer Setup<label
+ id="printing:simple"></heading>
+
+ <p> This section tells how to configure printer hardware and the
+ LPD software to use the printer. It teaches the basics:
+
+ <itemize>
+ <item>Section <ref id="printing:hardware" name="Hardware
+ Setup"> gives some hints on connecting the printer to a
+ port on your computer.
+
+ <item>Section <ref id="printing:software" name="Software
+ Setup"> shows how to setup the LPD spooler configuration
+ file <tt>/etc/printcap</tt>.
+ </itemize>
+
+ If you're setting up a printer that uses a network protocol
+ to accept data to print instead of a serial or parallel interface,
+ see <ref id="printing:advanced:network:net-if" name="Printers
+ With Networked Data Stream Interaces">.
+
+ Although this section is called ``Simple Printer Setup,'' it's
+ actually fairly complex. Getting the printer to work with
+ your computer and the LPD spooler is the hardest part. The
+ advanced options like header pages and accounting are fairly
+ easy once you get the printer working.
+
+ <sect1><heading>Hardware Setup<label id="printing:hardware"></heading>
+
+ <p> This section tells about the various ways you can connect a
+ printer to your PC. It talks about the kinds of ports and
+ cables, and also the kernel configuration you may need to
+ enable FreeBSD to speak to the printer.
+
+ If you've already connected your printer and have
+ successfully printed with it under another operating system,
+ you can probably skip to section <ref id="printing:software"
+ name="Software Setup">.
+
+ <sect2><heading>Ports and Cables<label
+ id="printing:ports"></heading>
+
+ <p> Nearly all printers you can get for a PC today support
+ one or both of the following interfaces:
+
+ <itemize>
+ <item><em/Serial/ interfaces use a serial port on your
+ computer to send data to the printer. Serial
+ interfaces are common in the computer industry and
+ cables are readily available and also easy to
+ construct. Serial interfaces sometimes need special
+ cables and might require you to configure somewhat
+ complex communications options.
+
+ <item><em/Parallel/ interfaces use a parallel port on
+ your computer to send data to the printer. Parallel
+ interfaces are common in the PC market. Cables are
+ readily available but more difficult to construct by
+ hand. There are usually no communications options
+ with parallel interfaces, making their configuration
+ exceedingly simple.
+
+ <p> Parallel interfaces are sometimes known as
+ ``Centronics'' interfaces, named after the connector
+ type on the printer.
+ </itemize>
+
+ In general, serial interfaces are slower than parallel
+ interfaces. Parallel interfaces usually offer just
+ one-way communication (computer to printer) while serial
+ gives you two-way. Many newer parallel ports can also
+ receive data from the printer, but only few printers need
+ to send data back to the computer. And FreeBSD doesn't
+ support two-way parallel communication yet.
+
+ Usually, the only time you need two-way communication with
+ the printer is if the printer speaks PostScript.
+ PostScript printers can be very verbose. In fact,
+ PostScript jobs are actually programs sent to the printer;
+ they needn't produce paper at all and may return results
+ directly to the computer. PostScript also uses
+ two-way communication to tell the computer about problems,
+ such as errors in the PostScript program or paper jams.
+ Your users may be appreciative of such information.
+ Furthermore, the best way to do effective accounting with
+ a PostScript printer requires two-way communication: you
+ ask the printer for its page count (how many pages it's
+ printed in its lifetime), then send the user's job, then
+ ask again for its page count. Subtract the two values and
+ you know how much paper to charge the user.
+
+ So, which interface should you use?
+
+ <itemize>
+ <item>If you need two-way communication, use a serial
+ port. FreeBSD does not yet support two-way
+ communication over a parallel port.
+
+ <item>If you don't need two-way communication and can
+ pick parallel or serial, prefer the parallel
+ interface. It keeps a serial port free for other
+ peripherals---such as a terminal or a modem---and is
+ faster most of the time. It's also easier to
+ configure.
+
+ <item>Finally, use whatever works.
+ </itemize>
+
+
+ <sect2><heading>Parallel Ports<label id="printing:parallel"></heading>
+
+ <p> To hook up a printer using a parallel interface, connect
+ the Centronics cable between the printer and the
+ computer. The instructions that came with the printer, the
+ computer, or both should give you complete guidance.
+
+ Remember which parallel port you used on the computer. The
+ first parallel port is /dev/lpt0 to FreeBSD; the second is
+ /dev/lpt1, and so on.
+
+ <sect2><heading>Serial Ports<label id="printing:serial"></heading>
+
+ <p> To hook up a printer using a serial interface, connect
+ the proper serial cable between the printer and the
+ computer. The instructions that came with the printer,
+ the computer, or both should give you complete guidance.
+
+ If you're unsure what the ``proper serial cable'' is, you
+ may wish to try one of the following alternatives:
+ <itemize>
+ <item>A <em/modem/ cable connects each pin of the
+ connector on one end of the cable straight through to
+ its corresponding pin of the connector on the other
+ end. This type of cable is also known as a DTE-to-DCE
+ cable.
+
+ <item>A <em/null-modem/ cable connects some pins
+ straight through, swaps others (send data to receive
+ data, for example), and shorts some internally in each
+ connector hood. This type of cable is also known as a
+ DTE-to-DTE cable.
+
+ <item>A <em/serial printer/ cable, required for some
+ unusual printers, is like the null modem cable, but
+ sends some signals to their counterparts instead of
+ being internally shorted.
+ </itemize>
+
+ You should also set up the communications parameters for
+ the printer, usually through front-panel controls or DIP
+ switches on the printer. Choose the highest bps (bits per
+ second, sometimes <em/baud rate/) rate that both your
+ computer and the printer can support. Choose 7 or 8 data
+ bits; none, even, or odd parity; and 1 or 2 stop bits.
+ Also choose a flow control protocol: either none, or
+ XON/XOFF (also known as <em/in-band/ or <em/software/)
+ flow control. Remember these settings for the software
+ configuration that follows.
+
+ <sect1><heading>Software Setup<label id="printing:software"></heading>
+
+ <p> This section describes the software setup necessary to
+ print with the LPD spooling system in FreeBSD.
+
+ Here's an outline of the steps involved:
+ <enum>
+ <item>Configure your kernel, if necessary, for the port
+ you're using for the printer; section <ref
+ id="printing:kernel" name="Kernel Configuration"> tells
+ you what you need to do.
+
+ <item>Set the communications mode for the parallel port,
+ if you're using a parallel port; section <ref
+ id="printing:parallel-port-mode" name = "Setting the
+ Communication Mode for the Parallel Port"> gives
+ details.
+
+ <item>Test if the operating system can send data to the
+ printer. Section <ref id="printing:testing"
+ name="Checking Printer Communications"> gives some
+ suggestions on how to do this.
+
+ <item>Set up LPD for the printer by modifying the file
+ <tt>/etc/printcap</tt>. Section <ref
+ id="printing:printcap" name="The /etc/printcap File">
+ shows you how.
+ </enum>
+
+ <sect2><heading>Kernel Configuration<label
+ id="printing:kernel"></heading>
+
+ <p> The operating system kernel is compiled to work with a
+ specific set of devices. The serial or parallel interface
+ for your printer is a part of that set. Therefore, it
+ might be necessary to add support for an additional serial
+ or parallel port if your kernel isn't already configured
+ for one.
+
+ To find out if the kernel you're currently using supports a serial
+ interface, type
+<tscreen>
+<tt>dmesg &verbar; grep sio</tt><it/N/
+</tscreen>
+ where <it/N/ is the number of the serial port, starting
+ from zero. If you see output similar to the following
+<tscreen><verb>
+sio2 at 0x3e8-0x3ef irq 5 on isa
+sio2: type 16550A
+</verb></tscreen>
+ then the kernel supports the port.
+
+ To find out if the kernel supports a parallel interface,
+ type
+<tscreen>
+<tt>dmesg &verbar; grep lpt</tt><it/N/
+</tscreen>
+ where <it/N/ is the number of the parallel port, starting
+ from zero. If you see output similar to the following
+<tscreen><verb>
+lpt0 at 0x378-0x37f on isa
+</verb></tscreen>
+ then the kernel supports the port.
+
+ You might have to reconfigure your kernel in order for the
+ operating system to recognize and use the parallel or
+ serial port you're using for the printer.
+
+ To add support for a serial port, see the section on
+ kernel configuration. To add support for a parallel port,
+ see that section <em/and/ the section that follows.
+
+ <sect3><heading>Adding <tt>/dev</tt> Entries for the Ports
+ <label id="printing:dev-ports"></heading>
+
+ <p> Even though the kernel may support communication along
+ a serial or parallel port, you'll still need a software
+ interface through which programs running on the system
+ can send and receive data. That's what entries in the
+ <tt>/dev</tt> directory are for.
+
+ <bf>To add a <tt>/dev</tt> entry for a port:</bf>
+ <enum>
+ <item>Become root with the <tt/su/ command. Enter
+ the root password when prompted.
+
+ <item>Change to the <tt>/dev</tt> directory:
+<tscreen><verb>
+cd /dev
+</verb></tscreen>
+
+ <item>Type
+<tscreen>
+<tt> ./MAKEDEV</tt> <it/port/
+</tscreen>
+ where <it/port/ is the device entry for the port you
+ want to make. Use <tt/lpt0/ for the first parallel
+ port, <tt/lpt1/ for the second, and so on; use
+ <tt/ttyd0/ for the first serial port, <tt/ttyd1/ for
+ the second, and so on.
+
+ <item>Type
+<tscreen>
+<tt>ls -l</tt> <it/port/
+</tscreen>
+ to make sure the device entry got created.
+ </enum>
+
+ <sect3><heading>Setting the Communication Mode for the Parallel Port
+ <label id="printing:parallel-port-mode"></heading>
+
+ <p> When you're using the parallel interface, you can
+ choose whether FreeBSD should use interrupt-driven or
+ polled communication with the printer.
+
+ <itemize>
+ <item>The <em/interrupt-driven/ method is the default
+ with the GENERIC kernel. With this method, the
+ operating system uses an IRQ line to determine when
+ the printer's ready for data.
+
+ <item>The <em/polled/ method directs the operating
+ system to repeatedly ask the printer if it's ready
+ for more data. When it responds ready, the kernel
+ sends more data.
+ </itemize>
+
+ The interrupt-driven method is somewhat faster but uses
+ up a precious IRQ line. You should use whichever one
+ works.
+
+ You can set the communications mode in two ways: by
+ configuring the kernel or by using the <tt/lptcontrol/
+ program.
+
+ <bf>To set the communications mode by configuring the
+ kernel:</bf>
+ <enum>
+ <item>Edit your kernel configuration file. Look for
+ or add an <tt/lpt0/ entry. If you're setting up the
+ second parallel port, use <tt/lpt1/ instead. Use
+ <tt/lpt2/ for the third port, and so on.
+ <itemize>
+ <item>If you want interrupt-driven mode, add the <tt/irq/
+ specifer:
+<tscreen>
+<tt>device lpt0 at isa? port? tty irq <it/N/ vector lptintr</tt>
+</tscreen>
+ where <it/N/ is the IRQ number for your
+ computer's parallel port.
+
+ <item>If you want polled mode, don't add the
+ <tt/irq/ specifier:
+<tscreen>
+<tt>device lpt0 at isa? port? tty vector lptintr</tt>
+</tscreen>
+ </itemize>
+ <item>Save the file. Then configure, build, and
+ install the kernel, then reboot. See <ref id="kernelconfig"
+ name="kernel configuration"> for more details.
+ </enum>
+
+ <bf>To set the communications mode with
+ <tt/lptcontrol/:</bf>
+ <itemize>
+ <item>
+ Type
+<tscreen>
+<tt>lptcontrol -i -u <it/N/</tt>
+</tscreen>
+ to set interrupt-driven mode for <tt/lpt<it/N//.
+
+ <item>
+ Type
+<tscreen>
+<tt>lptcontrol -p -u <it/N/</tt>
+</tscreen>
+ to set polled-mode for <tt/lpt<it/N//.
+ </itemize>
+ You could put these commands in your
+ <tt>/etc/rc.local</tt> file to set the mode each time
+ your system boots. See lptcontrol(8) for more
+ information.
+
+ <sect3><heading>Checking Printer Communications<label
+ id="printing:testing"></heading>
+
+ <p> Before proceeding to configure the spooling system,
+ you should make sure the operating system can
+ successfully send data to your printer. It's a lot
+ easier to debug printer communication and the spooling
+ system separately.
+
+ To test the printer, we'll send some text to it. For
+ printers that can immediately print characters sent to
+ them, the program <tt/lptest/ is perfect: it generates
+ all 96 printable ASCII characters in 96 lines.
+
+ For a PostScript (or other language-based) printer,
+ we'll need a more sophisticated test. A small
+ PostScript program, such as the following, will suffice:
+<code>
+%!PS
+100 100 moveto 300 300 lineto stroke
+310 310 moveto
+/Helvetica findfont 12 scalefont setfont
+(Is this thing working?) show
+showpage
+</code>
+ <em/Note:/ When this document refers to a printer
+ language, I'm assuming a language like PostScript, and
+ not Hewlett Packard's PCL. Although PCL has great
+ functionality, you can intermingle plain text with its
+ escape sequences. PostScript cannot directly print
+ plain text, and that's the kind of printer language for
+ which we must make special accomodations.
+
+ <sect4><heading>Checking a Parallel Printer<label
+ id="printing:checking:parallel"></heading>
+
+ <p> This section tells you how to check if FreeBSD can
+ communicate with a printer connected to a parallel port.
+
+ <bf>To test a printer on a parallel port:</bf>
+ <enum>
+ <item>Become root with <tt/su/.
+ <item>Send data to the printer.
+ <itemize>
+ <item>If the printer can print plain text, then
+ use <tt/lptest/. Type:
+<tscreen>
+<tt>lptest > /dev/lpt<it/N/</tt>
+</tscreen>
+ where <it/N/ is the number of the parallel
+ port, starting from zero.
+
+ <item>If the printer understands PostScript or
+ other printer language, then send a small
+ program to the printer. Type
+<tscreen>
+<tt>cat > /dev/lpt<it/N/</tt>
+</tscreen>
+ Then, line by line, type the program
+ <em/carefully/ as you can't edit a line once
+ you've pressed RETURN or ENTER. When you've
+ finished entering the program, press
+ CONTROL+D, or whatever your end of file key
+ is.
+
+ <p> Alternatively, you can put the program in
+ a file and type
+<tscreen>
+<tt>cat <it/file/ > /dev/lpt<it/N/</tt>
+</tscreen>
+ where <it/file/ is the name of the file
+ containing the program you want to send to
+ the printer.
+ </itemize>
+ </enum>
+
+ You should see something print. Don't worry if the
+ text doesn't look right; we'll fix such things later.
+
+ <sect4><heading>Checking a Serial Printer<label
+ id="printing:checking:serial"></heading>
+
+ <p> This section tells you how to check if FreeBSD can
+ communicate with a printer on a serial port.
+
+ <bf>To test a printer on a serial port:</bf>
+ <enum>
+ <item>Become root with <tt/su/.
+
+ <item>Edit the file <tt>/etc/remote</tt>. Add the
+ following entry:
+<tscreen>
+<tt>printer:dv=/dev/<it/port/:br&num;<it/bps-rate/:pa=<it/parity/</tt>
+</tscreen>
+ where <it/port/ is the device entry for the serial
+ port (<tt/ttyd0/, <tt/ttyd1/, etc.), <it/bps-rate/
+ is the bits-per-second rate at which the printer
+ communicates, and <it/parity/ is the parity
+ required by the printer (either <tt/even/,
+ <tt/odd/, <tt/none/, or <tt/zero/).
+ <p>
+ Here's a sample entry for a printer connected
+ via a serial line to the third serial port at
+ 19200 bps with no parity:
+<code>
+printer:dv=/dev/ttyd2:br#19200:pa=none
+</code>
+
+ <item>Connect to the printer with <tt/tip/. Type:
+<tscreen><verb>
+tip printer
+</verb></tscreen>
+ If this step doesn't work, edit the file
+ <tt>/etc/remote</tt> again and try using
+ <tt>/dev/cuaa<it/N/</tt> instead of
+ <tt>/dev/ttyd<it/N/</tt>.
+
+ <item>Send data to the printer.
+ <itemize>
+ <item>If the printer can print plain text, then
+ use <tt/lptest/. Type:
+<tscreen><verb>
+~$lptest
+</verb></tscreen>
+
+ <item>If the printer understands PostScript or
+ other printer language, then send a small
+ program to the printer. Type the program,
+ line by line, <em/very carefully/ as
+ backspacing or other editing keys may be
+ significant to the printer. You may also need
+ to type a special end-of-file key for the
+ printer so it knows it received the whole
+ program. For PostScript printers, press
+ CONTROL+D.
+
+ <p> Alternatively, you can put the program in
+ a file and type
+<tscreen>
+<tt>&tilde;&gt;<it/file/</tt>
+</tscreen>
+ where <it/file/ is the name of the file
+ containing the program. After <tt/tip/
+ sends the file, press any required
+ end-of-file key.
+ </itemize>
+ </enum>
+
+ You should see something print. Don't worry if the
+ text doesn't look right; we'll fix that later.
+
+ <sect2><heading>Enabling the Spooler: The <tt>/etc/printcap</tt> File
+ <label id="printing:printcap"></heading>
+
+ <p> At this point, your printer should be hooked up, your
+ kernel configured to communicate with it (if necessary),
+ and you've been able to send some simple data to the
+ printer. Now, we're ready to configure LPD to control
+ access to your printer.
+
+ You configure LPD by editing the file
+ <tt>/etc/printcap</tt>. The LPD spooling system reads
+ this file each time the spooler is used, so updates to the
+ file take immediate effect.
+
+ The format of the <tt/printcap/ file is straightforward.
+ Use your favorite text editor to make changes to
+ <tt>/etc/printcap</tt>. The format is identical to other
+ capability files like <tt>/usr/share/misc/termcap</tt> and
+ <tt>/etc/remote</tt>. For complete information about the
+ format, see the cgetent(3).
+
+ The simple spooler configuration consists of the following steps:
+ <enum>
+ <item>Pick a name (and a few convenient aliases) for
+ the printer, and put them in the
+ <tt>/etc/printcap</tt> file; see <ref
+ id="printing:naming" name="Naming the Printer">.
+
+ <item>Turn off header pages (which are on by default)
+ by inserting the <tt/sh/ capability; see <ref
+ id="printing:no-header-pages" name="Suppressing Header
+ Pages">.
+
+ <item>Make a spooling directory, and specify its
+ location with the <tt/sd/ capability; see <ref
+ id="printing:spooldir" name="Making the Spooling
+ Directory">.
+
+ <item>Set the <tt>/dev</tt> entry to use for the
+ printer, and note it in <tt>/etc/printcap</tt> with
+ the <tt/lp/ capability; see <ref id="printing:device"
+ name="Identifying the Printer Device">. Also, if the
+ printer's on a serial port, set up the communication
+ parameters with the <tt/fs/, <tt/fc/, <tt/xs/, and
+ <tt/xc/ capabilities; see <ref id="printing:commparam"
+ name="Configuring Spooler Communications Parameters">.
+
+ <item>Install a plain text input filter; see <ref
+ id="printing:textfilter" name="Installing the Text
+ Filter">
+
+ <item>Test the setup by printing something with the
+ <tt/lpr/ command; see <ref id="printing:trying"
+ name="Trying It Out"> and <ref
+ id="printing:troubleshooting" name="Troubleshooting">.
+ </enum>
+
+ <em/Note:/ Language-based printers, such as PostScript
+ printers, can't directly print plain text. The simple
+ setup outlined above and described in the following
+ sections assumes that if you're installing such a printer
+ you'll print only files that the printer can understand.
+
+ Users often expect that they can print plain text to any
+ of the printers installed on your system. Programs that
+ interface to LPD to do their printing usually make the
+ same assumption. If you're installing such a printer and
+ want to be able to print jobs in the printer language
+ <em/and/ print plain text jobs, you're strongly urged to
+ add an additional step to the simple setup outlined above:
+ install an automatic plain-text--to--PostScript (or other
+ printer language) conversion program. Section <ref
+ id="printing:advanced:if-conversion" name="Accomodating
+ Plain Text Jobs on PostScript Printers"> tells how to do
+ this.
+
+ <sect3><heading>Naming the Printer<label
+ id="printing:naming"></heading>
+
+ <p> The first (easy) step is to pick a name for your
+ printer. It really doesn't matter whether you choose
+ functional or whimsical names since you can also provide
+ a number aliases for the printer.
+
+ At least one of the printers specified in the
+ <tt>/etc/printcap</tt> should have the alias
+ <tt/lp/. This is the default printer's name. If users
+ don't have the PRINTER environment variable nor
+ specify a printer name on the command line of any of the
+ LPD commands, then <tt/lp/ will be the default printer
+ they get to use.
+
+ Also, it's common practice to make the last alias for a
+ printer be a full description of the printer, including
+ make and model.
+
+ Once you've picked a name and some common aliases, put
+ them in the <tt>/etc/printcap</tt> file. The name of
+ the printer should start in the leftmost column.
+ Separate each alias with a vertical bar and put a colon
+ after the last alias.
+
+ In the following example, we start with a skeletal
+ <tt>/etc/printcap</tt> that defines two printers (a
+ Diablo 630 line printer and a Panasonic KX-P4455
+ PostScript laser printer):
+<code>
+#
+# /etc/printcap for host rose
+#
+rattan|line|diablo|lp|Diablo 630 Line Printer:
+
+bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:
+</code>
+ In this example, the first printer is named <tt/rattan/
+ and has as aliases <tt/line/, <tt/diablo/, <tt/lp/, and
+ <tt/Diablo 630 Line Printer/. Since it has the alias
+ <tt/lp/, it's also the default printer. The second is
+ named <tt/bamboo/, and has as aliases <tt/ps/, <tt/PS/,
+ <tt/S/, <tt/panasonic/, and <tt/Panasonic KX-P4455
+ PostScript v51.4/.
+
+ <sect3><heading>Suppressing Header Pages<label
+ id="printing:no-header-pages"></heading>
+
+ <p> The LPD spooling system will by default print a
+ <em/header page/ for each job. The header page contains
+ the user name who requested the job, the host from which
+ the job came, and the name of the job, in nice large
+ letters. Unfortunately, all this extra text gets in the
+ way of debugging the simple printer setup, so we'll
+ suppress header pages.
+
+ To suppress header pages, add the <tt/sh/ capability to
+ the entry for the printer in
+ <tt>/etc/printcap</tt>. Here's the example
+ <tt>/etc/printcap</tt> with <tt/sh/ added:
+<code>
+#
+# /etc/printcap for host rose - no header pages anywhere
+#
+rattan|line|diablo|lp|Diablo 630 Line Printer:\
+ :sh:
+
+bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
+ :sh:
+</code>
+ Note how we used the correct format: the first line
+ starts in the leftmost column, and subsequent lines are
+ indented with a single TAB. Every line in an entry
+ except the last ends in a backslash character.
+
+ <sect3><heading>Making the Spooling Directory<label
+ id="printing:spooldir"></heading>
+
+ <p> The next step in the simple spooler setup is to make a
+ <em/spooling directory/, a directory where print jobs
+ reside until they're printed, and where a number of
+ other spooler support files live.
+
+ Because of the variable nature of spooling directories,
+ it's customary to put these directories under
+ <tt>/var/spool</tt>. It's not necessary to backup the
+ contents of spooling directories, either. Recreating
+ them is as simple as running <tt/mkdir/.
+
+ It's also customary to make the directory with a name
+ that's identical to the name of the printer, as shown
+ below:
+<tscreen>
+<tt>mkdir /var/spool/<it>printer-name</it></tt>
+</tscreen>
+ However, if you have a lot of printers on your network,
+ you might want to put the spooling directories under a
+ single directory that you reserve just for printing with
+ LPD. We'll do this for our two example printers
+ <tt/rattan/ and <tt/bamboo/:
+<tscreen><verb>
+mkdir /var/spool/lpd
+mkdir /var/spool/lpd/rattan
+mkdir /var/spool/lpd/bamboo
+</verb></tscreen>
+
+ <em/Note:/ If you're concerned about the privacy of jobs
+ that users print, you might want to protect the spooling
+ directory so it's not publicly accessible. Spooling
+ directories should be owned and be readable, writable,
+ and searchable by user daemon and group daemon, and no
+ one else. We'll do this for our example printers:
+
+<tscreen><verb>
+chown daemon.daemon /var/spool/lpd/rattan
+chown daemon.daemon /var/spool/lpd/bamboo
+chmod 770 /var/spool/lpd/rattan
+chmod 770 /var/spool/lpd/bamboo
+</verb></tscreen>
+
+ Finally, you need to tell LPD about these directories
+ using the <tt>/etc/printcap</tt> file. You specify the
+ pathname of the spooling directory with the <tt/sd/
+ capability:
+<code>
+#
+# /etc/printcap for host rose - added spooling directories
+#
+rattan|line|diablo|lp|Diablo 630 Line Printer:\
+ :sh:sd=/var/spool/lpd/rattan:
+
+bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
+ :sh:sd=/var/spool/lpd/bamboo:
+</code>
+ Note that the name of the printer starts in the first
+ column but all other entries describing the printer
+ should be indented with a tab and each line escaped with
+ a backslash.
+
+ If you don't specify a spooling directory with <tt/sd/,
+ the spooling system will use <tt>/var/spool/lpd</tt> as
+ a default.
+
+ <sect3><heading>Identifying the Printer Device<label
+ id="printing:device"></heading>
+
+ <p> In section <ref id="printing:dev-ports" name="Adding
+ /dev Entries for the Ports">, we identified which
+ entry in the <tt>/dev</tt> directory FreeBSD will use
+ to communicate with the printer. Now, we tell LPD
+ that information. When the spooling system has a job
+ to print, it will open the specified device on behalf
+ of the filter program (which is responsible for
+ passing data to the printer).
+
+ List the <tt>/dev</tt> entry pathname in the
+ <tt>/etc/printcap</tt> file using the <tt/lp/
+ capability.
+
+ In our running example, let's assume that <tt/rattan/ is
+ on the first parallel port, and <tt/bamboo/ is on a
+ sixth serial port; here are the additions to
+ <tt>/etc/printcap</tt>:
+<code>
+#
+# /etc/printcap for host rose - identified what devices to use
+#
+rattan|line|diablo|lp|Diablo 630 Line Printer:\
+ :sh:sd=/var/spool/lpd/rattan:\
+ :lp=/dev/lpt0:
+
+bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
+ :sh:sd=/var/spool/lpd/bamboo:\
+ :lp=/dev/ttyd5:
+</code>
+
+ If you don't specify the <tt/lp/ capability for a
+ printer in your <tt>/etc/printcap</tt> file, LPD uses
+ <tt>/dev/lp</tt> as a default. <tt>/dev/lp</tt>
+ currently doesn't exist in FreeBSD.
+
+ If the printer you're installing is connected to a
+ parallel port, skip to the section <ref name="Installing
+ the Text Filter" id="printing:textfilter">. Otherwise,
+ be sure to follow the instructions in the next section.
+
+ <sect3><heading>Configuring Spooler Communication
+ Parameters<label id="printing:commparam"></heading>
+
+ <p> For printers on serial ports, LPD can set up the bps
+ rate, parity, and other serial communication parameters
+ on behalf of the filter program that sends data to the
+ printer. This is advantageous since
+ <itemize>
+ <item>It lets you try different communication
+ parameters by simply editing the
+ <tt>/etc/printcap</tt> file; you don't have to
+ recompile the filter program.
+
+ <item>It enables the spooling system to use the same
+ filter program for multiple printers which may have
+ different serial communication settings.
+ </itemize>
+
+ The following <tt>/etc/printcap</tt> capabilities
+ control serial communication parameters of the device
+ listed in the <tt/lp/ capability:
+ <descrip>
+ <tag/<tt>br&num;<it/bps-rate/</tt>/
+
+ Sets the communications speed of the device to
+ <it/bps-rate/, where <it/bps-rate/ can be 50, 75,
+ 110, 134, 150, 200, 300, 600, 1200, 1800, 2400,
+ 4800, 9600, 19200, or 38400 bits-per-second.
+
+ <tag/<tt>fc&num;<it/clear-bits/</tt>/
+
+ Clears the flag bits <it/clear-bits/ in the
+ <tt/sgttyb/ structure after opening the device.
+
+ <tag/<tt>fs&num;<it/set-bits/</tt>/
+
+ Sets the flag bits <it/set-bits/ in the <tt/sgttyb/
+ structure.
+
+ <tag/<tt>xc&num;<it/clear-bits/</tt>/
+
+ Clears local mode bits <it/clear-bits/ after opening
+ the device.
+
+ <tag/<tt>xs&num;<it/set-bits/</tt>/
+
+ Sets local mode bits <it/set-bits/.
+ </descrip>
+ For more information on the bits for the <tt/fc/,
+ <tt/fs/, <tt/xc/, and <tt/xs/ capabilities, see the file
+ <tt>/usr/include/sys/ioctl_compat.h</tt>.
+
+ When LPD opens the device specified by the <tt/lp/
+ capability, it reads the flag bits in the <tt/sgttyb/
+ structure; it clears any bits in the <tt/fc/ capability,
+ then sets bits in the <tt/fs/ capability, then applies
+ the resultant setting. It does the same for the local
+ mode bits as well.
+
+ Let's add to our example printer on the sixth serial
+ port. We'll set the bps rate to 38400. For the flag
+ bits, we'll set the TANDEM, ANYP, LITOUT, FLUSHO, and
+ PASS8 flags. For the local mode bits, we'll set the
+ LITOUT and PASS8 flags:
+<tscreen><verb>
+bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
+ :sh:sd=/var/spool/lpd/bamboo:\
+ :lp=/dev/ttyd5:fs#0x82000c1:xs#0x820:
+</verb></tscreen>
+
+
+ <sect3><heading>Installing the Text Filter<label
+ id="printing:textfilter"></heading>
+
+ <p> We're now ready to tell LPD what text filter to use to
+ send jobs to the printer. A <em/text filter/, also
+ known as an <em/input filter/, is a program that LPD
+ runs when it has a job to print. When LPD runs the text
+ filter for a printer, it sets the filter's standard
+ input to the job to print, and its standard output to
+ the printer device specified with the <tt/lp/
+ capability. The filter is expected to read the job from
+ standard input, peform any necessary translation for the
+ printer, and write the results to standard output, which
+ will get printed. For more information on the text
+ filter, see section <ref id="printing:advanced:filters"
+ name="Filters">.
+
+ For our simple printer setup, the text filter can be a
+ small shell script that just executes <tt>/bin/cat</tt>
+ to send the job to the printer. FreeBSD comes with
+ another filter called <tt/lpf/ that handles backspacing
+ and underlining for printers that might not deal with
+ such character streams well. And, of course, you can
+ use any other filter program you want. The filter
+ <tt/lpf/ is described in detail in section <ref
+ id="printing:advanced:lpf" name="lpf: a Text Filter">.
+
+ First, let's make the shell script
+ <tt>/usr/local/libexec/if-simple</tt> be a simple text
+ filter. Put the following text into that file with your
+ favorite text editor:
+<code>
+#!/bin/sh
+#
+# if-simple - Simple text input filter for lpd
+# Installed in /usr/local/libexec/if-simple
+#
+# Simply copies stdin to stdout. Ignores all filter arguments.
+
+/bin/cat &ero;&ero; exit 0
+exit 2
+</code>
+ Make the file executable:
+<tscreen><verb>
+chmod 555 /usr/local/libexec/if-simple
+</verb></tscreen>
+
+ And then tell LPD to use it by specifying it with the
+ <tt/if/ capability in <tt>/etc/printcap</tt>. We'll add
+ it to the two printers we have so far in the example
+ <tt>/etc/printcap</tt>:
+<code>
+#
+# /etc/printcap for host rose - added text filter
+#
+rattan|line|diablo|lp|Diablo 630 Line Printer:\
+ :sh:sd=/var/spool/lpd/rattan:\
+ :lp=/dev/lpt0:\
+ :if=/usr/local/libexec/if-simple:
+
+bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
+ :sh:sd=/var/spool/lpd/bamboo:\
+ :lp=/dev/ttyd5:fs#0x82000e1:xs#0x820:\
+ :if=/usr/local/libexec/if-simple:
+</code>
+
+ <sect3><heading>Trying It Out<label id="printing:trying"></heading>
+
+ <p> You've reached the end of the simple LPD setup.
+ Unfortunately, congratulations are not quite yet in
+ order, since we've still got to test the setup and
+ correct any problems. To test the setup, try printing
+ something. To print with the LPD system, you use the
+ command <tt/lpr/, which submits a job for printing.
+
+ You can combine <tt/lpr/ with the <tt/lptest/ program,
+ introduced in section <ref id="printing:testing"
+ name="Checking Printer Communications"> to generate some
+ test text.
+
+ <bf>To test the simple LPD setup:</bf>
+
+ <p> Type:
+<tscreen>
+<tt>lptest 20 5 | lpr -P<it/printer-name/</tt>
+</tscreen>
+ where <it/printer-name/ is a the name of a printer (or
+ an alias) specified in <tt>/etc/printcap</tt>. To test
+ the default printer, type <tt/lpr/ without any <tt/-P/
+ argument. Again, if you're testing a printer that
+ expects PostScript, send a PostScript program in that
+ language instead of using <tt/lptest/. You can do so by
+ putting the program in a file and typing <tt/lpr
+ <it/file//.
+
+ For a PostScript printer, you should get the results
+ of the program. If you're using <tt/lptest/, then your
+ results should look like the following:
+
+<tscreen><verb>
+!"#$%&ero;'()*+,-./01234
+"#$%&ero;'()*+,-./012345
+#$%&ero;'()*+,-./0123456
+$%&ero;'()*+,-./01234567
+%&ero;'()*+,-./012345678
+</verb></tscreen>
+
+ To further test the printer, try downloading larger
+ programs (for language-based printers) or running
+ <tt/lptest/ with different arguments. For example,
+ <tt/lptest 80 60/ will produce 60 lines of 80 characters
+ each.
+
+ If the printer didn't work, see the next section, <ref
+ id="printing:troubleshooting" name="Troubleshooting">.
+
+ <sect3><heading>Troubleshooting<label
+ id="printing:troubleshooting"></heading>
+
+ <p> After performing the simple test with <tt/lptest/, you
+ might've gotten one of the following results instead of
+ the correct printout:
+ <descrip>
+ <tag/It worked, after awhile; or, it didn't eject a full sheet./
+
+ The printer printed the above, but it sat for awhile
+ and did nothing. In fact, you might've needed to
+ press a PRINT REMAINING or FORM FEED button on the
+ printer to get any results to appear.
+
+ If this is the case, the printer was probably
+ waiting to see if there was any more data for your
+ job before it printed anything. To fix this
+ problem, you can have the text filter send a FORM
+ FEED character (or whatever is necessary) to the
+ printer. This is usually sufficient to have the
+ printer immediately print any text remaining in its
+ internal buffer. It's also useful to make sure each
+ print job ends on a full sheet, so the next job
+ doesn't start somewhere on the middle of the last
+ page of the previous job.
+
+ The following replacement for the shell script
+ <tt>/usr/local/libexec/if-simple</tt> prints a form
+ feed after it sends the job to the printer:
+<code>
+#!/bin/sh
+#
+# if-simple - Simple text input filter for lpd
+# Installed in /usr/local/libexec/if-simple
+#
+# Simply copies stdin to stdout. Ignores all filter arguments.
+# Writes a form feed character (\f) after printing job.
+
+/bin/cat &ero;&ero; printf "\f" &ero;&ero; exit 0
+exit 2
+</code>
+
+ <tag/It produced the ``staircase effect.''/
+
+ You got the following on paper:
+<tscreen><verb>
+!"#$%&ero;'()*+,-./01234
+ "#$%&ero;'()*+,-./012345
+ #$%&ero;'()*+,-./0123456
+ $%&ero;'()*+,-./01234567
+</verb></tscreen>
+ You've become another victim of the <em/staircase
+ effect/, caused by conflicting interpretations of
+ what characters should indicate a new-line.
+ UNIX-style operating systems use a single character:
+ ASCII code 10, the line feed (LF). MS-DOS, OS/2,
+ and others uses a pair of characters, ASCII code 10
+ <em/and/ ASCII code 13 (the carriage return or CR).
+ Many printers use the MS-DOS convention for
+ representing new-lines.
+
+ When you print with FreeBSD, your text used just the
+ line feed character. The printer, upon seeing a
+ line feed character, advanced the paper one line,
+ but maintained the same horizontal position on the
+ page for the next character to print. That's what
+ the carriage return is for: to move the location of
+ the next character to print to the left edge of the
+ paper.
+
+ Here's what FreeBSD wants your printer to do:
+<tscreen><verb>
+Printer received CR Printer prints CR
+Printer received LF Printer prints CR + LF
+</verb></tscreen>
+
+ Here are some ways to achieve this:
+ <itemize>
+ <item>Use the printer's configuration switches or
+ control panel to alter its interpretation of
+ these characters. Check your printer's manual
+ to find out how to do this.
+
+ <p> <em/Note:/ If you boot your system into
+ other operating systems besides FreeBSD, you
+ may have to <em/reconfigure/ the printer to
+ use a an interpretation for CR and LF
+ characters that those other operating systems
+ use. You might prefer one of the other
+ solutions, below.
+
+ <item>Have FreeBSD's serial line driver
+ automatically convert LF to CR+LF. Of course,
+ this works with printers on serial ports
+ <em/only/. To enable this feature, set the
+ CRMOD bit in <tt/fs/ capability in the
+ <tt>/etc/printcap</tt> file for the printer.
+
+ <item>Send an <em/escape code/ to the printer to
+ have it temporarily treat LF characters
+ differently. Consult your printer's manual for
+ escape codes that your printer might support.
+ When you find the proper escape code, modify the
+ text filter to send the code first, then send
+ the print job.
+
+ <p> Here's an example text filter for printers
+ that understand the Hewlett-Packard PCL escape
+ codes. This filter makes the printer treat LF
+ characters as a LF and CR; then it sends the
+ job; then it sends a form feed to eject the
+ last page of the job. It should work with
+ nearly all Hewlett Packard printers.
+
+<code>
+#!/bin/sh
+#
+# hpif - Simple text input filter for lpd for HP-PCL based printers
+# Installed in /usr/local/libexec/hpif
+#
+# Simply copies stdin to stdout. Ignores all filter arguments.
+# Tells printer to treat LF as CR+LF. Writes a form feed character
+# after printing job.
+
+printf "\033&ero;k2G" &ero;&ero; cat &ero;&ero; printf "\f" &ero;&ero; exit 0
+exit 2
+</code>
+
+ Here's an example <tt>/etc/printcap</tt> from
+ a host called orchid. It has a single printer
+ attached to its first parallel port, a Hewlett
+ Packard LaserJet 3Si named <tt/teak/. It's
+ using the above script as its text filter:
+<code>
+#
+# /etc/printcap for host orchid
+#
+teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\
+ :lp=/dev/lpt0:sh:sd=/var/spool/lpd/teak:mx#0:\
+ :if=/usr/local/libexec/hpif:
+</code>
+ </itemize>
+
+ <tag/It overprinted each line./
+
+ The printer never advanced a line. All of the lines
+ of text were printed on top of each other on one
+ line.
+
+ This problem is the ``opposite'' of the staircase
+ effect, described above, and is much rarer.
+ Somewhere, the LF characters that FreeBSD uses to
+ end a line are being treated as CR characters to
+ return the print location to the left edge of the
+ paper, but not also down a line.
+
+ Use the printer's configuration switches or control
+ panel to enforce the following interpretation of LF
+ and CR characters:
+<tscreen><verb>
+Printer received CR Printer prints CR
+Printer received LF Printer prints CR + LF
+</verb></tscreen>
+
+ <tag/The printer lost characters./
+
+ While printing, the printer didn't print a few
+ characters in each line. The problem might've
+ gotten worse as the printer ran, losing more and
+ more characters.
+
+ The problem is that the printer can't keep up with
+ the speed at which the computer sends data over a
+ serial line. (This problem shouldn't occur with
+ printers on parallel ports.) There are two ways to
+ overcome the problem:
+ <itemize>
+ <item>If the printer supports XON/XOFF flow
+ control, have FreeBSD use it by specifying the
+ TANDEM bit in the <tt/fs/ capability.
+
+ <item>If the printer supports carrier flow
+ control, specify the MDMBUF bit in the <tt/fs/
+ capability. Make sure the cable connecting the
+ printer to the computer is correctly wired for
+ carrier flow control.
+
+ <item>If the printer doesn't support any flow
+ control, use some combination of the NLDELAY,
+ TBDELAY, CRDELAY, VTDELAY, and BSDELAY bits in
+ the <tt/fs/ capability to add appropriate delays
+ to the stream of data sent to the printer.
+ </itemize>
+
+ <tag/It printed garbage./
+
+ The printer printed what appeared to be random
+ garbage, but not the desired text.
+
+ This is usually another symptom of incorrect
+ communications parameters with a serial printer.
+ Double-check the bps rate in the <tt/br/ capability,
+ and the parity bits in the <tt/fs/ and <tt/fc/
+ capabilities; make sure the printer is using the
+ same settings as specified in the
+ <tt>/etc/printcap</tt> file.
+
+ <tag/Nothing happened./
+
+ If nothing happened, the problem is probably within
+ FreeBSD and not the hardware. Add the log file
+ (<tt/lf/) capability to the entry for the printer
+ you're debugging in the <tt>/etc/printcap</tt> file.
+ For example, here's the entry for <tt/rattan/, with
+ the <tt/lf/ capability:
+<tscreen><verb>
+rattan|line|diablo|lp|Diablo 630 Line Printer:\
+ :sh:sd=/var/spool/lpd/rattan:\
+ :lp=/dev/lpt0:\
+ :if=/usr/local/libexec/if-simple:\
+ :lf=/var/log/rattan.log
+</verb></tscreen>
+ Then, try printing again. Check the log file (in
+ our example, <tt>/var/log/rattan.log</tt>) to see
+ any error messages that might appear. Based on the
+ messages you see, try to correct the problem.
+
+ If you don't specify a <tt/lf/ capability, LPD uses
+ <tt>/dev/console</tt> as a default.
+ </descrip>
+
+ <sect><heading>Using Printers<label id="printing:using"></heading>
+
+ <p> This section tells you how to use printers you've setup with
+ FreeBSD. Here's an overview of the user-level commands:
+ <descrip>
+ <tag/<tt/lpr//
+ Print jobs
+
+ <tag/<tt/lpq//
+ Check printer queues
+
+ <tag/<tt/lprm//
+ Remove jobs from a printer's queue
+
+ </descrip>
+
+ There's also an administrative command, <tt/lpc/, described in
+ the section <ref id="printing:lpc" name="Administrating the
+ LPD Spooler">, used to control printers and their queues.
+
+ All three of the commands <tt/lpr/, <tt/lprm/, and <tt/lpq/
+ accept an option ``<tt/-P/ <it/printer-name/'' to specify on
+ which printer/queue to operate, as listed in the
+ <tt>/etc/printcap</tt> file. This enables you to submit,
+ remove, and check on jobs for various printers. If you don't
+ use the <tt/-P/ option, then these commands use the printer
+ specified in the PRINTER environment variable. Finally, if
+ you don't have a PRINTER environment variable, these commands
+ default to the printer named <tt/lp/.
+
+ Hereafter, the terminology <em/default printer/ means the
+ printer named in the PRINTER environment variable, or the
+ printer named <tt/lp/ when there's no PRINTER environment
+ variable.
+
+ <sect1><heading>Printing Jobs<label id="printing:lpr"></heading>
+ <p>
+
+ To print files, type
+<tscreen>
+<tt>lpr <it/filename.../</tt>
+</tscreen>
+ This prints each of the listed files to the default printer.
+ If you list no files, <tt/lpr/ reads data to print from
+ standard input. For example, this command prints some
+ important system files:
+<tscreen><verb>
+lpr /etc/host.conf /etc/hosts.equiv
+</verb></tscreen>
+ To select a specific printer, type
+<tscreen>
+<tt>lpr -P <it/printer-name/ <it/filename.../</tt>
+</tscreen>
+ This example prints a long listing of the current directory
+ to the printer named <tt/rattan/:
+<tscreen><verb>
+ls -l | lpr -P rattan
+</verb></tscreen>
+ Because no files were listed for the <tt/lpr/ command,
+ <tt/lpr/ read the data to print from standard input, which
+ was the output of the <tt/ls -l/ command.
+
+ The <tt/lpr/ command can also accept a wide variety of
+ options to control formatting, apply file conversions,
+ generate multiple copies, and so forth. For more
+ information, see the section <ref id="printing:lpr:options"
+ name="Printing Options">.
+
+ <sect1><heading>Checking Jobs<label id="printing:lpq"></heading>
+
+ <p> When you print with <tt/lpr/, the data you wish to print
+ is put together in a package called a <em/print job/, which
+ is sent to the LPD spooling system. Each printer has a
+ queue of jobs, and your job waits in that queue along with
+ other jobs from yourself and from other users. The printer
+ prints those jobs in a first-come, first-served order.
+
+ To display the queue for the default printer, type <tt/lpq/.
+ For a specific printer, use the <tt/-P/ option. For
+ example, the command
+<tscreen><verb>
+lpq -P bamboo
+</verb></tscreen>
+ shows the queue for the printer named <tt/bamboo/. Here's
+ an example of the output of the <tt/lpq/ command:
+<tscreen><verb>
+bamboo is ready and printing
+Rank Owner Job Files Total Size
+active kelly 9 /etc/host.conf, /etc/hosts.equiv 88 bytes
+2nd kelly 10 (standard input) 1635 bytes
+3rd mary 11 ... 78519 bytes
+</verb></tscreen>
+ This shows three jobs in the queue for <tt/bamboo/. The
+ first job, submitted by user kelly, got assigned <em/job
+ number/ 9. Every job for a printer gets a unique job
+ number. Most of the time you can ignore the job number, but
+ you'll need it if you want to cancel the job; see section
+ <ref id="printing:lprm" name="Removing Jobs"> for details.
+
+ Job number nine consists of two files; multiple files given
+ on the <tt/lpr/ command line are treated as part of a single
+ job. It's the currently active job (note the word
+ <tt/active/ under the ``Rank'' column), which means the
+ printer should be currently printing that job. The second
+ job consists of data passed as the standard input to the
+ <tt/lpr/ command. The third job came from user mary; it's a
+ much larger job. The pathname of the files she's trying to
+ print is too long to fit, so the <tt/lpq/ command just shows
+ three dots.
+
+ The very first line of the output from <tt/lpq/ is also
+ useful: it tells what the printer is currently doing (or at
+ least what LPD thinks the printer is doing).
+
+ The <tt/lpq/ command also support a <tt/-l/ option to
+ generate a detailed long listing. Here's an example of
+ <tt/lpq -l/:
+<tscreen><verb>
+waiting for bamboo to become ready (offline ?)
+
+kelly: 1st [job 009rose]
+ /etc/host.conf 73 bytes
+ /etc/hosts.equiv 15 bytes
+
+kelly: 2nd [job 010rose]
+ (standard input) 1635 bytes
+
+mary: 3rd [job 011rose]
+ /home/orchid/mary/research/venus/alpha-regio/mapping 78519 bytes
+</verb></tscreen>
+
+ <sect1><heading>Removing Jobs<label
+ id="printing:lprm"></heading>
+
+ <p> If you change your mind about printing a job, you can
+ remove the job from the queue with the <tt/lprm/ command.
+ Often, you can even use <tt/lprm/ to remove an active job,
+ but some or all of the job might still get printed.
+
+ To remove a job from the default printer, first use <tt/lpq/
+ to find the job number. Then type
+<tscreen>
+<tt/lprm <it/job-number//
+</tscreen>
+ To remove the job from a specific printer, add the <tt/-P/
+ option. The following command removes job number 10 from
+ the queue for the printer <tt/bamboo/:
+<tscreen><verb>
+lprm -P bamboo 10
+</verb></tscreen>
+ The <tt/lprm/ command has a few shortcuts:
+ <descrip>
+ <tag/lprm -/
+
+ Removes all jobs (for the default printer) belonging to
+ you.
+
+ <tag/lprm <it/user//
+
+ Removes all jobs (for the default printer) belonging to
+ <it/user/. The superuser can remove other users' jobs;
+ you can remove only your own jobs.
+
+ <tag/lprm/
+
+ With no job number, user name, or ``<tt/-/'' appearing
+ on the command line, <tt/lprm/ removes the currently
+ active job on the default printer, if it belongs to
+ you. The superuser can remove any active job.
+ </descrip>
+
+ Just use the <tt/-P/ option with the above shortcuts to
+ operate on a specific printer instead of the default. For
+ example, the following command removes all jobs for the
+ current user in the queue for the printer named <tt/rattan/:
+
+<tscreen><verb>
+lprm -P rattan -
+</verb></tscreen>
+
+ <em/Note:/ If you're working in a networked environment,
+ <tt/lprm/ will let you remove jobs only from the host from
+ which the jobs were submitted, even if the same printer is
+ available from other hosts. The following command sequence
+ demonstrates this:
+<code>
+rose% lpr -P rattan myfile
+rose% rlogin orchid
+orchid% lpq -P rattan
+Rank Owner Job Files Total Size
+active seeyan 12 ... 49123 bytes
+2nd kelly 13 myfile 12 bytes
+orchid% lprm -P rattan 13
+rose: Permission denied
+orchid% logout
+rose% lprm -P rattan 13
+dfA013rose dequeued
+cfA013rose dequeued
+rose%
+</code>
+
+ <sect1><heading>Beyond Plain Text: Printing Options<label
+ id="printing:lpr:options"></heading>
+
+ <p> The <tt/lpr/ command supports a number of options that
+ control formatting text, converting graphic and other file
+ formats, producing multiple copies, handling of the job, and
+ more. This section describes the options.
+
+ <sect2><heading>Formatting and Conversion Options<label
+ id="printing:lpr:options:format"></heading>
+
+ <p> The following <tt/lpr/ options control formatting of the
+ files in the job. Use these options if the job doesn't
+ contain plain text or if you want plain text formatted
+ through the <tt/pr/ utility.
+
+ For example, the following command prints a DVI file (from
+ the TeX typesetting system) named <tt/fish-report.dvi/
+ to the printer named <tt/bamboo/:
+<tscreen><verb>
+lpr -P bamboo -d fish-report.dvi
+</verb></tscreen>
+ These options apply to every file in the job, so you can't
+ mix (say) DVI and ditroff files together in a job.
+ Instead, submit the files as separate jobs, using a
+ different conversion option for each job.
+
+ <em/Note:/ All of these options except <tt/-p/ and <tt/-T/
+ require conversion filters installed for the destination
+ printer. For example, the <tt/-d/ option requires the DVI
+ conversion filter. Section <ref
+ id="printing:advanced:convfilters" name="Conversion
+ Filters"> gives details.
+
+ <descrip>
+ <tag/<tt/-c// Print cifplot files.
+
+ <tag/<tt/-d// Print DVI files.
+
+ <tag/<tt/-f// Print FORTRAN text files.
+
+ <tag/<tt/-g// Print plot data.
+
+ <tag/<tt/-i <it/number///
+
+ Indent the output by <it/number/ columns; if you omit
+ <it/number/, indent by 8 columns. This option works
+ only with certain conversion filters.
+
+ <em/Note:/ Don't put any space between the <tt/-i/ and
+ the number.
+
+ <tag/<tt/-l//
+
+ Print literal text data, including control characters.
+
+ <tag/<tt/-n// Print ditroff (device indepdendent troff) data.
+
+ <tag/-p/
+
+ Format plain text with <tt/pr/ before printing. See
+ pr(1) for more information.
+
+ <tag/<tt/-T <it/title///
+
+ Use <it/title/ on the <tt/pr/ header instead of the
+ file name. This option has effect only when used with
+ the <tt/-p/ option.
+
+ <tag/<tt/-t// Print troff data.
+
+ <tag/<tt/-v// Print raster data.
+
+ </descrip>
+
+ Here's an example: this command prints a nicely
+ formatted version of the <tt/ls/ manual page on the
+ default printer:
+<tscreen><verb>
+zcat /usr/share/man/man1/ls.1.gz | troff -t -man | lpr -t
+</verb></tscreen>
+ The <tt/zcat/ command uncompresses the source of the
+ <tt/ls/ manual page and passes it to the <tt/troff/
+ command, which formats that source and makes GNU troff
+ output and passes it to <tt/lpr/, which submits the job to
+ the LPD spooler. Because we used the <tt/-t/ option to
+ <tt/lpr/, the spooler will convert the GNU troff output
+ into a format the default printer can understand when it
+ prints the job.
+
+ <sect2><heading>Job Handling Options<label
+ id="printing:lpr:options:job-handling"></heading>
+
+ <p> The following options to <tt/lpr/ tell LPD to handle the
+ job specially:
+
+ <descrip>
+ <tag/-&num; <it/copies//
+
+ Produce a number of <it/copies/ of each file in the
+ job instead of just one copy. An administrator may
+ disable this option to reduce printer wear-and-tear
+ and encourage photocopier usage. See section <ref
+ id="printing:advanced:restricting:copies"
+ name="Restricting Multiple Copies">.
+
+ <p> This example prints three copies of <tt/parser.c/
+ followed by three copies of <tt/parser.h/ to the
+ default printer:
+<tscreen><verb>
+lpr -#3 parser.c parser.h
+</verb></tscreen>
+
+ <tag/-m/
+
+ Send mail after completing the print job. With this
+ option, the LPD system will send mail to your account
+ when it finishes handling your job. In its message,
+ it will tell you if the job completed successfully or
+ if there was an error, and (often) what the error was.
+
+ <tag/-s/ Don't copy the files to the spooling directory,
+ but make symbolic links to them instead.
+
+ If you're printing a large job, you probably want to
+ use this option. It saves space in the spooling
+ directory (your job might overflow the free space on
+ the filesystem where the spooling directory resides).
+ It saves time as well since LPD won't have to copy
+ each and every byte of your job to the spooling
+ directory.
+
+ There is a drawback, though: since LPD will refer to
+ the original files directly, you can't modify or
+ remove them until they have been printed.
+
+ <em/Note:/ If you're printing to a remote printer, LPD
+ will eventually have to copy files from the local host
+ to the remote host, so the <tt/-s/ option will save
+ space only on the local spooling directory, not the
+ remote. It's still useful, though.
+
+ <tag/-r/
+
+ Remove the files in the job after copying them to the
+ spooling directory, or after printing them with the
+ <tt/-s/ option. Be careful with this option!
+
+ </descrip>
+
+ <sect2><heading>Header Page Options<label
+ id="printing:lpr:options:misc"></heading>
+
+ <p> These options to <tt/lpr/ adjust the text that normally
+ appears on a job's header page. If header pages are
+ suppressed for the destination printer, these options have
+ no effect. See section <ref name="Header Pages"
+ id="printing:advanced:header-pages"> for information about
+ setting up header pages.
+
+ <descrip>
+ <tag/-C <it/text//
+
+ Replace the hostname on the header page with
+ <it/text/. The hostname is normally the name of the
+ host from which the job was submitted.
+
+ <tag/-J <it/text//
+
+ Replace the job name on the header page with
+ <it/text/. The job name is normally the name of the
+ first file of the job, or ``stdin'' if you're printing
+ standard input.
+
+ <tag/-h/
+
+ Do not print any header page. <em/Note:/ At some
+ sites, this option may have no effect due to the way
+ header pages are generated. See <ref name="Header
+ Pages" id="printing:advanced:header-pages"> for
+ details.
+
+ </descrip>
+
+ <sect1><heading>Administrating Printers<label
+ id="printing:lpc"></heading>
+
+ <p> As an administrator for your printers, you've had to
+ install, set up, and test them. Using the <tt/lpc/ command,
+ you can interact with your printers in yet more ways. With
+ <tt/lpc/, you can
+
+ <itemize>
+ <item>Start and stop the printers
+
+ <item>Enable and disable their queues
+
+ <item>Rearrange the order of the jobs in each queue.
+ </itemize>
+
+ First, a note about terminology: if a printer is
+ <em/stopped/, it won't print anything in its queue. Users
+ can still submit jobs, which will wait in the queue until
+ the printer is <em/started/ or the queue is cleared.
+
+ If a queue is <em/disabled/, no user (except root) can
+ submit jobs for the printer. An <em/enabled/ queue allows
+ jobs to be submitted. A printer can be <em/started/ for a
+ disabled queue, in which case it'll continue to print jobs
+ in the queue until the queue is empty.
+
+ In general, you have to have root privileges to use the
+ <tt/lpc/ command. Ordinary users can use the <tt/lpc/
+ command to get printer status and to restart a hung printer
+ only.
+
+ Here is a summary of the <tt/lpc/ commands. Most of the
+ commands takes a <it/printer-name/ argument to tell on which
+ printer to operate. You can use <tt/all/ for the
+ <it/printer-name/ to mean all printers listed in
+ <tt>/etc/printcap</tt>.
+
+ <descrip>
+ <tag/<tt/abort <it/printer-name///
+
+ Cancel the current job and stop the printer. Users can
+ still submit jobs if the queue's enabled.
+
+ <tag/<tt/clean <it/printer-name///
+
+ Remove old files from the printer's spooling directory.
+ Occasionally, the files that make up a job aren't
+ properly removed by LPD, particularly if there have been
+ errors during printing or a lot of administrative
+ activity. This command finds files that don't belong in
+ the spooling directory and removes them.
+
+ <tag/<tt/disable <it/printer-name///
+
+ Disable queuing of new jobs. If the printer's started,
+ it will continue to print any jobs remaining in the
+ queue. The superuser (root) can always submit jobs,
+ even to a disabled queue.
+
+ This command is useful while you're testing a new
+ printer or filter installation: disable the queue and
+ submit jobs as root. Other users won't be able to
+ submit jobs until you complete your testing and reenable
+ the queue with the <tt/enable/ command.
+
+ <tag/<tt/down <it/printer-name/ <it/message...///
+
+ Take a printer down. Equivalent to <tt/disable/
+ followed by <tt/stop/. The <it/message/ appears as the
+ printer's status whenever a user checks the printer's
+ queue with <tt/lpq/ or status with <tt/lpc status/.
+
+ <tag/<tt/enable <it/printer-name///
+
+ Enable the queue for a printer. Users can submit jobs
+ but the printer won't print anything until it's started.
+
+ <tag/<tt/help <it/command-name///
+
+ Print help on the command <it/command-name/. With no
+ <it/command-name/, print a summary of the commands
+ available.
+
+ <tag/<tt/restart <it/printer-name///
+
+ Start the printer. Ordinary users can use this command
+ if some extraordinary circumstance hangs LPD, but they
+ can't start a printer stopped with either the <tt/stop/
+ or <tt/down/ commands. The <tt/restart/ command is
+ equivalent to <tt/abort/ followed by <tt/start/.
+
+ <tag/<tt/start <it/printer-name///
+
+ Start the printer. The printer will print jobs in its
+ queue.
+
+ <tag/<tt/stop <it/printer-name///
+
+ Stop the printer. The printer will finish the current
+ job and won't print anything else in its queue. Even
+ though the printer is stopped, users can still submit
+ jobs to an enabled queue.
+
+ <tag/<tt/topq <it/printer-name/ <it/job-or-username...///
+
+ Rearrange the queue for <it/printer-name/ by placing the
+ jobs with the listed <it/job/ numbers or the jobs
+ belonging to <it/username/ at the top of the queue. For
+ this command, you can't use <tt/all/ as the
+ <it/printer-name/.
+
+ <tag/<tt/up <it/printer-name///
+
+ Bring a printer up; the opposite of the <tt/down/
+ command. Equivalent to <tt/start/ followed by
+ <tt/enable/.
+
+ </descrip>
+
+ <tt/lpc/ accepts the above commands on the command line. If
+ you don't enter any commands, <tt/lpc/ enters an interactive
+ mode, where you can enter commands until you type <tt/exit/,
+ <tt/quit/, or end-of-file.
+
+ <sect><heading>Advanced Printer Setup<label
+ id="printing:advanced"></heading>
+
+ <p> This section describes filters for printing specially
+ formatted files, header pages, printing across networks, and
+ restricting and accounting for printer usage.
+
+ <sect1><heading>Filters<label
+ id="printing:advanced:filter-intro"></heading>
+
+ <p> Although LPD handles network protocols, queuing, access
+ control, and other aspects of printing, most of the
+ <em/real/ work happens in the <em/filters/. Filters are
+ programs that communicate with the printer and handle its
+ device dependencies and special requirements. In the simple
+ printer setup, we installed a plain text filter---an
+ extremely simple one that should work with most printers
+ (section <ref id="printing:textfilter" name="Installing the
+ Text Filter">).
+
+ However, in order to take advantage of format conversion,
+ printer accounting, specific printer quirks, and so on, you
+ should understand how filters work. It will ultimately be
+ the filter's responsibility to handle these aspects. And the
+ bad news is that most of the time <em/you/ have to provide
+ filters yourself. The good news is that many are generally
+ available; when they're not, they're usually easy to write.
+
+ Also, FreeBSD comes with one, <tt>/usr/libexec/lpr/lpf</tt>,
+ that works with many printers that can print plain text.
+ (It handles backspacing and tabs in the file, and does
+ accounting, but that's about all it does.) There are also
+ several filters and filter components in the FreeBSD ports
+ collection.
+
+ Here's what you'll find in this section:
+
+ <itemize>
+ <item>Section <ref id="printing:advanced:filters"
+ name="How Fitlers Work">, tries to give an overview of a
+ filter's role in the printing process. You should read
+ this section to get an understanding of what's happening
+ ``under the hood'' when LPD uses filters. This
+ knowledge could help you anticipate and debug problems
+ you might encounter as you install more and more filters
+ on each of your printers.
+
+ <item>LPD expects every printer to be able to print plain
+ text by default. This presents a problem for PostScript
+ (or other language-based printers) which can't directly
+ print plain text. Section <ref
+ id="printing:advanced:if-conversion" name="Accomodating
+ Plain Text Jobs on PostScript Printers"> tells you what
+ you should do to overcome this problem. I recommend
+ reading this section if you have a PostScript printer.
+
+ <item>PostScript is a popular output format for many
+ programs. Even some people (myself included) write
+ PostScript code directly. But PostScript printers are
+ expensive. Section <ref id="printing:advanced:ps"
+ name="Simulating PostScript on Non-PostScript Printers">
+ tells how you can further modify a printer's text filter
+ to accept and print PostScript data on a
+ <em/non-PostScript/ printer. I recommend reading this
+ section if you don't have a PostScript printer.
+
+ <item>Section <ref id="printing:advanced:convfilters"
+ name="Conversion Filters"> tells about a way you can
+ automate the conversion of specific file formats, such
+ as graphic or typesetting data, into formats your
+ printer can understand. After reading this section,
+ you should be able to set up your printers such that
+ users can type <tt/lpr -t/ to print troff data, or
+ <tt/lpr -d/ to print TeX DVI data, or <tt/lpr -v/ to
+ print raster image data, and so forth. I recommend
+ reading this section.
+
+ <item>Section <ref id="printing:advanced:of" name="Output
+ Filters"> tells all about a not often used feature of
+ LPD: output filters. Unless you're printing header
+ pages (see <ref id="printing:advanced:header-pages"
+ name="Header Pages">), you can probably skip that
+ section altogether.
+
+ <item>Section <ref id="printing:advanced:lpf" name="lpf:
+ a Text Filter"> describes <tt/lpf/, a fairly complete
+ if simple text filter for line printers (and laser
+ printers that act like line printers) that comes with
+ FreeBSD. If you need a quick way to get printer
+ accounting working for plain text, or if you have a
+ printer which emits smoke when it sees backspace
+ characters, you should definitely consider <tt/lpf/.
+ </itemize>
+
+ <sect2><heading>How Filters Work<label
+ id="printing:advanced:filters"></heading>
+
+ <p> As mentioned before, a filter is an executable program
+ started by LPD to handle the device-dependent part of
+ communicating with the printer.
+
+ When LPD wants to print a file in a job, it starts a
+ filter program. It sets the filter's standard input to
+ the file to print, its standard output to the printer, and
+ its standard error to the error logging file (specified in
+ the <tt/lf/ capability in <tt>/etc/printcap</tt>, or
+ <tt>/dev/console</tt> by default).
+
+ Which filter LPD starts and the filter's arguments depend
+ on what's listed in the <tt>/etc/printcap</tt> file and
+ what arguments the user specified for the job on the
+ <tt/lpr/ command line. For example, if the user typed
+ <tt/lpr -t/, LPD would start the troff filter, listed in
+ the <tt/tf/ capability for the destination printer. If
+ the user wanted to print plain text, it would start the
+ <tt/if/ filter (this is mostly true: see <ref
+ id="printing:advanced:of" name="Output Filters"> for
+ details).
+
+ There are three kinds filters you can specify in
+ <tt>/etc/printcap</tt>:
+ <itemize>
+ <item>The <em/text filter/, confusingly called the
+ <em/input filter/ in LPD documentation, handles
+ regular text printing. Think of it as the default
+ filter. LPD expects every printer to be able to print
+ plain text by default, and it's the text filter's job
+ to make sure backspaces, tabs, or other special
+ characters don't confuse the printer.
+
+ If you're in an environment where you have to account
+ for printer usage, the text filter must also account
+ for pages printed, usually by counting the number of
+ lines printed and comparing that to the number of
+ lines per page the printer supports.
+
+ The text filter is started with the following argument
+ list:
+<tscreen>
+<tt>[-c] -w<it/width/ -l<it/length/ -i<it/indent/ -n <it/login/ -h <it/host/ <it/acct-file/</tt>
+</tscreen>
+ where
+ <descrip>
+ <tag/<tt/-c//
+
+ appears if the job's submitted with <tt/lpr -l/
+
+ <tag/<tt/<it/width///
+
+ is the value from the <tt/pw/ (page width)
+ capability specified in <tt>/etc/printcap</tt>,
+ default 132
+
+ <tag/<tt/<it/length///
+
+ is the value from the <tt/pl/ (page length)
+ capability, default 66
+
+ <tag/<tt/<it/indent///
+
+ is the amount of the indentation from <tt/lpr -i/,
+ default 0
+
+ <tag/<tt/<it/login///
+
+ is the account name of the user printing the file
+
+ <tag/<tt/<it/host///
+
+ is the host name from which the job was submitted
+
+ <tag/<tt/<it/acct-file///
+
+ is the name of the accounting file from the <tt/af/
+ capability.
+
+ </descrip>
+
+ <item>A <em/conversion filter/ converts a specific file
+ format into one the printer can render onto paper.
+ For example, ditroff typesetting data can't be
+ directly printed, but you can install a conversion
+ filter for ditroff files to convert the ditroff data
+ into a form the printer can digest and print. Section
+ <ref id="printing:advanced:convfilters"
+ name="Conversion Filters"> tells all about them.
+ Conversion filters also need to do accounting, if you
+ need printer accounting.
+
+ Conversion filters are started with the following
+ arguments:
+<tscreen>
+<tt>-x<it/pixel-width/ -y<it/pixel-height/ -n <it/login/ -h <it/host/ <it/acct-file/</tt>
+</tscreen>
+ where <it/pixel-width/ is the value from the <tt/px/
+ capability (default 0) and <it/pixel-height/ is the
+ value from the <tt/py/ capability (default 0).
+
+ <item>The <em/output filter/ is used only if there's no
+ text filter, or if header pages are enabled. In my
+ experience, output filters are rarely used. Section
+ <ref id="printing:advanced:of" name="Output Filters">
+ describe them. There are only two arguments to an
+ output filter:
+<tscreen>
+<tt>-w<it/width/ -l<it/length/</tt>
+</tscreen>
+ which are identical to the text filters <tt/-w/ and
+ <tt/-l/ arguments.
+ </itemize>
+
+ Filters should also <em/exit/ with the following exit
+ status:
+ <descrip>
+ <tag/exit 0/
+
+ If the filter printed the file successfully.
+
+ <tag/exit 1/
+
+ If the filter failed to print the file but wants LPD
+ to try to print the file again. LPD will restart a
+ filter if it exits with this status.
+
+ <tag/exit 2/
+
+ If the filter failed to print the file and doesn't
+ want LPD to try again. LPD will throw out the file.
+ </descrip>
+
+ The text filter that comes with the FreeBSD release,
+ <tt>/usr/libexec/lpr/lpf</tt>, takes advantage of the page
+ width and length arguments to determine when to send a
+ form feed and how to account for printer usage. It uses
+ the login, host, and accounting file arguments to make the
+ accounting entries.
+
+ If you're shopping for filters, see if they're
+ LPD-compatible. If they are, they must support the
+ argument lists described above. If you plan on writing
+ filters for general use, then have them support the same
+ argument lists and exit codes.
+
+ <sect2><heading>Accommodating Plain Text Jobs on PostScript Printers
+ <label id="printing:advanced:if-conversion"></heading>
+
+ <p> If you're the only user of your computer and PostScript
+ (or other language-based) printer, and you promise to
+ never send plain text to your printer and to never use
+ features of various programs that will want to send plain
+ text to your printer, then you don't need to worry about
+ this section at all.
+
+ But, if you would like to send both PostScript and plain
+ text jobs to the printer, then you're urged to augment
+ your printer setup. To do so, we have the text filter
+ detect if the arriving job is plain text or PostScript.
+ All PostScript jobs must start with <tt/&percnt;!/ (for
+ other printer languages, see your printer documentation).
+ If those are the first two characters in the job, we have
+ PostScript, and can pass the rest of the job directly. If
+ those aren't the first two characters in the file, then
+ the filter will convert the text into PostScript and print
+ the result.
+
+ How do we do this?
+
+ If you've got a serial printer, a great way to do it is to
+ install <tt/lprps/. <tt/lprps/ is a PostScript printer
+ filter which performs two-way communication with the
+ printer. It updates the printer's status file with
+ verbose information from the printer, so users and
+ administrators can see exactly what the state of the
+ printer is (such as ``toner low'' or ``paper jam''). But
+ more importantly, it includes a program called <tt/psif/
+ which detects whether the incoming job is plain text and
+ calls <tt/textps/ (another program that comes with
+ <tt/lprps/) to convert it to PostScript. It then uses
+ <tt/lprps/ to send the job to the printer.
+
+ <tt/lprps/ should be part of the FreeBSD ports collection
+ (see <ref id="ports" name="The Ports Collection">); if not,
+ it should be shortly. You can fetch, build and install it
+ yourself, of course. After installing <tt/lprps/, just
+ specify the pathname to the <tt/psif/ program that's part
+ of <tt/lprps/. If you installed <tt/lprps/ from the ports
+ collection, use the following in the serial PostScript
+ printer's entry in <tt>/etc/printcap</tt>:
+<tscreen><verb>
+ :if=/usr/local/libexec/psif:
+</verb></tscreen>
+ You should also specify the <tt/rw/ capability; that tells
+ LPD to open the printer in read-write mode.
+
+ If you have a parralel PostScript printer (and therefore
+ can't use two-way communication with the printer, which
+ <tt/lprps/ needs), you can use the following shell script
+ as the text filter:
+<code>
+#!/bin/sh
+#
+# psif - Print PostScript or plain text on a PostScript printer
+# Script version; NOT the version that comes with lprps
+# Installed in /usr/local/libexec/psif
+#
+
+read first_line
+first_two_chars=`expr "$first_line" : '\(..\)'`
+
+if [ "$first_two_chars" = "%!" ]; then
+ #
+ # PostScript job, print it.
+ #
+ echo $first_line &ero;&ero; cat &ero;&ero; printf "\004" &ero;&ero; exit 0
+ exit 2
+else
+ #
+ # Plain text, convert it, then print it.
+ #
+ ( echo $first_line; cat ) | /usr/local/bin/textps &ero;&ero; printf "\004" &ero;&ero; exit 0
+ exit 2
+fi
+</code>
+ In the above script, <tt/textps/ is a program we installed
+ separately to convert plain text to PostScript. You can
+ use any text-to-PostScript program you wish. The FreeBSD
+ ports collection (see <ref id="ports" name="The Ports
+ Collection">) includes a full featured text-to-PostScript
+ program called <tt/a2ps/ that you might want to
+ investigate.
+
+ <sect2><heading>Simulating PostScript on Non-PostScript Printers
+ <label id="printing:advanced:ps"></heading>
+
+ <p> PostScript is the <it/de facto/ standard for high
+ quality typesetting and printing. PostScript is, however,
+ an <em/expensive/ standard. Thankfully, Alladin
+ Enterprises has a free PostScript workalike called
+ <it/Ghostscript/ that runs with FreeBSD. Ghostscript can
+ read most PostScript files and can render their pages onto
+ a variety of devices, including many brands of
+ non-PostScript printers. By installing Ghostscript and
+ using a special text filter for your printer, you can make
+ your non-PostScript printer act like a real PostScript
+ printer.
+
+ Ghostscript should be in the FreeBSD ports collection, if
+ you'd like to install it from there. You can fetch,
+ build, and install it quite easily yourself, as well.
+
+ To simulate PostScript, we have the text filter detect if
+ it's printing a PostScript file. If it's not, then the
+ filter will pass the file directly to the printer;
+ otherwise, it will use Ghostscript to first convert the
+ file into a format the printer will understand.
+
+ Here's an example: the following script is a text filter
+ for Hewlett Packard DeskJet 500 printers. For other
+ printers, substitute the <tt/-sDEVICE/ argument to the
+ <tt/gs/ (Ghostscript) command. (Type <tt/gs -h/ to get a
+ list of devices the current installation of Ghostscript
+ supports.)
+<code>
+#!/bin/sh
+#
+# ifhp - Print Ghostscript-simulated PostScript on a DesJet 500
+# Installed in /usr/local/libexec/hpif
+
+#
+# Treat LF as CR+LF:
+#
+printf "\033&ero;k2G" || exit 2
+
+#
+# Read first two characters of the file
+#
+read first_line
+first_two_chars=`expr "$first_line" : '\(..\)'`
+
+if [ "$first_two_chars" = "%!" ]; then
+ #
+ # It's PostScript; use Ghostscript to scan-convert and print it
+ #
+ /usr/local/bin/gs -dSAFER -dNOPAUSE -q -sDEVICE=djet500 -sOutputFile=- - \
+ &ero;&ero; exit 0
+
+else
+ #
+ # Plain text or HP/PCL, so just print it directly; print a form
+ # at the end to eject the last page.
+ #
+ echo $first_line &ero;&ero; cat &ero;&ero; printf "\f" &ero;&ero; exit 2
+fi
+
+exit 2
+</code>
+ Finally, you need to notify LPD of the filter via the
+ <tt/if/ capability:
+<tscreen><verb>
+ :if=/usr/local/libexec/hpif:
+</verb></tscreen>
+ That's it. You can type <tt/lpr plain.text/ and <tt/lpr
+ whatever.ps/ and both should print successfully.
+
+
+ <sect2><heading>Conversion Filters<label
+ id="printing:advanced:convfilters"></heading>
+
+ <p> After completing the simple setup described in <ref
+ name="Simple Printer Setup" id="printing:simple">, the
+ first thing you'll probably want to do is install
+ conversion filters for your favorite file formats
+ (besides plain ASCII text).
+
+ <sect3><heading>Why Install Conversion Filters?</heading>
+
+ <p> Conversion filters make printing various kinds of
+ files easy. As an example, suppose we do a lot of work
+ with the TeX typesetting system, and we have a
+ PostScript printer. Every time we generate a DVI file
+ from TeX, we can't print it directly until we convert
+ the DVI file into PostScript. The command sequence
+ goes like this:
+<tscreen><verb>
+dvips seaweed-analysis.dvi
+lpr seaweed-analysis.ps
+</verb></tscreen>
+ By installing a conversion filter for DVI files, we can
+ skip the hand conversion step each time by having LPD do
+ it for us. Now, each time we get a DVI file, we're just
+ one step away from printing it:
+<tscreen><verb>
+lpr -d seaweed-analysis.dvi
+</verb></tscreen>
+ We got LPD to do the DVI file conversion for us by
+ specifying the <tt/-d/ option. Section <ref
+ id="printing:lpr:options:format" name="Formatting and
+ Conversion Options"> lists the conversion options.
+
+ For each of the conversion options you want a printer to
+ support, install a <em/conversion filter/ and specify
+ its pathname in <tt>/etc/printcap</tt>. A conversion
+ filter is like the text filter for the simple printer
+ setup (see section <ref id="printing:textfilter"
+ name="Installing the Text Filter">) except that instead
+ of printing plain text, the filter converts the file
+ into a format the printer can understand.
+
+ <sect3><heading>Which Conversions Filters Should I Install?
+ </heading>
+
+ <p> You should install the conversion filters you expect
+ to use. If you print a lot of DVI data, then a DVI
+ conversion filter is in order. If you've got plenty of
+ troff to print out, then you probably want a troff
+ filter.
+
+ The following table summarizes the filters that LPD
+ works with, their capability entries for the
+ <tt>/etc/printcap</tt> file, and how to invoke them with
+ the <tt/lpr/ command:
+<code>
+ /etc/printcap
+File type Capability lpr option
+------------ ------------- ----------
+cifplot cf -c
+DVI df -d
+plot gf -g
+ditroff nf -n
+FORTRAN text rf -f
+troff tf -t
+raster vf -v
+plain text if none, -p, or -l
+</code>
+
+ In our example, using <tt/lpr -d/ means the printer
+ needs a <tt/df/ capability in its entry in
+ <tt>/etc/printcap</tt>.
+
+ Despite what others might contend, formats like FORTRAN
+ text and plot are probably obsolete. At your site, you
+ can give new meanings to these or any of the formatting
+ options just by installing custom filters. For example,
+ suppose you'd like to directly print Printerleaf files
+ (files from the Interleaf desktop publishing program),
+ but will never print plot files. You could install a
+ Printerleaf conversion filter under the <tt/gf/
+ capability and then educate your users that <tt/lpr -g/
+ mean ``print Printerleaf files.''
+
+ <sect3><heading>Installing Conversion Filters</heading>
+
+ <p> Since conversion filters are programs you install
+ outside of the base FreeBSD installation, they should
+ probably go under <tt>/usr/local</tt>. The directory
+ <tt>/usr/local/libexec</tt> is a popular location, since
+ they they're specialized programs that only LPD will
+ run; regular users shouldn't ever need to run them.
+
+ To enable a conversion filter, specify its pathname
+ under the appropriate capability for the destination
+ printer in <tt>/etc/printcap</tt>.
+
+ In our example, we'll add the DVI conversion filter to
+ the entry for the printer named <tt/bamboo/. Here's the
+ example <tt>/etc/printcap</tt> file again, with the new
+ <tt/df/ capability for the printer <tt/bamboo/
+<code>
+#
+# /etc/printcap for host rose - added df filter for bamboo
+#
+rattan|line|diablo|lp|Diablo 630 Line Printer:\
+ :sh:sd=/var/spool/lpd/rattan:\
+ :lp=/dev/lpt0:\
+ :if=/usr/local/libexec/if-simple:
+
+bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
+ :sh:sd=/var/spool/lpd/bamboo:\
+ :lp=/dev/ttyd5:fs#0x82000e1:xs#0x820:rw:\
+ :if=/usr/local/libexec/psif:\
+ :df=/usr/local/libexec/psdf:
+</code>
+ The DVI filter is a shell script named
+ <tt>/usr/local/libexec/psdf</tt>. Here's that script:
+<code>
+#!bin/sh
+#
+# DVI to PostScript printer filter
+# Installed in /usr/local/libexec/psdf
+#
+# Invoked by lpd when user runs lpr -d
+#
+exec /usr/local/bin/dvips -f | /usr/local/libexec/lprps "$@"
+</code>
+ This script runs <tt/dvips/ in filter mode (the <tt/-f/
+ argument) on standard input, which is the job to print.
+ It then starts the PostScript printer filter <tt/lprps/
+ (see section <ref id="printing:advanced:if-conversion"
+ name="Accomodating Plain Text Jobs on PostScript
+ Printers">) with the arguments LPD passed to this script.
+ <tt/lprps/ will use those arguments to account for the
+ pages printed.
+
+ <sect3><heading>More Conversion Filter Examples</heading>
+
+ <p> Since there's no fixed set of steps to install
+ conversion filters, let me instead provide more
+ examples. Use these as guidance to making your own
+ filters. Use them directly, if appropriate.
+
+ This example script is a raster (well, GIF file,
+ actually) conversion filter for a Hewlett Packard
+ LaserJet III-Si printer:
+<code>
+#!/bin/sh
+#
+# hpvf - Convert GIF files into HP/PCL, then print
+# Installed in /usr/local/libexec/hpvf
+
+PATH=/usr/X11R6/bin:$PATH; export PATH
+
+giftopnm | ppmtopgm | pgmtopbm | pbmtolj -resolution 300 \
+ && exit 0 \
+ || exit 2
+</code>
+ It works by converting the GIF file into a portable
+ anymap, converting that into a portable graymap,
+ converting that into a portable bitmap, and converting
+ that into LaserJet/PCL-compatible data.
+
+ Here's the <tt>/etc/printcap</tt> file with an entry for
+ a printer using the above filter:
+<code>
+#
+# /etc/printcap for host orchid
+#
+teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\
+ :lp=/dev/lpt0:sh:sd=/var/spool/lpd/teak:mx#0:\
+ :if=/usr/local/libexec/hpif:\
+ :vf=/usr/local/libexec/hpvf:
+</code>
+
+ The following script is a conversion filter for troff
+ data from the groff typesetting system for the
+ PostScript printer named <tt/bamboo/:
+<code>
+#!/bin/sh
+#
+# pstf - Convert groff's troff data into PS, then print.
+# Installed in /usr/local/libexec/pstf
+#
+exec grops | /usr/local/libexec/lprps "$@"
+</code>
+ The above script makes use of <tt/lprps/ again to handle
+ the communication with the printer. If the printer were
+ on a parallel port, we'd use this script instead:
+<code>
+#!/bin/sh
+#
+# pstf - Convert groff's troff data into PS, then print.
+# Installed in /usr/local/libexec/pstf
+#
+exec grops
+</code>
+ That's it. Here's the entry we need to add to
+ <tt>/etc/printcap</tt> to enable the filter:
+<tscreen><verb>
+ :tf=/usr/local/libexec/pstf:
+</verb></tscreen>
+
+ Here's an example that might make old hands at FORTRAN
+ blush. It's a FORTRAN-text filter for any printer that
+ can directly print plain text. We'll install it for the
+ printer <tt/teak/:
+<code>
+#!/bin/sh
+#
+# hprf - FORTRAN text filter for LaserJet 3si:
+# Installed in /usr/local/libexec/hprf
+#
+
+printf "\033&ero;k2G" &ero;&ero; fpr &ero;&ero; printf "\f" &ero;&ero; exit 0
+exit 2
+</code>
+ And we'll add this line to the <tt>/etc/printcap</tt>
+ for the printer <tt/teak/ to enable this filter:
+<tscreen><verb>
+ :rf=/usr/local/libexec/hprf:
+</verb></tscreen>
+
+ Here's one final, somewhat complex example. We'll add a
+ DVI filter to the LaserJet printer <tt/teak/ introduced
+ earlier. First, the easy part: updating
+ <tt>/etc/printcap</tt> with the location of the DVI
+ filter:
+<tscreen><verb>
+ :df=/usr/local/libexec/hpdf:
+</verb></tscreen>
+
+ Now, for the hard part: making the filter. For that, we
+ need a DVI-to-LaserJet/PCL conversion program. The
+ FreeBSD ports collection (see <ref id="ports" name="The
+ Ports Collection">) has one: <tt/dvi2xx/ is the name of
+ the package. Installing this package gives us the
+ program we need, <tt/dvilj2p/, which converts DVI into
+ LaserJet IIp, LaserJet III, and LaserJet 2000 compatible
+ codes.
+
+ <tt/dvilj2p/ makes the filter <tt/hpdf/ quite complex
+ since <tt/dvilj2p/ can't read from standard input. It
+ wants to work with a filename. What's worse, the
+ filename has to end in <tt/.dvi/ so using
+ <tt>/dev/fd/0</tt> for standard input is problematic.
+ We can get around that problem by linking (symbolically)
+ a temporary file name (one that ends in <tt/.dvi/) to
+ <tt>/dev/fd/0</tt>, thereby forcing <tt/dvilj2p/ to read
+ from standard input.
+
+ The only other fly in the ointment is the fact that we
+ can't use /tmp for the temporary link. Symbolic links
+ are owned by user and group <tt/bin/. The filter runs
+ as user <tt/daemon/. And the <tt>/tmp</tt> directory
+ has the sticky bit set. The filter can create the link,
+ but it won't be able clean up when done and remove it
+ since the link will belong to a different user.
+
+ Instead, the filter will make the symbolic link in the
+ current working directory, which is the spooling
+ directory (specified by the <tt/sd/ capability in
+ <tt>/etc/printcap</tt>). This is a perfect place for
+ filters to do their work, especially since there's
+ (sometimes) more free disk space in the spooling directory
+ than under <tt>/tmp</tt>.
+
+ Here, finally, is the filter:
+<code>
+#!/bin/sh
+#
+# hpdf - Print DVI data on HP/PCL printer
+# Installed in /usr/local/libexec/hpdf
+
+PATH=/usr/local/bin:$PATH; export PATH
+
+#
+# Define a function to clean up our temporary files. These exist
+# in the current directory, which will be the spooling directory
+# for the printer.
+#
+cleanup() {
+ rm -f hpdf$$.dvi
+}
+
+#
+# Define a function to handle fatal errors: print the given message
+# and exit 2. Exiting with 2 tells LPD to don't try to reprint the
+# job.
+#
+fatal() {
+ echo "$@" 1>&ero;2
+ cleanup
+ exit 2
+}
+
+#
+# If user removes the job, LPD will send SIGINT, so trap SIGINT
+# (and a few other signals) to clean up after ourselves.
+#
+trap cleanup 1 2 15
+
+#
+# Make sure we're not colliding with any existing files.
+#
+cleanup
+
+#
+# Link the DVI input file to standard input (the file to print).
+#
+ln -s /dev/fd/0 hpdf$$.dvi || fatal "Cannot symlink /dev/fd/0"
+
+#
+# Make LF = CR+LF
+#
+printf "\033&ero;k2G" || fatal "Cannot initialize printer"
+
+#
+# Convert and print. Return value from dvilj2p doesn't seem to be
+# reliable, so we ignore it.
+#
+dvilj2p -M1 -q -e- dfhp$$.dvi
+
+#
+# Clean up and exit
+#
+cleanup
+exit 0
+</code>
+
+ <sect3><heading>Automated Conversion: An Alternative To Conversion Filters
+ <label id="printing:advanced:autoconv"></heading>
+
+ <p> All these conversion filters accomplish a lot for your
+ printing environment, but at the cost forcing the user
+ to specify (on the <tt/lpr/ command line) which one to
+ use. If your users aren't particularly computer
+ literate, having to specify a filter option will become
+ annoying. What's worse, though, is that an incorrectly
+ specified filter option may run a filter on the wrong
+ type of file and cause your printer to spew out hundreds
+ of sheets of paper.
+
+ Rather than install conversion filters at all, you might
+ want to try having the text filter (since it's the
+ default filter) detect the type of file it's asked to
+ print and then automatically run the right conversion
+ filter. Tools such as <tt/file/ can be of help here.
+ Of course, it'll be hard to determine the differences
+ between <em/some/ file types---and, of course, you can
+ still provide conversion filters just for them.
+
+ The FreeBSD ports collection has a text filter that
+ performs automatic conversion called <tt/apsfilter/. It
+ can detect plain text, PostScript, and DVI files, run
+ the proper conversions, and print.
+
+ <sect2><heading>Output Filters<label
+ id="printing:advanced:of"></heading>
+
+ <p> The LPD spooling system supports one other type of
+ filter that we've not yet explored: an output filter. An
+ output filter is intended for printing plain text only,
+ like the text filter, but with many simplifications. If
+ you're using an output filter but no text filter, then
+ <itemize>
+ <item>LPD starts an output filter once for the entire
+ job instead of once for each file in the job.
+
+ <item>LPD doesn't make any provision to identify the
+ start or the end of files within the job for the
+ output filter.
+
+ <item>LPD doesn't pass the user's login or host to
+ the filter, so it's not intended to do accounting. In
+ fact, it gets only two arguments:
+<tscreen>
+<tt>-w<it/width/ -l<it/length/</tt>
+</tscreen>
+ where <it/width/ is from the <tt/pw/ capability and
+ <it/length/ is from the <tt/pl/ capability for the
+ printer in question.
+ </itemize>
+
+ Don't be seduced by an output filter's simplicity. If
+ you'd like each file in a job to start on a different page
+ an output filter <em/won't work/. Use a text filter (also
+ known as an input filter); see section <ref
+ id="printing:textfilter" name="Installing the Text
+ Filter">. Furthermore, an output filter is actually
+ <em/more complex/ in that it has to examine the byte
+ stream being sent to it for special flag characters and
+ must send signals to itself on behalf of LPD.
+
+ However, an output filter is <em/necessary/ if you want
+ header pages and need to send escape sequences or other
+ initialization strings to be able to print the header
+ page. (But it's also <em/futile/ if you want to charge
+ header pages to the requesting user's account, since LPD
+ doesn't give any user or host information to the output
+ filter.)
+
+ On a single printer, LPD allows both an output filter and
+ text or other filters. In such cases, LPD will start the
+ output filter to print the header page (see section <ref
+ id="printing:advanced:header-pages" name="Header Pages">)
+ only. LPD then expects the output filter to <em/stop
+ itself/ by sending two bytes to the filter: ASCII 031
+ followed by ASCII 001. When an output filter sees these
+ two bytes (031, 001), it should stop by sending SIGSTOP to
+ itself. When LPD's done running other filters, it'll
+ restart the output filter by sending SIGCONT to it.
+
+ If there's an output filter but <em/no/ text filter and
+ LPD is working on a plain text job, LPD uses the output
+ filter to do the job. As stated before, the output filter
+ will print each file of the job in sequence with no
+ intervening form feeds or other paper advancement, and
+ this is probably <em/not/ what you want. In almost all
+ cases, you need a text filter.
+
+ The program <tt/lpf/, whch we introduced earlier as a text
+ filter, can also run as an output filter. If you need a
+ quick-and-dirty output filter but don't want to write the
+ byte detection and signal sending code, try <tt/lpf/. You
+ can also wrap <tt/lpf/ in a shell script to handle any
+ intialization codes the printer might require.
+
+ <sect2><heading><tt/lpf/: a Text Filter<label
+ id="printing:advanced:lpf"></heading>
+
+ <p> The program <tt>/usr/libexec/lpr/lpf</tt> that comes
+ with FreeBSD binary distribution is a text filter (input
+ filter) that can indent output (job submitted with <tt/lpr
+ -i/), allow literal characters to pass (job submitted with
+ <tt/lpr -l/), adjust the printing position for backspaces
+ and tabs in the job, and account for pages printed. It
+ can also act like an output filter.
+
+ <tt/lpf/ is suitable for many printing environments. And
+ although it has no capability to send initialization
+ sequences to a printer, it's easy to write a shell script
+ to do the needed initialization and then execute <tt/lpf/.
+
+ In order for <tt/lpf/ to do page accounting correctly, it
+ needs correct values filled in for the <tt/pw/ and <tt/pl/
+ capabilities in the <tt>/etc/printcap</tt> file. It uses
+ these values to determine how much text can fit on a page
+ and how many pages were in a user's job. For more
+ information on printer accounting, see <ref
+ id="printing:advanced:acct" name="Accounting for Printer
+ Usage">.
+
+ <sect1><heading>Header Pages<label
+ id="printing:advanced:header-pages"></heading>
+
+ <p> If you've got <em/lots/ of users, all of them using
+ various printers, then you probably want to consider
+ <em/header pages/ as a necessary evil.
+
+ Header pages, also known as <em/banner/ or <em/burst pages/
+ identify to whom jobs belong after they're printed. They're
+ usually printed in large, bold letters, perhaps with
+ decorative borders, so that in a stack of printouts they
+ stand out from the real documents that comprise users' jobs.
+ They enable users to locate their jobs quickly. The obvious
+ drawback to a header page is that it's yet one more sheet
+ that has to be printed for every job, their ephemeral
+ usefulness lasting not more than a few minutes, ultimately
+ finding themselves in a recycling bin or rubbish heap.
+ (Note that header pages go with each job, not each file in a
+ job, so the paper waste might not be that bad.)
+
+ The LPD system can provide header pages automatically for
+ your printouts <em/if/ your printer can directly print plain
+ text. If you've got a PostScript printer, you'll need an
+ external program to generate the header page; see <ref
+ id="printing:advanced:header-pages:ps" name="Header Pages on
+ PostScript Printers">.
+
+ <sect2><heading>Enabling Header Pages<label
+ id="printing:advanced:header-pages:enabling"></heading>
+
+ <p> In the <ref id="printing:simple" name="Simple Printer
+ Setup">, we turned off header pages by specifying
+ <tt/sh/ (meaning ``suppress header'') in the
+ <tt>/etc/printcap</tt> file. To enable header pages for
+ a printer, just remove the <tt/sh/ capability.
+
+ Sounds too easy, right?
+
+ You're right. You <em/might/ have to provide an output
+ filter to send initialization strings to the printer.
+ Here's an example output filter for Hewlett Packard
+ PCL-compatible printers:
+<code>
+#!/bin/sh
+#
+# hpof - Output filter for Hewlett Packard PCL-compatible printers
+# Installed in /usr/local/libexec/hpof
+
+
+printf "\033&ero;k2G" || exit 2
+exec /usr/libexec/lpr/lpf
+</code>
+ Specify the path to the output filter in the <tt/of/
+ capability. See <ref id="printing:advanced:of"
+ name="Output Filters"> for more information.
+
+ Here's an example <tt>/etc/printcap</tt> file for the printer
+ <tt/teak/ that we introduced earlier; we enabled header
+ pages and added the above output filter:
+<code>
+#
+# /etc/printcap for host orchid
+#
+teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\
+ :lp=/dev/lpt0:sd=/var/spool/lpd/teak:mx#0:\
+ :if=/usr/local/libexec/hpif:\
+ :vf=/usr/local/libexec/hpvf:\
+ :of=/usr/local/libexec/hpof:
+</code>
+ Now, when users print jobs to <tt/teak/, they get a header
+ page with each job. If users want to spend time searching
+ for their printouts, they can suppress header pages by
+ submitting the job with <tt/lpr -h/; see <ref
+ id="printing:lpr:options:misc" name="Header Page Options">
+ for more <tt/lpr/ options.
+
+ <tt/Note:/ LPD prints a form feed character after the
+ header page. If your printer uses a different character
+ or sequence of characters to eject a page, specify them
+ with the <tt/ff/ capability in <tt>/etc/printcap</tt>.
+
+ <sect2><heading>Controlling Header Pages<label
+ id="printing:advanced:header-pages:controlling"></heading>
+
+ <p> By enabling header pages, LPD will produce a <em/long
+ header/, a full page of large letters identifying the
+ user, host, and job. Here's an example (kelly printed
+ the job named outline from host rose):
+<tscreen><verb>
+k ll ll
+k l l
+k l l
+k k eeee l l y y
+k k e e l l y y
+k k eeeeee l l y y
+kk k e l l y y
+k k e e l l y yy
+k k eeee lll lll yyy y
+ y
+ y y
+ yyyy
+
+
+ ll
+ t l i
+ t l
+ oooo u u ttttt l ii n nnn eeee
+o o u u t l i nn n e e
+o o u u t l i n n eeeeee
+o o u u t l i n n e
+o o u uu t t l i n n e e
+ oooo uuu u tt lll iii n n eeee
+
+
+
+
+
+
+
+
+
+r rrr oooo ssss eeee
+rr r o o s s e e
+r o o ss eeeeee
+r o o ss e
+r o o s s e e
+r oooo ssss eeee
+
+
+
+
+
+
+
+ Job: outline
+ Date: Sun Sep 17 11:04:58 1995
+</verb></tscreen>
+ LPD appends a form feed after this text so the job starts
+ on a new page (unless you've got <tt/sf/ (suppress form
+ feeds) in the destination printer's entry in
+ <tt>/etc/printcap</tt>).
+
+ If you prefer, LPD can make a <em/short header/; specify
+ <tt/sb/ (short banner) in the <tt>/etc/printcap</tt> file.
+ The header page will look like this:
+<tscreen><verb>
+rose:kelly Job: outline Date: Sun Sep 17 11:07:51 1995
+</verb></tscreen>
+ Also by default, LPD prints the header page first, then
+ the job. To reverse that, specify <tt/hl/ (header last)
+ in <tt>/etc/printcap</tt>.
+
+ <sect2><heading>Accounting for Header Pages<label
+ id="printing:advanced:header-pages:accounting"></heading>
+
+ <p> Using LPD's built-in header pages enforces a particular
+ paradigm when it comes to printer accounting: header pages
+ must be <em/free of charge/.
+
+ Why?
+
+ Because the output filter is the only external program
+ that will have control when the header page is printed
+ that could do accounting, and it isn't provided with any
+ <em/user or host/ information or an accounting file, so it
+ has no idea whom to charge for printer use. It's also not
+ enough to just ``add one page'' to the text filter or any
+ of the conversion filters (which do have user and host
+ information) since users can suppress header pages with
+ <tt/lpr -h/. They could still be charged for header pages
+ they didn't print. Basically, <tt/lpr -h/ will be the
+ preferred option of environmentally-minded users, but you
+ can't offer any incentive to use it.
+
+ It's <em/still not enough/ to have each of the filters
+ generate their own header pages (thereby being able to
+ charge for them). If users wanted the option of
+ suppressing the header pages with <tt/lpr -h/, they will
+ still get them and be charged for them since LPD does not
+ pass any knowledge of the <tt/-h/ option to any of the
+ filters.
+
+ So, what are your options?
+
+ You can
+ <itemize>
+ <item>Accept LPD's paradigm and make header pages free.
+
+ <item>Install an alternative to LPD, such as LPDng or
+ PLP. Section <ref name="Alternatives to the Standard
+ Spooler" id="printing:lpd-alternatives"> tells more
+ about other spooling software you can substitute for
+ LPD.
+
+ <item>Write a <em/smart/ output filter. Normally, an
+ output filter isn't meant to do anything more than
+ initialize a printer or do some simple character
+ conversion. It's suited for header pages and plain
+ text jobs (when there's no text (input) filter).
+
+ But, if there is a text filter for the plain text
+ jobs, then LPD will start the output filter only for
+ the header pages. And the output filter can parse the
+ header page text that LPD generates to determine what
+ user and host to charge for the header page. The only
+ other problem with this method is that the output
+ filter still doesn't know what accounting file to use
+ (it's not passed the name of the file from the <tt/af/
+ capability), but if you have a well-known accounting
+ file, you can hard-code that into the output filter.
+
+ To facilitate the parsing step, use the <tt/sh/ (short
+ header) capability in <tt>/etc/printcap</tt>.
+
+ Then again, all that might be too much trouble, and
+ users will certainly appreciate the more generous
+ system administrator who makes header pages free.
+ </itemize>
+
+ <sect2><heading>Header Pages on PostScript Printers<label
+ id="printing:advanced:header-pages:ps"></heading>
+
+ <p> As described above, LPD can generate a plain text header
+ page suitable for many printers. Of course, PostScript
+ can't directly print plain text, so the header page
+ feature of LPD is useless---or mostly so.
+
+ One obvious way to get header pages is to have every
+ conversion filter and the text filter generate the header
+ page. The filters should should use the user and host
+ arguments to generate a suitable header page. The
+ drawback of this method is that users will always get a
+ header page, even if they submit jobs with <tt/lpr -h/.
+
+ Let's explore this method. The following script takes
+ three arguments (user login name, host name, and job name)
+ and makes a simple PostScript header page:
+<code>
+#!/bin/sh
+#
+# make-ps-header - make a PostScript header page on stdout
+# Installed in /usr/local/libexec/make-ps-header
+#
+
+#
+# These are PostScript units (72 to the inch). Modify for A4 or
+# whatever size paper you're using:
+#
+page_width=612
+page_height=792
+border=72
+
+#
+# Check arguments
+#
+if [ $# -ne 3 ]; then
+ echo "Usage: `basename $0` <user> <host> <job>" 1>&ero;2
+ exit 1
+fi
+
+#
+# Save these, mostly for readability in the PostScript, below.
+#
+user=$1
+host=$2
+job=$3
+date=`date`
+
+#
+# Send the PostScript code to stdout.
+#
+exec cat <<EOF
+%!PS
+
+%
+% Make sure we don't interfere with user's job that will follow
+%
+save
+
+%
+% Make a thick, unpleasant border around the edge of the paper.
+%
+$border $border moveto
+$page_width $border 2 mul sub 0 rlineto
+0 $page_height $border 2 mul sub rlineto
+currentscreen 3 -1 roll pop 100 3 1 roll setscreen
+$border 2 mul $page_width sub 0 rlineto closepath
+0.8 setgray 10 setlinewidth stroke 0 setgray
+
+%
+% Display user's login name, nice and large and prominent
+%
+/Helvetica-Bold findfont 64 scalefont setfont
+$page_width ($user) stringwidth pop sub 2 div $page_height 200 sub moveto
+($user) show
+
+%
+% Now show the boring particulars
+%
+/Helvetica findfont 14 scalefont setfont
+/y 200 def
+[ (Job:) (Host:) (Date:) ] {
+ 200 y moveto show /y y 18 sub def
+} forall
+
+/Helvetica-Bold findfont 14 scalefont setfont
+/y 200 def
+[ ($job) ($host) ($date) ] {
+ 270 y moveto show /y y 18 sub def
+} forall
+
+%
+% That's it
+%
+restore
+showpage
+EOF
+</code>
+ Now, each of the conversion filters and the text filter
+ can call this script to first generate the header page,
+ and then print the user's job. Here's the DVI conversion
+ filter from earlier in this document, modified to make a
+ header page:
+<code>
+#!/bin/sh
+#
+# DVI to PostScript printer filter
+# Installed in /usr/local/libexec/psdf
+#
+# Invoked by lpd when user runs lpr -d
+#
+
+orig_args="$@"
+
+fail() {
+ echo "$@" 1>&ero;2
+ exit 2
+}
+
+while getopts "x:y:n:h:" option; do
+ case $option in
+ x|y) ;; # Ignore
+ n) login=$OPTARG ;;
+ h) host=$OPTARG ;;
+ *) echo "LPD started `basename $0` wrong." 1>&ero;2
+ exit 2
+ ;;
+ esac
+done
+
+[ "$login" ] || fail "No login name"
+[ "$host" ] || fail "No host name"
+
+( /u/kelly/freebsd/printing/filters/make-ps-header $login $host "DVI File"
+ /usr/local/bin/dvips -f ) | eval /usr/local/libexec/lprps $orig_args
+</code>
+ Notice how the filter has to parse the argument list in
+ order to determine the user and host name. The parsing
+ for the other conversion filters is identical. The text
+ filter takes a slightly different set of arguments, though
+ (see section <ref id="printing:advanced:filters" name="How
+ Filters Work">).
+
+ As we've mentioned before, the above scheme, though fairly
+ simple, disables the ``suppress header page'' option (the
+ <tt/-h/ option) to <tt/lpr/. If users wanted to save a
+ tree (or a few pennies, if you charge for header pages),
+ they wouldn't be able to do so, since every filter's going
+ to print a header page with every job.
+
+ To allow users to shut off header pages on a per-job
+ basis, you'll need to use the trick introduced in section
+ <ref id="printing:advanced:header-pages:accounting"
+ name="Accounting for Header Pages">: write an output
+ filter that parses the LPD-generated header page and
+ produces a PostScript version. If the user submits the
+ job with <tt/lpr -h/, then LPD won't generate a header
+ page, and neither will your output filter. Otherwise,
+ your output filter will read the text from LPD and send
+ the appropriate header page PostScript code to the
+ printer.
+
+ If you've got a PostScript printer on a serial line, you
+ can make use of <tt/lprps/, which comes with an output
+ filter, <tt/psof/, which does the above. Note that
+ <tt/psof/ doesn't charge for header pages.
+
+ <sect1><heading>Networked Printing<label
+ id="printing:advanced:network-printers"></heading>
+
+ <p> FreeBSD supports networked printing: sending jobs to
+ remote printers. Networked printing generally refers to two
+ different things:
+ <itemize>
+ <item>Accessing a printer attached to a remote host. You
+ install a printer that has a conventional serial or
+ parallel interface on one host. Then, you set up LPD to
+ enable access to the printer from other hosts on the
+ network. Section <ref id="printing:advanced:network:rm"
+ name="Printers Installed on Remote Hosts"> tells how to
+ do this.
+
+ <item>Accessing a printer attached directly to a network.
+ The printer has a network interface in addition (or in
+ place of) a more conventional serial or parallel
+ interface. Such a printer might work as follows:
+
+ <itemize>
+ <item>It might understand the LPD protocol and can
+ even queue jobs from remote hosts. In this case, it
+ acts just like a regular host running LPD. Follow
+ the same procedure in section <ref
+ id="printing:advanced:network:rm" name="Printers
+ Installed on Remote Hosts"> to set up such a
+ printer.
+
+ <item>It might support a data stream network
+ connection. In this case, you ``attach'' the
+ printer to one host on the network by making that
+ host responsible for spooling jobs and sending them
+ to the printer. Section <ref
+ id="printing:advanced:network:net-if" name="Printers
+ with Networked Data Stream Interfaces"> gives some
+ suggestions on installing such printers.
+ </itemize>
+ </itemize>
+
+ <sect2><heading>Printers Installed on Remote Hosts<label
+ id="printing:advanced:network:rm"></heading>
+
+ <p> The LPD spooling system has built-in support for sending
+ jobs to other hosts also running LPD (or are compatible
+ with LPD). This feature enables you to install a printer
+ on one host and make it accessible from other hosts. It
+ also works with printers that have network interfaces that
+ understand the LPD protocol.
+
+ To enable this kind of remote printing, first install a
+ printer on one host, the <em/printer host/, using the
+ simple printer setup described in <ref
+ id="printing:simple" name="Simple Printer Setup">. Do any
+ advanced setup in <ref id="printing:advanced"
+ name="Advanced Printer Setup"> that you need. Make sure
+ to test the printer and see if it works with the features
+ of LPD you've enabled.
+
+ If you're using a printer with a network interface that's
+ compatible with LPD, then the <em/printer host/ in the
+ discussion below is the printer itself, and the
+ <em/printer name/ is the name you configured for the
+ printer. See the documentation that accompanied your
+ printer and/or printer-network interface.
+
+ Then, on the other hosts you want to have access to the
+ printer, make an entry in their <tt>/etc/printcap</tt>
+ files with the following:
+ <enum>
+ <item>Name the entry anything you want. For
+ simplicity, though, you probably want to use the same
+ name and aliases as on the printer host.
+
+ <item>Leave the <tt/lp/ capability blank, explicitly
+ (<tt/:lp=:/).
+
+ <item>Make a spooling directory and specify its
+ location in the <tt/sd/ capability. LPD will store
+ jobs here before they get sent to the printer host.
+
+ <item>Place the name of the printer host in the <tt/rm/
+ capability.
+
+ <item>Place the printer name on the <em/printer host/ in
+ the <tt/rp/ capability.
+ </enum>
+ That's it. You don't need to list conversion filters,
+ page dimensions, or anything else in the
+ <tt>/etc/printcap</tt> file.
+
+ Here's an example. The host rose has two printers,
+ <tt/bamboo/ and <tt/rattan/. We'll enable users on the
+ host orchid to print to those printers. Here's the
+ <tt>/etc/printcap</tt> file for orchid (back from section
+ <ref id="printing:advanced:header-pages:enabling"
+ name="Enabling Header Pages">). It already had the entry
+ for the printer <tt/teak/; we've added entries for the two
+ printers on the host rose:
+<code>
+#
+# /etc/printcap for host orchid - added (remote) printers on rose
+#
+
+#
+# teak is local; it's connected directly to orchid:
+#
+teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\
+ :lp=/dev/lpt0:sd=/var/spool/lpd/teak:mx#0:\
+ :if=/usr/local/libexec/ifhp:\
+ :vf=/usr/local/libexec/vfhp:\
+ :of=/usr/local/libexec/ofhp:
+
+#
+# rattan is connected to rose; send jobs for rattan to rose:
+#
+rattan|line|diablo|lp|Diablo 630 Line Printer:\
+ :lp=:rm=rose:rp=rattan:sd=/var/spool/lpd/rattan:
+
+#
+# bamboo is connected to rose as well:
+#
+bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
+ :lp=:rm=rose:rp=bamboo:sd=/var/spool/lpd/bamboo:
+</code>
+ Then, we just need to make spooling directories on orchid:
+<tscreen><verb>
+mkdir -p /var/spool/lpd/rattan /var/spool/lpd/bamboo
+chmod 770 /var/spool/lpd/rattan /var/spool/lpd/bamboo
+chown daemon.daemon /var/spool/lpd/rattan /var/spool/lpd/bamboo
+</verb></tscreen>
+
+ Now, users on orchid can print to <tt/rattan/ and
+ <tt/bamboo/. If, for example, a user on orchid typed
+<tscreen><verb>
+lpr -P bamboo -d sushi-review.dvi
+</verb></tscreen>
+ the LPD system on orchid would copy the job to the
+ spooling directory <tt>/var/spool/lpd/bamboo</tt> and note
+ that it was a DVI job. As soon as the host rose has room
+ in its <tt/bamboo/ spooling directory, the two
+ LPDs would transfer the file to rose. The file would wait
+ in rose's queue until it was finally printed. It would be
+ converted from DVI to PostScript (since bamboo is a
+ PostScript printer) on rose.
+
+ <sect2><heading>Printers with Networked Data Stream Interfaces<label
+ id="printing:advanced:network:net-if"></heading>
+
+ <p> Often, when you buy a network interface card for a
+ printer, you can get two versions: one which emulates a
+ spooler (the more expensive version), or one which just
+ lets you send data to it as if you were using a serial or
+ parallel port (the cheaper version). This section tells
+ how to use the cheaper version. For the more expensive
+ version, see the previous section <ref name="Printers
+ Installed on Remote Hosts" id="printing:advanced:network:rm">.
+
+ The format of the <tt>/etc/printcap</tt> file lets you
+ specify what serial or parallel interface to use, and (if
+ you're using a serial interface), what baud rate, whether
+ to use flow control, delays for tabs, conversion of
+ newlines, and more. But there's no way to specify a
+ connection to a printer that's listening on a TCP/IP or
+ other network port.
+
+ To send data to a networked printer, you need to develop a
+ communications program that can be called by the text and
+ conversion filters. Here's one such example: the script
+ <tt/netprint/ takes all data on standard input and sends
+ it to a network-attached printer. We specify the hostname
+ of the printer as the first argument and the port number
+ to which to connect as the second argument to
+ <tt/netprint/. Note that this supports one-way
+ communication only (FreeBSD to printer); many network
+ printers support two-way communication, and you might want
+ to take advantage of that (to get printer status, perform
+ accounting, etc.).
+<code>
+#!/usr/bin/perl
+#
+# netprint - Text filter for printer attached to network
+# Installed in /usr/local/libexec/netprint
+#
+
+$#ARGV eq 1 || die "Usage: $0 <printer-hostname> <port-number>";
+
+$printer_host = $ARGV[0];
+$printer_port = $ARGV[1];
+
+require 'sys/socket.ph';
+
+($ignore, $ignore, $protocol) = getprotobyname('tcp');
+($ignore, $ignore, $ignore, $ignore, $address)
+ = gethostbyname($printer_host);
+
+$sockaddr = pack('S n a4 x8', &ero;AF_INET, $printer_port, $address);
+
+socket(PRINTER, &ero;PF_INET, &ero;SOCK_STREAM, $protocol)
+ || die "Can't create TCP/IP stream socket: $!";
+connect(PRINTER, $sockaddr) || die "Can't contact $printer_host: $!";
+while (<STDIN>) { print PRINTER; }
+exit 0;
+</code>
+ We can then use this script in various filters. Suppose
+ we had a Diablo 750-N line printer connected to the
+ network. The printer accepts data to print on port number
+ 5100. The host name of the printer is scrivener. Here's
+ the text filter for the printer:
+<code>
+#!/bin/sh
+#
+# diablo-if-net - Text filter for Diablo printer `scrivener' listening
+# on port 5100. Installed in /usr/local/libexec/diablo-if-net
+#
+
+exec /usr/libexec/lpr/lpf "$@" | /usr/local/libexec/netprint scrivener 5100
+</code>
+
+
+ <sect1><heading>Restricting Printer Usage<label
+ id="printing:advanced:restricting"></heading>
+
+ <p> This section gives information on restricting printer
+ usage. The LPD system lets you control who can access a
+ printer, both locally or remotely, whether they can print
+ multiple copies, how large their jobs can be, and how large
+ the printer queues can get.
+
+ <sect2><heading>Restricting Multiple Copies<label
+ id="printing:advanced:restricting:copies"></heading>
+
+ <p> The LPD system makes it easy for users to print multiple
+ copies of a file. Users can print jobs with <tt/lpr -&num;5/
+ (for example) and get five copies of each file in the job.
+ Whether this is a good thing is up to you.
+
+ If you feel multiple copies cause unnecessary wear and
+ tear on your printers, you can disable the <tt/-&num;/ option
+ to <tt/lpr/ by adding the <tt/sc/ capability to the
+ <tt>/etc/printcap</tt> file. When users submit jobs
+ with the <tt/-&num;/ option, they'll see
+<tscreen><verb>
+lpr: multiple copies are not allowed
+</verb></tscreen>
+
+ Note that if you've set up access to a printer remotely
+ (see section <ref name="Printers Installed on Remote
+ Hosts" id="printing:advanced:network:rm">), you need the
+ <tt/sc/ capability on the remote <tt>/etc/printcap</tt>
+ files as well, or else users will still be able to submit
+ multiple-copy jobs by using another host.
+
+ Here's an example. This is the <tt>/etc/printcap</tt>
+ file for the host rose. The printer <tt/rattan/ is quite
+ hearty, so we'll allow multiple copies, but the laser
+ printer <tt/bamboo/'s a bit more delicate, so we'll
+ disable multiple copies by adding the <tt/sc/ capability:
+<code>
+#
+# /etc/printcap for host rose - restrict multiple copies on bamboo
+#
+rattan|line|diablo|lp|Diablo 630 Line Printer:\
+ :sh:sd=/var/spool/lpd/rattan:\
+ :lp=/dev/lpt0:\
+ :if=/usr/local/libexec/if-simple:
+
+bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
+ :sh:sd=/var/spool/lpd/bamboo:sc:\
+ :lp=/dev/ttyd5:fs#0x82000e1:xs#0x820:rw:\
+ :if=/usr/local/libexec/psif:\
+ :df=/usr/local/libexec/psdf:
+</code>
+ Now, we also need to add the <tt/sc/ capability on the
+ host orchid's <tt>/etc/printcap</tt> (and while we're at
+ it, let's disable multiple copies for the printer
+ <tt/teak/):
+<code>
+#
+# /etc/printcap for host orchid - no multiple copies for local
+# printer teak or remote printer bamboo
+
+teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\
+ :lp=/dev/lpt0:sd=/var/spool/lpd/teak:mx#0:sc:\
+ :if=/usr/local/libexec/ifhp:\
+ :vf=/usr/local/libexec/vfhp:\
+ :of=/usr/local/libexec/ofhp:
+
+rattan|line|diablo|lp|Diablo 630 Line Printer:\
+ :lp=:rm=rose:rp=rattan:sd=/var/spool/lpd/rattan:
+
+bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
+ :lp=:rm=rose:rp=bamboo:sd=/var/spool/lpd/bamboo:sc:
+</code>
+ By using the <tt/sc/ capability, we prevent the use of
+ <tt/lpr -&num;/, but that still doesn't prevent users from
+ running <tt/lpr/ multiple times, or from submitting the
+ same file mutliple times in one job like this:
+<tscreen><verb>
+lpr forsale.sign forsale.sign forsale.sign forsale.sign forsale.sign
+</verb></tscreen>
+ There are many ways to prevent this abuse (including
+ ignoring it) which you are free to explore.
+
+ <sect2><heading>Restricting Access To Printers<label
+ id="printing:advanced:restricting:access"></heading>
+
+ <p> You can control who can print to what printers by using
+ the UNIX group mechanism and the <tt/rg/ capability in
+ <tt>/etc/printcap</tt>. Just place the users you want to
+ have access to a printer in a certain group, and then name
+ that group in the <tt/rg/ capability.
+
+ Users outside the group (including root) will be greeted
+ with
+<tscreen><verb>
+lpr: Not a member of the restricted group
+</verb></tscreen>
+ if they try to print to the controlled printer.
+
+ As with the <tt/sc/ (suppress multiple copies) capability,
+ you need to specify <tt/rg/ on remote hosts that also have
+ access to your printers, if you feel it's appropriate (see
+ section <ref name="Printers Installed on Remote Hosts"
+ id="printing:advanced:network:rm">).
+
+ For example, we'll let anyone access the printer
+ <tt/rattan/, but only those in group <tt/artists/ can use
+ <tt/bamboo/. Here's the familiar <tt>/etc/printcap</tt>
+ for host rose:
+<code>
+#
+# /etc/printcap for host rose - restricted group for bamboo
+#
+rattan|line|diablo|lp|Diablo 630 Line Printer:\
+ :sh:sd=/var/spool/lpd/rattan:\
+ :lp=/dev/lpt0:\
+ :if=/usr/local/libexec/if-simple:
+
+bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
+ :sh:sd=/var/spool/lpd/bamboo:sc:rg=artists:\
+ :lp=/dev/ttyd5:fs#0x82000e1:xs#0x820:rw:\
+ :if=/usr/local/libexec/psif:\
+ :df=/usr/local/libexec/psdf:
+</code>
+ Let's leave the other example <tt>/etc/printcap</tt> file
+ (for the host orchid) alone. Of course, anyone on orchid
+ can print to <tt/bamboo/. It might be the case that we
+ only allow certain logins on orchid anyway, and want them
+ to have access to the printer. Or not.
+
+ <em/Note:/ there can be only one restricted group per
+ printer.
+
+ <sect2><heading>Controlling Sizes of Jobs Submitted<label
+ id="printing:advanced:restricting:sizes"></heading>
+
+ <p> If you have many users accessing the printers, you
+ probably need to put an upper limit on the sizes of the
+ files users can submit to print. After all, there's only
+ so much free space on the filesystem that houses the
+ spooling directories, and you also need to make sure
+ there's room for the jobs of other users.
+
+ LPD enables you to limit the maximum byte size a file in a
+ job can be with the <tt/mx/ capability. The units are in
+ BUFSIZ blocks, which are 1024 bytes. If you put a zero
+ for this capability, there'll be no limit on file size.
+ Note that the limit applies to <em/files/ in a job, and
+ <em/not/ the total job size.
+
+ LPD won't refuse a file that's larger than the limit you
+ place on a printer. Instead, it'll queue as much of the
+ file up to the limit, which will then get printed. The
+ rest will be discarded. Whether this is correct behavior
+ is up for debate.
+
+ Let's add limits to our example printers <tt/rattan/ and
+ <tt/bamboo/. Since those artists' PostScript files tend
+ to be large, we'll limit them to five megabytes. We'll
+ put no limit on the plain text line printer:
+<code>
+#
+# /etc/printcap for host rose
+#
+
+#
+# No limit on job size:
+#
+rattan|line|diablo|lp|Diablo 630 Line Printer:\
+ :sh:sd=/var/spool/lpd/rattan:\
+ :lp=/dev/lpt0:\
+ :if=/usr/local/libexec/if-simple:
+
+#
+# Limit of five megabytes:
+#
+bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
+ :sh:sd=/var/spool/lpd/bamboo:sc:rg=artists:mx#5000:\
+ :lp=/dev/ttyd5:fs#0x82000e1:xs#0x820:rw:\
+ :if=/usr/local/libexec/psif:\
+ :df=/usr/local/libexec/psdf:
+</code>
+ Again, the limits apply to the local users only. If
+ you've set up access to your printers remotely, remote
+ users won't get those limits. You'll need to specify the
+ <tt/mx/ capability in the remote <tt>/etc/printcap</tt>
+ files as well. See section <ref name="Printers Installed
+ on Remote Hosts" id="printing:advanced:network:rm"> for
+ more information on remote printing.
+
+ There's another specialized way to limit job sizes from
+ remote printers; see section <ref
+ id="printing:advanced:restricting:remote"
+ name="Restricting Jobs from Remote Printers">.
+
+ <sect2><heading>Restricting Jobs from Remote Printers<label
+ id="printing:advanced:restricting:remote"></heading>
+
+ <p> The LPD spooling system provides several ways to restrict
+ print jobs submitted from remote hosts:
+
+ <descrip>
+ <tag/Host restrictions/
+
+ You can control from which remote hosts a local LPD
+ accepts requests with the files
+ <tt>/etc/hosts.equiv</tt> and <tt>/etc/hosts.lpd</tt>.
+ LPD checks to see if an incoming request is from a
+ host listed in either one of these files. If not, LPD
+ refuses the request.
+
+ The format of these files is simple: one host name per
+ line. Note that the file <tt>/etc/hosts.equiv</tt> is
+ also used by the ruserok(3) protocol, and affects
+ programs like <tt/rsh/ and <tt/rcp/, so be careful.
+
+ For example, here's the <tt>/etc/hosts.lpd</tt> file
+ on the host rose:
+<code>
+orchid
+violet
+madrigal.fishbaum.de
+</code>
+ This means rose will accept requests from the hosts
+ orchid, violet, and madrigal.fishbaum.de. If any
+ other host tries to access rose's LPD, LPD will
+ refuse them.
+
+ <tag/Size restrictions/
+
+ You can control how much free space there needs to
+ remain on the filesystem where a spooling directory
+ resides. Make a file called <tt/minfree/ in the
+ spooling directory for the local printer. Insert in
+ that file a number representing how many disk blocks
+ (512 bytes) of free space there has to be for a remote
+ job to be accepted.
+
+ This lets you insure that remote users won't fill your
+ filesystem. You can also use it to give a certain
+ priority to local users: they'll be able to queue jobs
+ long after the free disk space has fallen below the
+ amount specified in the <tt/minfree/ file.
+
+ For example, let's add a <tt/minfree/ file for the
+ printer <tt/bamboo/. We examine
+ <tt>/etc/printcap</tt> to find the spooling directory
+ for this printer; here's <tt/bamboo/'s entry:
+<tscreen><verb>
+bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
+ :sh:sd=/var/spool/lpd/bamboo:sc:rg=artists:mx#5000:\
+ :lp=/dev/ttyd5:fs#0x82000e1:xs#0x820:rw:mx#5000:\
+ :if=/usr/local/libexec/psif:\
+ :df=/usr/local/libexec/psdf:
+</verb></tscreen>
+ The spooling directory is the given in the <tt/sd/
+ capability. We'll make three megabytes (which is 6144
+ disk blocks) the amount of free disk space that must
+ exist on the filesystem for LPD to accept remote jobs:
+<tscreen><verb>
+echo 6144 > /var/spool/lpd/bamboo/minfree
+</verb></tscreen>
+ <tag/User restrictions/
+
+ You can control which remote users can print to local
+ printers by specifying the <tt/rs/ capability in
+ <tt>/etc/printcap</tt>. When <tt/rs/ appears in the
+ entry for a locally-attached printer, LPD will accept
+ jobs from remote hosts <em/if/ the user submitting the
+ job also has an account of the same login name on the
+ local host. Otherwise, LPD refuses the job.
+
+ This capability is particularly useful in an
+ environment where there are (for example) different
+ departments sharing a network, and some users
+ transcend departmental boundaries. By giving them
+ accounts on your systems, they can use your printers
+ from their own departmental systems. If you'd rather
+ allow them to use <em/only/ your printers and not your
+ compute resources, you can give them ``token''
+ accounts, with no home directory and a useless shell
+ like <tt>/usr/bin/false</tt>.
+ </descrip>
+
+ <sect1><heading>Accounting for Printer Usage<label
+ id="printing:advanced:acct"></heading>
+
+ <p> So, you need to charge for printouts. And why not? Paper
+ and ink cost money. And then there are maintenance
+ costs---printers are loaded with moving parts and tend to
+ break down. You've examined your printers, usage patterns,
+ and maintenance fees and have come up with a per-page (or
+ per-foot, per-meter, or per-whatever) cost. Now, how do you
+ actually start accounting for printouts?
+
+ Well, the bad news is the LPD spooling system doesn't
+ provide much help in this department. Accounting is highly
+ dependent on the kind of printer in use, the formats being
+ printed, and <em/your/ requirements in charging for printer
+ usage.
+
+ To implement accounting, you have to modify a printer's text
+ filter (to charge for plain text jobs) and the conversion
+ filters (to charge for other file formats), to count pages
+ or query the printer for pages printed. You can't get away
+ with using the simple output filter, since it cannot do
+ accounting. See section <ref name="Filters"
+ id="printing:advanced:filter-intro">.
+
+ Generally, there are two ways to do accounting:
+ <itemize>
+ <item><em/Periodic accounting/ is the more common way,
+ possibly because it's easier. Whenever someone prints a
+ job, the filter logs the user, host, and number of pages
+ to an accounting file. Every month, semester, year, or
+ whatever time period you prefer, you collect the
+ accounting files for the various printers, tally up the
+ pages printed by users, and charge for usage. Then you
+ truncate all the logging files, starting with a clean
+ slate for the next period.
+
+ <item><em/Timely accounting/ is less common, probably
+ because it's more difficult. This method has the
+ filters charge users for printouts as soon as they use
+ the printers. Like disk quotas, the accounting is
+ immediate. You can prevent users from printing when
+ their account goes in the red, and might provide a way
+ for users to check and adjust their ``print quotas.''
+ But this method requires some database code to track
+ users and their quotas.
+ </itemize>
+
+ The LPD spooling system supports both methods easily: since
+ you have to provide the filters (well, most of the time),
+ you also have to provide the accounting code. But there is
+ a bright side: you have enormous flexibility in your
+ accounting methods. For example, you choose whether to use
+ periodic or timely accounting. You choose what information
+ to log: user names, host names, job types, pages printed,
+ square footage of paper used, how long the job took to
+ print, and so forth. And you do so by modifying the filters
+ to save this information.
+
+ <sect2><heading>Quick and Dirty Printer Accounting</heading>
+
+ <p> FreeBSD comes with two programs that can get you set up
+ with simple periodic accounting right away. They are the
+ text filter <tt/lpf/, described in section <ref
+ id="printing:advanced:lpf" name="lpf: a Text Filter">, and
+ <tt/pac/, a program to gather and total entries from
+ printer accounting files.
+
+ As mentioned in the section on filters (<ref
+ id="printing:advanced:filters" name="Filters">), LPD
+ starts the text and the conversion filters with the name
+ of the accounting file to use on the filter command
+ line. The filters can use this argument to know where
+ to write an accounting file entry. The name of this
+ file comes from the <tt/af/ capability in
+ <tt>/etc/printcap</tt>, and if not specified as an
+ absolute path, is relative to the spooling directory.
+
+ LPD starts <tt/lpf/ with page width and length arguments
+ (from the <tt/pw/ and <tt/pl/ capabilities). <tt/lpf/
+ uses these arguments to determine how much paper will be
+ used. After sending the file to the printer, it then
+ writes an accounting entry in the accounting file. The
+ entries look like this:
+<tscreen><verb>
+ 2.00 rose:andy
+ 3.00 rose:kelly
+ 3.00 orchid:mary
+ 5.00 orchid:mary
+ 2.00 orchid:zhang
+</verb></tscreen>
+ You should use a separate accounting file for each
+ printer, as <tt/lpf/ has no file locking logic built into
+ it, and two <tt/lpf/s might corrupt each other's entries
+ if they were to write to the same file at the same time.
+ A easy way to insure a separate accounting file for each
+ printer is to use <tt/af=acct/ in <tt>/etc/printcap</tt>.
+ Then, each accounting file will be in the spooling directory
+ for a printer, in a file named <tt/acct/.
+
+ When you're ready to charge users for printouts, run the
+ <tt/pac/ program. Just change to the spooling directory
+ for the printer you want to collect on and type <tt/pac/.
+ You'll get a dollar-centric summary like the following:
+<code>
+ Login pages/feet runs price
+orchid:kelly 5.00 1 $ 0.10
+orchid:mary 31.00 3 $ 0.62
+orchid:zhang 9.00 1 $ 0.18
+rose:andy 2.00 1 $ 0.04
+rose:kelly 177.00 104 $ 3.54
+rose:mary 87.00 32 $ 1.74
+rose:root 26.00 12 $ 0.52
+
+total 337.00 154 $ 6.74
+</code>
+ These are the arguments <tt/pac/ expects:
+ <descrip>
+ <tag/<tt/-P<it/printer///
+
+ Which <it/printer/ to summarize. This option works
+ only if there's an absolute path in the <tt/af/
+ capability in <tt>/etc/printcap</tt>.
+
+ <tag/<tt/-c//
+
+ Sort the output by cost instead of alphabetically by
+ user name.
+
+ <tag/<tt/-m//
+
+ Ignore host name in the accounting files. With this
+ option, user smith on host alpha is the same user
+ smith on host gamma. Without, they're different users.
+
+ <tag/<tt/-p<it/price///
+
+ Compute charges with <it/price/ dollars per page or
+ per foot instead of the price from the <tt/pc/
+ capabilty in <tt>/etc/printcap</tt>, or two cents (the
+ default). You can specify <it/price/ as a floating
+ point number.
+
+ <tag/<tt/-r//
+
+ Reverse the sort order.
+
+ <tag/<tt/-s//
+
+ Make an accounting summary file and truncate the
+ accounting file.
+
+ <tag/<tt/<it/names...///
+
+ Print accounting information for the given user
+ <it/names/ only.
+ </descrip>
+
+ In the default summary that <tt/pac/ produces, you see the
+ number of pages printed by each user from various hosts.
+ If, at your site, host doesn't matter (because users can
+ use any host), run <tt/pac -m/, to produce the following
+ summary:
+<code>
+ Login pages/feet runs price
+andy 2.00 1 $ 0.04
+kelly 182.00 105 $ 3.64
+mary 118.00 35 $ 2.36
+root 26.00 12 $ 0.52
+zhang 9.00 1 $ 0.18
+
+total 337.00 154 $ 6.74
+</code>
+ To compute the dollar amount due, <tt/pac/ uses the
+ <tt/pc/ capability in the <tt>/etc/printcap</tt> file
+ (default of 200, or 2 cents per page). Specify, in
+ hundreths of cents, the price per page or per foot you
+ want to charge for printouts in this capability. You can
+ override this value when you run <tt/pac/ with the <tt/-p/
+ option. The units for the <tt/-p/ option are in dollars,
+ though, not hundreths of cents. For example,
+<tscreen><verb>
+pac -p1.50
+</verb></tscreen>
+ makes each page cost one dollar and fifty cents. You can
+ really rake in the profits by using this option.
+
+ Finally, running <tt/pac -s/ will save the summary
+ information in a summary accounting file, which is named
+ the same as the printer's accounting file, but with
+ <tt/_sum/ appended to the name. It then truncates the
+ accounting file. When you run <tt/pac/ again, it rereads
+ the summary file to get starting totals, then adds
+ information from the regular accounting file.
+
+
+ <sect2><heading>How Can You Count Pages Printed?</heading>
+
+ <p> In order to perform even remotely accurate accounting,
+ you need to be able to determine how much paper a job
+ uses. This is the essential problem of printer
+ accounting.
+
+ For plain text jobs, the problem's not that hard to solve:
+ you count how many lines are in a job and compare it to
+ how many lines per page your printer supports. Don't
+ forget to take into account backspaces in the file which
+ overprint lines, or long logical lines that wrap onto one
+ or more additional physical lines.
+
+ The text filter <tt/lpf/ (introduced in <ref
+ id="printing:advanced:lpf" name="lpf: a Text Filter">)
+ takes into account these things when it does accounting.
+ If you're writing a text filter which needs to do
+ accounting, you might want to examine <tt/lpf/'s source
+ code.
+
+ How do you handle other file formats, though?
+
+ Well, for DVI-to-LaserJet or DVI-to-PostScript conversion,
+ you can have your filter parse the diagnostic output of
+ <tt/dvilj/ or <tt/dvips/ and look to see how many pages
+ were converted. You might be able to do similar things
+ with other file formats and conversion programs.
+
+ But these methods suffer from the fact that the printer
+ may not actually print all those pages. For example, it
+ could jam, run out of toner, or explode---and the user
+ would still get charged.
+
+ So, what can you do?
+
+ There is only one <em/sure/ way to do <em/accurate/
+ accounting. Get a printer that can tell you how much
+ paper it uses, and attach it via a serial line or a
+ network connection. Nearly all PostScript printers
+ support this notion. Other makes and models do as well
+ (networked Imagen laser printers, for example). Modify
+ the filters for these printers to get the page usage after
+ they print each job and have them log accounting
+ information based on that value <em/only/. There's no
+ line counting nor error-prone file examination required.
+
+ Of course, you can always be generous and make all
+ printouts free.
+
+ <sect><heading>Alternatives to the Standard Spooler<label
+ id="printing:lpd-alternatives"></heading>
+
+ <p> If you've been reading straight through this manual, by now
+ you've learned just about everything there is to know about
+ the LPD spooling system that comes with FreeBSD. You can
+ probably appreciate many of its shortcomings, which naturally
+ leads to the question: ``What other spooling systems are out
+ there (and work with FreeBSD)?''
+
+ Unfortunately, I've located only <em/two/ alternatives---and
+ they're almost identical to each other! They are
+ <descrip>
+ <tag/PLP, the Portable Line Printer Spooler System/
+
+ PLP was based on software developed by Patrick Powell and
+ then maintained by an Internet-wide group of developers.
+ The main site for the software is at <htmlurl
+ url="ftp://ftp.iona.ie/pub/plp"
+ name="ftp://ftp.iona.ie/pub/plp">. There's also a <htmlurl
+ url="http://www.iona.ie:8000/www/hyplan/jmason/plp.html"
+ name="web page">.
+
+ It's quite similar to the BSD LPD spooler, but boasts a
+ host of features, including:
+ <itemize>
+ <item>Better network support, including built-in support
+ for networked printers, NIS-maintained printcaps, and
+ NFS-mounted spooling directories
+
+ <item>Sophisticated queue management, allowing multiple
+ printers on a queue, transfer of jobs between queues,
+ and queue redirection
+
+ <item>Remote printer control functions
+
+ <item>Prioritization of jobs
+
+ <item>Expansive security and access options
+ </itemize>
+
+ <tag/LPRng/
+
+ LPRng, which purportedly means ``LPR: the Next
+ Generation'' is a complete rewrite of PLP. Patrick Powell
+ and Justin Mason (the principal maintainer of PLP)
+ collaborated to make LPRng. The main site for LPRng is
+ <htmlurl url="ftp://dickory.sdsu.edu/pub/LPRng"
+ name="ftp://dickory.sdsu.edu/pub/LPRng">.
+ </descrip>
+
+
+ <sect><heading>Acknowledgments</heading>
+
+ <p> I'd like to thank the following people who've assisted in
+ the development of this document:
+
+ <descrip>
+ <tag/Daniel Eischen <tt/&lt;deischen@iworks.interworks.org&gt;//
+
+ For providing a plethora of HP filter programs for perusal.
+
+ <tag/Jake Hamby <tt/&lt;jehamby@lightside.com&gt;//
+
+ For the Ghostscript-to-HP filter.
+
+ <tag/My wife, Mary Kelly <tt/&lt;urquhart@argyre.colorado.edu&gt;//
+
+ For allowing me to spend more time with FreeBSD than with her.
+
+ </descrip>
diff --git a/share/doc/handbook/routing.sgml b/share/doc/handbook/routing.sgml
new file mode 100644
index 000000000000..5441cce05ffd
--- /dev/null
+++ b/share/doc/handbook/routing.sgml
@@ -0,0 +1,279 @@
+<!-- $Id$ -->
+<!-- The FreeBSD Documentation Project -->
+<!-- <!DOCTYPE linuxdoc PUBLIC '-//FreeBSD//DTD linuxdoc//EN'> -->
+
+ <sect><heading>Gateways and routes<label id="routing"></heading>
+
+ <p><em>Contributed by &a.gryphon;.<newline>6 October 1995.</em>
+
+ For one machine to be able to find another, there must be a
+ mechanism in place to describe how to get from one to the
+ other. This is called Routing. A ``route'' is a defined
+ pair of addresses: a <bf>destination</bf> and a
+ <bf>gateway</bf>. The pair indicates that if you are
+ trying to get to this <em>destination</em>, send along
+ through this <em>gateway</em>. There are three types of
+ destinations: individual hosts, subnets, and ``default''. The
+ ``default route'' is used if none of the other routes
+ apply. We will talk a little bit more about default routes
+ later on. There are also three types of gateways:
+ individual hosts, interfaces (also called ``links''), and
+ ethernet hardware addresses.
+
+ <sect1><heading>An example</heading>
+
+ <p>To illustrate different aspects of routing, we will use
+ the following example which is the output of the command
+ <tt>netstat -r</tt>:
+
+<tscreen><verb>
+Destination Gateway Flags Refs Use Netif Expire
+
+default outside-gw UGSc 37 418 ppp0
+localhost localhost UH 0 181 lo0
+test0 0:e0:b5:36:cf:4f UHLW 5 63288 ed0 77
+10.20.30.255 link#1 UHLW 1 2421
+foobar.com link#1 UC 0 0
+host1 0:e0:a8:37:8:1e UHLW 3 4601 lo0
+host2 0:e0:a8:37:8:1e UHLW 0 5 lo0 =>
+host2.foobar.com link#1 UC 0 0
+224 link#1 UC 0 0
+</verb></tscreen>
+
+ The first two lines specify the default route (which we
+ will cover in the next section) and the <tt>localhost</tt> route.
+
+ The interface (<tt>Netif</tt> column) that it specifies to use
+ for <tt>localhost</tt> is <tt>lo0</tt>, also known as the
+ loopback device. This says to keep all traffic for this
+ destination internal, rather than sending it out over the
+ LAN, since it will only end up back where it started
+ anyway.
+
+ The next thing that stands out are the
+ ``<tt>0:e0:...</tt>'' addresses. These are ethernet
+ hardware addresses. FreeBSD will automatically identify any
+ hosts (<tt>test0</tt> in the example) on the local ethernet and
+ add a route for that host, directly to it over the ethernet
+ interface, <tt>ed0</tt>. There is also a timeout
+ (<tt>Expire</tt> column) associated with this type of route,
+ which is used if we fail to hear from the host in a
+ specific amount of time. In this case the route will be
+ automatically deleted. These hosts are identified using a
+ mechanism known as RIP (Routing Information Protocol),
+ which figures out routes to local hosts based upon a
+ shortest path determination.
+
+ FreeBSD will also add subnet routes for the local subnet
+ (<tt>10.20.30.255</tt> is the broadcast address for the subnet
+ <tt>10.20.30</tt>, and <tt>foobar.com</tt> is the domain name
+ associated with that subnet). The designation <tt>link&num;1</tt>
+ refers to the first ethernet card in the machine. You'll
+ notice no additional interface is specified for those.
+
+ Both of these groups (local network hosts and local
+ subnets) have their routes automatically configured by a
+ daemon called <tt>routed</tt>. If this is not run, then only
+ routes which are statically defined (ie. entered
+ explicitly) will exist.
+
+ The <tt>host1</tt> line refers to our host, which it knows by
+ ethernet address. Since we are the sending host, FreeBSD
+ knows to use the loopback interface (<tt>lo0</tt>) rather than
+ sending it out over the ethernet interface.
+
+ The two <tt>host2</tt> lines are an example of what happens
+ when we use an ifconfig alias (see the section of ethernet
+ for reasons why we would do this). The <tt>=&gt</tt>
+ symbol after the <tt>lo0</tt> interface says that not only are
+ we using the loopback (since this is address also refers to
+ the local host), but specifically it is an alias. Such
+ routes only show up on the host that supports the alias;
+ all other hosts on the local network will simply have a
+ <tt>link&num;1</tt> line for such.
+
+ The final line (destination subnet <tt>224</tt>) deals with
+ MultiCasting, which will be covered in a another section.
+
+ The other column that we should talk about are the
+ <tt>Flags</tt>. Each route has different attributes that are
+ described in the column. Below is a short table of some of
+ these flags and their meanings:
+
+ <descrip>
+
+ <tag/U/ <bf/Up:/ The route is active.
+
+ <tag/H/ <bf/Host:/ The route destination is a single host.
+
+ <tag/G/ <bf/Gateway:/ Send anything for this destination
+ on to this remote system, which will figure out from
+ there where to send it.
+
+ <tag/S/ <bf/Static:/ This route was configured manually,
+ not automatically generated by the system.
+
+ <tag/C/ <bf/Clone:/ Generates a new route based upon this
+ route for machines we connect to. This type of route is
+ normally used for local networks.
+
+ <tag/W/ <bf/WasCloned/ Indicated a route that was
+ auto-configured based upon a local area network (Clone)
+ route.
+
+ <tag/L/ <bf/Link:/ Route involves references to ethernet
+ hardware.
+
+ </descrip>
+
+
+ <sect1><heading>Default routes</heading>
+
+ <p>When the local system needs to make a connection to
+ remote host, it checks the routing table to determine if
+ a known path exists. If the remote host falls into a
+ subnet that we know how to reach (Cloned routes), then
+ the system checks to see if it can connect along that
+ interface.
+
+ If all known paths fail, the system has one last option:
+ the <bf>default</bf> route. This route is a special type
+ of gateway route (usually the only one present in the
+ system), and is always marked with a ``<tt>c</tt>'' in
+ the flags field. For hosts on a local area network, this
+ gateway is set to whatever machine has a direct
+ connection to the outside world (whether via PPP link, or
+ your hardware device attached to a dedicated data line).
+
+ If you are configuring the default route for a machine
+ which itself is functioning as the gateway to the outside
+ world, then the default route will be the gateway machine
+ at your Internet Service Provider's (ISP) site.
+
+ Let's look at an example of default routes. This is a
+ common configuration:
+<tscreen><verb>
+[Local2] <--ether--> [Local1] <--PPP--> [ISP-Serv] <--ether--> [T1-GW]
+</verb></tscreen>
+
+ The hosts <tt>Local1</tt> and <tt>Local2</tt> are at your
+ site, with the formed being your PPP connection to your
+ ISP's Terminal Server. Your ISP has a local network at
+ their site, which has, among other things, the server
+ where you connect and a hardware device (T1-GW) attached
+ to the ISP's internet feed.
+
+ The default routes for each of your machines will be:
+
+<tscreen><verb>
+host default gateway interface
+---- --------------- ---------
+Local2 Local1 ethernet
+Local1 T1-GW PPP
+</verb></tscreen>
+
+ A common question is ``Why (or how) would we set the
+ T1-GW to be the default gateway for Local1, rather than
+ the ISP server it is connected to?''.
+
+ Remember, since the PPP interface is using an address on
+ the ISP's local network for your side of the connection,
+ routes for any other machines on the ISP's local network
+ will be automatically generated. Hence, you will already
+ know how to reach the T1-GW machine, so there is no need
+ for the intermediate step of sending traffic to the ISP
+ server.
+
+ As a final note, it is common to use the address ``<tt>...1</tt>''
+ as the gateway address for your local network. So (using
+ the same example), if your local class-C address space
+ was <tt>10.20.30</tt> and your ISP was using <tt>10.9.9</tt> then the
+ default routes would be:
+
+<tscreen><verb>
+Local2 (10.20.30.2) --> Local1 (10.20.30.1)
+Local1 (10.20.30.1, 10.9.9.30) --> T1-GW (10.9.9.1)
+</verb></tscreen>
+
+ <sect1><heading>Dual homed hosts</heading>
+
+ <p>There is one other type of configuration that we should
+ cover, and that is a host that sits on two different
+ networks. Technically, any machine functioning as a
+ gateway (in the example above, using a PPP connection)
+ counts as a dual-homed host. But the term is really only
+ used to refer to a machine that sits on two local-area
+ networks.
+
+ In one case, the machine as two ethernet cards, each
+ having an address on the seperate subnets. Alternately,
+ the machine may only have one ethernet card, and be using
+ ifconfig aliasing. The former is used if two physically
+ separate ethernet networks are in use, the latter if
+ there is one physical network segment, but two logically
+ seperate subnets.
+
+ Either way, routing tables are set up so that each subnet
+ knows that this machine is the defined gateway (inbound
+ route) to the other subnet. This configuration, with the
+ machine acting as a Bridge between the two subnets, is
+ often used when we need to implement packet filtering or
+ firewall security in either or both directions.
+
+ <sect1><heading>Routing propogation</heading>
+
+ <p>We have already talked about how we define our routes to
+ the outside world, but not about how the outside world
+ finds us.
+
+ We already know that routing tables can be set up so that
+ all traffic for a particular address space (in our
+ examples, a class-C subnet) can be sent to a particular
+ host on that network, which will forward the packets
+ inbound.
+
+ When you get an address space assigned to your site, your
+ service provider will set up their routing tables so that
+ all traffic for your subnet will be sent down your PPP
+ link to your site. But how do sites across the country
+ know to send to your ISP?
+
+ There is a system (much like the distributed DNS
+ information) that keeps track of all assigned
+ address-spaces, and defines their point of connection to
+ the Internet Backbone. The ``Backbone'' are the main
+ trunk lines that carry internet traffic across the
+ country, and around the world. Each backbone machine has
+ a copy of a master set of tables, which direct traffic
+ for a particular network to a specific backbone carrier,
+ and from there down the chain of service providers until
+ it reaches your network.
+
+ It is the task of your service provider to advertise to
+ the backbone sites that they are the point of connection
+ (and thus the path inward) for your site. This is known
+ as route propogation.
+
+<!--
+ <sect1><heading>Multicast Routing</heading>
+-->
+
+ <sect1><heading>Troubleshooting</heading>
+
+ <p>Sometimes, there is a problem with routing propogation,
+ and some sites are unable to connect to you. Perhaps the
+ most useful command for trying to figure out where a
+ routing is breaking down is the <tt>traceroute(8)</tt>
+ command. It is equally useful if you cannot seem to make
+ a connection to a remote machine (ie. <tt>ping(8)</tt>
+ fails).
+
+ The <tt>traceroute(8)</tt> command is run with the name
+ of the remote host you are trying to connect to. It will
+ show the gateway hosts along the path of the attempt,
+ eventually either reaching the target host, or
+ terminating because of a lack of connection.
+
+ For more information, see the manual page for
+ <tt>traceroute(8)</tt>.
+
diff --git a/share/doc/handbook/skey.sgml b/share/doc/handbook/skey.sgml
new file mode 100644
index 000000000000..865e2ca5cfe0
--- /dev/null
+++ b/share/doc/handbook/skey.sgml
@@ -0,0 +1,302 @@
+<!-- $Id: skey.sgml,v 1.2 1995/09/26 19:12:28 wollman Exp $ -->
+<!-- The FreeBSD Documentation Project -->
+<!--
+Copyright 1995 Massachusetts Institute of Technology
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that both the above copyright notice and this
+permission notice appear in all copies, that both the above
+copyright notice and this permission notice appear in all
+supporting documentation, and that the name of M.I.T. not be used
+in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission. M.I.T. makes
+no representations about the suitability of this software for any
+purpose. It is provided "as is" without express or implied
+warranty.
+
+THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
+ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+SHALL M.I.T. 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.
+-->
+
+<sect><heading>S/Key<label id="skey"></heading>
+
+<p><em>Contributed by &a.wollman;<newline>25 September 1995.</em>
+
+<p>S/Key is a one-time password scheme based on a one-way hash function
+(in our version, this is MD4 for compatibility; other versions have
+used MD5 and DES-MAC). S/Key has been a standard part of all FreeBSD
+distributions since version 1.1.5, and is also implemented on a large
+and growing number of other systems. S/Key is a registered trademark
+of Bell Communications Research, Inc.
+
+<!-- XXX - is there a better word to use than UNIX? -->
+<p>There are three different sorts of passwords which we will talk about
+in the discussion below. The first is your usual UNIX-style or Kerberos
+password; we'll call this a ``UNIX password''. The second sort is the
+one-time password which is generated by the S/Key `<tt/key/' program and
+accepted by the `<tt/keyinit/' program and the login prompt; we'll call
+this a ``one-time password''. The final sort of password is the
+secret password which you give to the `<tt/key/' program (and sometimes the
+`<tt/keyinit/' program) which it uses to generate one-time passwords; we'll
+call it a ``secret password'' or just unqualified ``password''.
+
+<p>The secret password does not necessarily have anything to do with your
+UNIX password (while they can be the same, this is not recommended).
+While UNIX passwords are limited to eight characters in length, your
+S/Key secret password can be as long as you like; I use seven-word
+phrases. In general, the S/Key system operates completely
+independently of the UNIX password system.
+
+<p>There are in addition two other sorts of data involved in the S/Key
+system; one is called the ``seed'' or (confusingly) ``key'', and
+consists of two letters and five digits, and the other is the
+``iteration count'' and is a number between 100 and 1. S/Key
+constructs a one-time password from these components by concatenating
+the seed and the secret password, then applying a one-way hash (the
+RSA Data Security, Inc., MD4 secure hash function) iteration-count
+times, and turning the result into six short English words. The
+`<tt/login/' and `<tt/su/' programs keep track of the last one-time
+password used, and the user is authenticated if the hash of the
+user-provided password is equal to the previous password. Because a
+one-way hash function is used, it is not possible to generate future
+one-time passwords having overheard one which was successfully used;
+the iteration count is decremented after each successful login to keep
+the user and login program in sync. (When you get the iteration count
+down to 1, it's time to reinitialize S/Key.)
+
+<p>There are four programs involved in the S/Key system which we will
+discuss below. The `<tt/key/' program accepts an iteration count, a
+seed, and a secret password, and generates a one-time password. The
+`<tt/keyinit/' program is used to initialized S/Key, and to change
+passwords, iteration counts, or seeds; it takes either a secret
+password, or an iteration count, seed, and one-time password. The
+`<tt/keyinfo/' program examines the <tt>/etc/skeykeys</tt> file and
+prints out the invoking user's current iteration count and seed.
+Finally, the `<tt/login/' and `<tt/su/' programs contain the necessary
+logic to accept S/Key one-time passwords for authentication. The
+`<tt/login/' program is also capable of disallowing the use of UNIX
+passwords on connections coming from specified addresses.
+
+<p>There are four different sorts of operations we will cover. The first
+is using the `<tt/keyinit/' program over a secure connection to set up
+S/Key for the first time, or to change your password or seed. The
+second operation is using the `<tt/keyinit/' program over an insecure
+connection, in conjunction with the `<tt/key/' program over a secure
+connection, to do the same. The third is using the `<tt/key/' program to
+log in over an insecure connection. The fourth is using the `<tt/key/'
+program to generate a number of keys which can be written down or
+printed out to carry with you when going to some location without
+secure connections to anywhere (like at a conference).
+
+<sect1><heading>Secure connection initialization</heading>
+
+<p>To initialize S/Key, change your password, or change your seed while
+logged in over a secure connection (e.g., on the console of a machine),
+use the `<tt/keyinit/' command without any parameters while logged in as
+yourself:
+
+<tscreen><verb>
+$ keyinit
+Updating wollman: ) these will not appear if you
+Old key: ha73895 ) have not used S/Key before
+Reminder - Only use this method if you are directly connected.
+If you are using telnet or rlogin exit with no password and use keyinit -s.
+Enter secret password: ) I typed my pass phrase here
+Again secret password: ) I typed it again
+
+ID wollman s/key is 99 ha73896 ) discussed below
+SAG HAS FONT GOUT FATE BOOM )
+</verb></tscreen>
+
+<p>There is a lot of information here. At the `Enter secret password:'
+prompt, you should enter some password or phrase (I use phrases of
+minimum seven words) which will be needed to generate login keys. The
+line starting `ID' gives the parameters of your particular S/Key
+instance: your login name, the iteration count, and seed. When
+logging in with S/Key, the system will remember these parameters and
+present them back to you so you don't have to remember them. The last
+line gives the particular one-time password which corresponds to those
+parameters and your secret password; if you were to re-login
+immediately, this one-time password is the one you would use.
+
+<sect1><heading>Insecure connection initialization</heading>
+
+<p>To initialize S/Key or change your password or seed over an insecure
+connection, you will need to already have a secure connection to some
+place where you can run the `<tt/key/' program; this might be in the form
+of a desk accessory on a Macintosh, or a shell prompt on a machine you
+trust (we'll show the latter). You will also need to make up an
+iteration count (100 is probably a good value), and you may make up
+your own seed or use a randomly-generated one. Over on the insecure
+connection (to the machine you are initializing), use the `<tt/keyinit -s/'
+command:
+
+<tscreen><verb>
+$ keyinit -s
+Updating wollman:
+Old key: kh94741
+Reminder you need the 6 english words from the skey command.
+Enter sequence count from 1 to 9999: 100 ) I typed this
+Enter new key [default kh94742]:
+s/key 100 kh94742
+</verb></tscreen>
+
+To accept the default seed (which the `keyinit' program confusingly
+calls a `key'), press return. Then move over to your secure
+connection or S/Key desk accessory, and give it the same parameters:
+
+<tscreen><verb>
+$ key 100 kh94742
+Reminder - Do not use this program while logged in via telnet or rlogin.
+Enter secret password: ) I typed my secret password
+HULL NAY YANG TREE TOUT VETO
+</verb></tscreen>
+
+Now switch back over to the insecure connection, and copy the one-time
+password generated by `<tt/key/' over to the `<tt/keyinit/' program:
+
+<tscreen><verb>
+s/key access password: HULL NAY YANG TREE TOUT VETO
+
+ID wollman s/key is 100 kh94742
+HULL NAY YANG TREE TOUT VETO
+</verb></tscreen>
+
+The rest of the description from the previous section applies here as
+well.
+
+<sect1><heading>Diversion: a login prompt</heading>
+
+<p>Before explaining how to generate one-time passwords, we should go
+over an S/Key login prompt:
+
+<tscreen><verb>
+$ telnet himalia
+Trying 18.26.0.186...
+Connected to himalia.lcs.mit.edu.
+Escape character is '^]'.
+s/key 92 hi52030
+Password:
+</verb></tscreen>
+
+Note that, before prompting for a password, the login program
+prints out the iteration number and seed which you will need in order
+to generate the appropriate key. You will also find a useful feature
+(not shown here): if you press return at the password prompt, the
+login program will turn echo on, so you can see what you are typing.
+This can be extremely useful if you are attempting to type in an S/Key
+by hand, such as from a printout.
+
+<p>If this machine were configured to disallow UNIX passwords over a
+connection from my machine, the prompt would have also included the
+annotation `<tt>(s/key required)</tt>', indicating that only S/Key one-time
+passwords will be accepted.
+
+<sect1><heading>Generating a single one-time password</heading>
+
+<p>Now, to generate the one-time password needed to answer this login
+prompt, we use a trusted machine and the `<tt/key/' program. (There are
+versions of the `<tt/key/' program from DOS and Windows machines, and there
+is an S/Key desk accessory for Macintosh computers as well.) The
+command-line `<tt/key/' program takes as its parameters the iteration count
+and seed; you can cut-and-paste right from the login prompt starting
+at ``<tt/key/'' to the end of the line. Thus:
+
+<tscreen><verb>
+$ key 92 hi52030 ) pasted from previous section
+Reminder - Do not use this program while logged in via telnet or rlogin.
+Enter secret password: ) I typed my secret password
+ADEN BED WOLF HAW HOT STUN
+</verb></tscreen>
+
+And in the other window:
+
+<tscreen><verb>
+s/key 92 hi52030 ) from previous section
+Password:
+ (turning echo on)
+Password:ADEN BED WOLF HAW HOT STUN
+Last login: Wed Jun 28 15:31:00 from halloran-eldar.l
+[etc.]
+</verb></tscreen>
+
+This is the easiest mechanism <em/if/ you have a trusted machine.
+
+<sect1><heading>Generating multiple one-time passwords</heading>
+
+<p>Sometimes we have to go places where no trusted machines or
+connections are available. In this case, it is possible to use the
+`<tt/key/' command to generate a number of one-time passwords in the same
+command; these can then be printed out. For example:
+
+<tscreen><verb>
+$ key -n 25 57 zz99999
+Reminder - Do not use this program while logged in via telnet or rlogin.
+Enter secret password:
+33: WALT THY MALI DARN NIT HEAD
+34: ASK RICE BEAU GINA DOUR STAG
+[...]
+56: AMOS BOWL LUG FAT CAIN INCH
+57: GROW HAYS TUN DISH CAR BALM
+</verb></tscreen>
+
+The `<tt/-n 25/' requests twenty-five keys in sequence; the `<tt/57/' indicates
+the <em/ending/ iteration number; and the rest is as before. Note that
+these are printed out in <em/reverse/ order of eventual use. If you're
+really paranoid, you might want to write the results down by hand;
+otherwise you can cut-and-paste into `<tt/lpr/'. Note that each line shows
+both the iteration count and the one-time password; you may still find
+it handy to scratch off passwords as you use them.
+
+<sect1><heading>Restricting use of UNIX passwords</heading>
+
+<p>The configuration file <tt>/etc/skey.access</tt> can be used to
+configure restrictions on the use of UNIX passwords based on the host
+name, user name, terminal port, or IP address of a login session. The
+complete format of the file is documented in the <em/skey.access/(5)
+manual page; there are also some security cautions there which should
+be read before depending on this file for security.
+
+<p>If there is no <tt>/etc/skey.access</tt> file (which is the default
+state as FreeBSD is shipped), then all users will be allowed to use
+UNIX passwords. If the file exists, however, then all users will be
+required to use S/Key unless explicitly permitted to do otherwise by
+configuration statements in the <tt/skey.access/ file. In all cases,
+UNIX passwords are permitted on the console.
+
+<p>Here is a sample configuration file which illustrates the three most
+common sorts of configuration statements:
+
+<tscreen><verb>
+permit internet 18.26.0.0 255.255.0.0
+permit user jrl
+permit port ttyd0
+</verb></tscreen>
+
+The first line (`<tt/permit internet/') allows users whose IP source
+address (which is vulnerable to spoofing) matches the specified value
+and mask, to use UNIX passwords. This should not be considered a
+security mechanism, but rather, a means to remind authorized users
+that they are using an insecure network and need to use S/Key for
+authentication.
+
+<p>The second line (`<tt/permit user/') allows the specified user to
+use UNIX passwords at any time. Generally speaking, this should only
+be used for people who are either unable to use the `<tt/key/'
+program, like those with dumb terminls, or those who are uneducable.
+
+<p>The third line (`<tt/permit port/') allows all users logging in on
+the specified terminal line to use UNIX passwords; this would be used
+for dial-ups.
+
diff --git a/share/examples/sup/ports-supfile b/share/examples/sup/ports-supfile
new file mode 100644
index 000000000000..ffc078be4542
--- /dev/null
+++ b/share/examples/sup/ports-supfile
@@ -0,0 +1,26 @@
+ports-base release=current host=SUP.FreeBSD.ORG hostbase=/home base=/usr prefix=/usr/ports delete old
+ports-archivers release=current host=SUP.FreeBSD.ORG hostbase=/home base=/usr prefix=/usr/ports delete old
+ports-benchmarks release=current host=SUP.FreeBSD.ORG hostbase=/home base=/usr prefix=/usr/ports delete old
+ports-audio release=current host=SUP.FreeBSD.ORG hostbase=/home base=/usr prefix=/usr/ports delete old
+ports-cad release=current host=SUP.FreeBSD.ORG hostbase=/home base=/usr prefix=/usr/ports delete old
+ports-comms release=current host=SUP.FreeBSD.ORG hostbase=/home base=/usr prefix=/usr/ports delete old
+ports-databases release=current host=SUP.FreeBSD.ORG hostbase=/home base=/usr prefix=/usr/ports delete old
+ports-devel release=current host=SUP.FreeBSD.ORG hostbase=/home base=/usr prefix=/usr/ports delete old
+ports-editors release=current host=SUP.FreeBSD.ORG hostbase=/home base=/usr prefix=/usr/ports delete old
+ports-emulators release=current host=SUP.FreeBSD.ORG hostbase=/home base=/usr prefix=/usr/ports delete old
+ports-games release=current host=SUP.FreeBSD.ORG hostbase=/home base=/usr prefix=/usr/ports delete old
+ports-graphics release=current host=SUP.FreeBSD.ORG hostbase=/home base=/usr prefix=/usr/ports delete old
+ports-japanese release=current host=SUP.FreeBSD.ORG hostbase=/home base=/usr prefix=/usr/ports delete old
+ports-lang release=current host=SUP.FreeBSD.ORG hostbase=/home base=/usr prefix=/usr/ports delete old
+ports-mail release=current host=SUP.FreeBSD.ORG hostbase=/home base=/usr prefix=/usr/ports delete old
+ports-math release=current host=SUP.FreeBSD.ORG hostbase=/home base=/usr prefix=/usr/ports delete old
+ports-net release=current host=SUP.FreeBSD.ORG hostbase=/home base=/usr prefix=/usr/ports delete old
+ports-news release=current host=SUP.FreeBSD.ORG hostbase=/home base=/usr prefix=/usr/ports delete old
+ports-plan9 release=current host=SUP.FreeBSD.ORG hostbase=/home base=/usr prefix=/usr/ports delete old
+ports-print release=current host=SUP.FreeBSD.ORG hostbase=/home base=/usr prefix=/usr/ports delete old
+ports-russian release=current host=SUP.FreeBSD.ORG hostbase=/home base=/usr prefix=/usr/ports delete old
+ports-security release=current host=SUP.FreeBSD.ORG hostbase=/home base=/usr prefix=/usr/ports delete old
+ports-shells release=current host=SUP.FreeBSD.ORG hostbase=/home base=/usr prefix=/usr/ports delete old
+ports-sysutils release=current host=SUP.FreeBSD.ORG hostbase=/home base=/usr prefix=/usr/ports delete old
+ports-utils release=current host=SUP.FreeBSD.ORG hostbase=/home base=/usr prefix=/usr/ports delete old
+ports-x11 release=current host=SUP.FreeBSD.ORG hostbase=/home base=/usr prefix=/usr/ports delete old
diff --git a/share/examples/sup/secure-stable-supfile b/share/examples/sup/secure-stable-supfile
new file mode 100644
index 000000000000..61ac7f0b493a
--- /dev/null
+++ b/share/examples/sup/secure-stable-supfile
@@ -0,0 +1,2 @@
+eBones release=stable host=sup.internat.freebsd.org hostbase=/home base=/usr prefix=/usr/src delete old compress
+secure release=stable host=sup.internat.freebsd.org hostbase=/home base=/usr prefix=/usr/src delete old compress
diff --git a/share/examples/sup/secure-supfile b/share/examples/sup/secure-supfile
new file mode 100644
index 000000000000..716f70c0bb8f
--- /dev/null
+++ b/share/examples/sup/secure-supfile
@@ -0,0 +1,2 @@
+eBones release=current host=sup.internat.freebsd.org hostbase=/home base=/usr prefix=/usr/src delete old compress
+secure release=current host=sup.internat.freebsd.org hostbase=/home base=/usr prefix=/usr/src delete old compress
diff --git a/share/examples/sup/stable-supfile b/share/examples/sup/stable-supfile
new file mode 100644
index 000000000000..5ba1db895a79
--- /dev/null
+++ b/share/examples/sup/stable-supfile
@@ -0,0 +1,15 @@
+src-base release=stable host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
+src-bin release=stable host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
+#src-eBones release=stable host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
+src-etc release=stable host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
+src-games release=stable host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
+src-gnu release=stable host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
+src-include release=stable host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
+src-lib release=stable host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
+src-libexec release=stable host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
+src-sbin release=stable host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
+#src-secure release=stable host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
+src-share release=stable host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
+src-sys release=stable host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
+src-usrbin release=stable host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
+src-usrsbin release=stable host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
diff --git a/share/examples/sup/standard-supfile b/share/examples/sup/standard-supfile
new file mode 100644
index 000000000000..6d0ed19485a3
--- /dev/null
+++ b/share/examples/sup/standard-supfile
@@ -0,0 +1,15 @@
+src-base release=current host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
+src-bin release=current host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
+#src-eBones release=current host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
+src-etc release=current host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
+src-games release=current host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
+src-gnu release=current host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
+src-include release=current host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
+src-lib release=current host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
+src-libexec release=current host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
+src-sbin release=current host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
+#src-secure release=current host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
+src-share release=current host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
+src-sys release=current host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
+src-usrbin release=current host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
+src-usrsbin release=current host=sup.FreeBSD.org hostbase=/home base=/usr prefix=/usr/src delete old use-rel-suffix
diff --git a/share/man/man4/man4.i386/cy.4 b/share/man/man4/man4.i386/cy.4
new file mode 100644
index 000000000000..c1e2dbd8fc3f
--- /dev/null
+++ b/share/man/man4/man4.i386/cy.4
@@ -0,0 +1,241 @@
+.\" Copyright (c) 1990, 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Systems Programming Group of the University of Utah Computer
+.\" Science Department.
+.\" 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.
+.\"
+.\" from: @(#)dca.4 5.2 (Berkeley) 3/27/91
+.\" from: com.4,v 1.1 1993/08/06 11:19:07 cgd Exp
+.\" from: sio.4,v 1.16 1995/06/26 06:05:30 bde Exp $
+.\" $Id$
+.\"
+.Dd October 10, 1995
+.Dt CY 4 i386
+.Os FreeBSD
+.Sh NAME
+.Nm cy
+.Nd
+Cyclades Cyclom-8Y and Cyclom-16Y serial driver
+.Sh SYNOPSIS
+.Cd "device cy0 at isa? tty irq 10 iomem 0xd4000 iosiz 0x2000 vector cyintr
+.Cd "device cy1 at isa? tty irq 11 iomem 0xd6000 iosiz 0x2000 vector cyintr
+.sp
+Minor numbering:
+.br
+0b\fIOLIMMMMM\fR
+.br
+ call\fBO\fRut
+.br
+ \fBL\fRock
+.br
+ \fBI\fRnitial
+.br
+ \fBMMMMMM\fRinor
+.Sh DESCRIPTION
+The
+.Nm cy
+driver provides support for Cyrix CD1400-based
+.Tn EIA
+.Tn RS-232C
+.Pf ( Tn CCITT
+.Tn V.24 )
+communications interfaces (ports) on Cyclades Cyclom-Y boards.
+Each CD1400 provides 4 ports.
+Each Cyclom-8Y has 2 CD1400's giving 8 ports.
+Each Cyclom-16Y's has 4 CD1400's giving 16 ports.
+.Pp
+Input and output for each line may set independently
+to the following speeds:
+50, 75, 110, 134.5, 150, 300, 600, 1200, 1800, 2400, 4800, 9600,
+19200, 38400, 57600, or 115200 bps.
+Other speeds of up to 150000 are supported by the termios interface
+but not by the sgttyb compatibility interface.
+The CD1400 is not fast enough to handle speeds above 115200 bps
+effectively.
+It can transmit on a single line at slightly more than 115200 bps,
+but when 4 lines are active in both directions its limit is about
+90000 bps on each line.
+.\" XXX the following should be true for all serial drivers and
+.\" should not be repeated in the man pages for all serial drivers.
+.\" It was copied from sio.4. The only change was s/sio/cy/g.
+.Pp
+Serial ports controlled by the
+.Nm cy
+driver can be used for both `callin' and `callout'.
+For each port there is a callin device and a callout device.
+The minor number of the callout device is 128 higher
+than that of the corresponding callin port.
+The callin device is general purpose.
+Processes opening it normally wait for carrier
+and for the callout device to become inactive.
+The callout device is used to steal the port from
+processes waiting for carrier on the callin device.
+Processes opening it do not wait for carrier
+and put any processes waiting for carrier on the callin device into
+a deeper sleep so that they do not conflict with the callout session.
+The callout device is abused for handling programs that are supposed
+to work on general ports and need to open the port without waiting
+but are too stupid to do so.
+.Pp
+The
+.Nm cy
+driver also supports an initial-state and a lock-state control
+device for each of the callin and the callout "data" devices.
+The minor number of the initial-state device is 32 higher
+than that of the corresponding data device.
+The minor number of the lock-state device is 64 higher
+than that of the corresponding data device.
+The termios settings of a data device are copied
+from those of the corresponding initial-state device
+on first opens and are not inherited from previous opens.
+Use
+.Xr stty 1
+in the normal way on the initial-state devices to program
+initial termios states suitable for your setup.
+.sp
+The lock termios state acts as flags to disable changing
+the termios state. E.g., to lock a flag variable such as
+CRTSCTS, use
+.Nm stty crtscts
+on the lock-state device. Speeds and special characters
+may be locked by setting the corresponding value in the lock-state
+device to any nonzero value.
+.sp
+Correct programs talking to correctly wired external devices
+work with almost arbitrary initial states and almost no locking,
+but other setups may benefit from changing some of the default
+initial state and locking the state.
+In particular, the initial states for non (POSIX) standard flags
+should be set to suit the devices attached and may need to be
+locked to prevent buggy programs from changing them.
+E.g., CRTSCTS should be locked on for devices that support
+RTS/CTS handshaking at all times and off for devices that don't
+support it at all. CLOCAL should be locked on for devices
+that don't support carrier. HUPCL may be locked off if you don't
+want to hang up for some reason. In general, very bad things happen
+if something is locked to the wrong state, and things should not
+be locked for devices that support more than one setting. The
+CLOCAL flag on callin ports should be locked off for logins
+to avoid certain security holes, but this needs to be done by
+getty if the callin port is used for anything else.
+.Sh FILES
+.Bl -tag -width /dev/ttyic? -compact
+.\" XXX more cloning: s/d/c/g.
+.It Pa /dev/ttyc?
+for callin ports
+.It Pa /dev/ttyic?
+.It Pa /dev/ttylc?
+corresponding callin initial-state and lock-state devices
+.sp
+.\" XXX more cloning: s/a/c/g. No consistency :-(.
+.It Pa /dev/cuac?
+for callout ports
+.It Pa /dev/cuaic?
+.It Pa /dev/cualc?
+corresponding callout initial-state and lock-state devices
+.El
+.sp
+.Bl -tag -width /etc/rc.serial -compact
+.It Pa /etc/rc.serial
+examples of setting the initial-state and lock-state devices
+.\" XXX no examples in rc.serial for cy ports specifically.
+for sio ports (change the device names for cy ports)
+.El
+.Pp
+The devices numbers are made from the set [0-9a-v] so that more than
+10 ports can be supported.
+.\" XXX this is for cy only.
+[0-9a-f] are for the cy0 and [g-v] are for cy1.
+For Cyclom-8Y's, only the first 8 of these are used.
+.Sh DIAGNOSTICS
+.Bl -diag
+.\" XXX back to s/sio/cy/g.
+.It cy%d: silo overflow.
+Problem in the interrupt handler.
+.El
+.Bl -diag
+.It cy%d: interrupt-level buffer overflow.
+Problem in the bottom half of the driver.
+.El
+.Bl -diag
+.It cy%d: tty-level buffer overflow.
+Problem in the application.
+Input has arrived faster than the given module could process it
+and some has been lost.
+.El
+.\" .Bl -diag
+.\" .It sio%d: reduced fifo trigger level to %d.
+.\" Attempting to avoid further silo overflows.
+.\" .El
+.Sh SEE ALSO
+.Xr tty 4 ,
+.Xr termios 4 ,
+.Xr comcontrol 8 ,
+.Xr stty 1 .
+.Sh HISTORY
+The
+.Nm
+driver is derived from the
+.Nm sio
+driver and the NetBSD
+.Nm
+driver and is
+.Ud
+.Sh BUGS
+The naming scheme and the minor numbering scheme limit the number
+of ports to 32.
+.Pp
+BREAK is not yet implemented.
+.Pp
+Serial consoles are not implemented.
+.Pp
+Data loss may occur at very high baud rates on slow systems,
+or with too many ports on any system,
+or on heavily loaded systems when crtscts cannot be used.
+.Pp
+There are too many compile-time-only flags.
+The CD1400 has slightly smaller fifos than the NS16550 (12 bytes
+instead of 16), so it needs pseudo-dma more than a NS16550. The
+default configuration is optimized for generality at about a 30%
+relative cost in efficiency. These compile-time defines may be
+changed for higher efficiency:
+.Pp
+RxFifoThreshold: default 6; on a 486DX-33, this works for 8 ports
+talking to each other at 115200 bps; 11 works for 8 ports talking
+to each other at 57600 bps. The low threshold is not for FreeBSD,
+it's for the CD1400, which can't really keep up with 115200 bps.
+.Pp
+PollMode: required for Cyclom-16Y's; costs 10-20% relative efficiency
+on Cyclom-8Y's (more with a low RxFifoThreshold).
+.Pp
+SOFT_HOTCHAR: required in addition to the small RxFifoThreshold
+to avoid overruns with SLIP and PPP for 8 ports at 115200 bps.
+Costs 5% relative efficiency.
diff --git a/share/man/man4/man4.i386/dgb.4 b/share/man/man4/man4.i386/dgb.4
new file mode 100644
index 000000000000..b72ae1412f53
--- /dev/null
+++ b/share/man/man4/man4.i386/dgb.4
@@ -0,0 +1,362 @@
+.\" Copyright (c) 1990, 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Systems Programming Group of the University of Utah Computer
+.\" Science Department.
+.\" 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.
+.\"
+.\" from: @(#)dca.4 5.2 (Berkeley) 3/27/91
+.\" from: com.4,v 1.1 1993/08/06 11:19:07 cgd Exp
+.\" from: sio.4,v 1.15 1994/12/06 20:14:30 bde Exp
+.\" $Id$
+.\"
+.Dd Oct 13, 1995
+.Dt DGB 4 i386
+.Os FreeBSD
+.Sh NAME
+.Nm dgb
+.Nd
+DigiBoard intelligent serial cards driver
+.Sh SYNOPSIS
+.Cd "options" \&"NDGBPORTS=8\&"
+.Cd "device dgb0 at isa? tty port 0x220 iomem 0xfc0000 iosiz ? flags 0x0
+All values are just examples.
+.sp
+The \fBNDGBPORTS\fR option defines the total number of ports on all cards
+installed in the system. When not defined the number is computed:
+
+.br
+ default \fBNDGBPORTS\fR = number_of_described_DigiBoard_cards * 16
+
+If it is less than the actual number of ports
+the system will be able to use only the
+first \fBNDGBPORTS\fR ports. If it is greater then all ports will be usable
+but some memory will be wasted.
+.sp
+Meaning of \fBflags\fR:
+.br
+\fB0x0001\fR use alternate pinout (exchange DCD and DSR lines)
+.br
+\fB0x0002\fR don't use 8K window mode of PC/Xe
+.sp
+Device numbering:
+.br
+0b\fICC\fRmmmmmmmm\fIOLIPPPPP\fR
+.br
+ \fBCC\fRard number
+.br
+ mmmmmmmm\fRajor number
+.br
+ call\fBO\fRut
+.br
+ \fBL\fRock
+.br
+ \fBI\fRnitial
+.br
+ \fBPPPPP\fRort number
+.Sh DESCRIPTION
+The
+.Nm dgb
+driver provides support for DigiBoard PC/Xe and PC/Xi series intelligent
+serial multiport cards with asynchronous interfaces based on the
+.Tn EIA
+.Tn RS-232C
+.Pf ( Tn CCITT
+.Tn V.24 )
+standard.
+.Pp
+Input and output for each line may set to one of following baud rates;
+50, 75, 110, 134.5, 150, 300, 600, 1200, 1800, 2400, 4800, 9600,
+19200, 38400, 57600, or for newer versions of cards 115200.
+.Pp
+The driver doesn't use any interrupts, it is ``polling-based''. This means that
+it uses clock interrupts instead of interrupts generated by DigiBoard cards and
+checks the state of cards 25 times per second. This is practical because the
+DigiBoard cards have large input and output buffers (more than 1Kbyte per
+port) and hardware that allows efficiently finding the port that needs
+attention. The only problem seen with this policy is slower
+SLIP and PPP response.
+.sp
+Each line in the kernel configuration file describes one card, not one port
+as in the
+.Nm sio
+driver.
+.sp
+The
+.Nm flags
+keyword may be used on each
+.Nm device dgb
+line in the kernel configuration file
+to change the pinout of the interface or to use new PC/Xe cards
+which can work with an 8K memory window in compatibility mode
+(with a 64K memory window). Note
+that using 8K memory window doesn't mean shorter input/output buffers, it means
+only that all buffers will be mapped to the same memory address and switched as
+needed.
+.sp
+The
+.Nm port
+value must be the same
+as the
+.Nm port
+set on the card by jumpers.
+For PC/Xi cards the same rule is applicable to the
+.Nm iomem
+value. It must be the same as the memory address set on the card
+by jumpers.
+.\"Some documentation gives the address as a ``paragraph'' or ``segment'';
+.\"you can get the value of address by adding the digit "0" at end of
+.\"paragraph value, e.g., 0xfc000 -> 0xfc0000.
+For PC/Xe cards there is no need to use jumpers for this purpose.
+In fact there are no jumpers to do it. Just
+write the address you want as the
+.Nm iomem
+value in kernel config file and the card will be programmed
+to use this address.
+.sp
+The same range of memory addresses may be used
+for all the DigiBoards installed
+(but not for any other card or real memory). DigiBoards
+with a large amount of memory (256K or 512K and perhaps
+even 128K) must be mapped
+to memory addresses outside of the first megabyte. If the computer
+has more than 15 megabytes of memory then there is no free address space
+outside of the first megabyte where such DigiBoards can be mapped.
+In this case you
+may need to reduce the amount of memory in the computer.
+But many machines provide a better solution. They have the ability to
+``turn off'' the memory in the 16th megabyte (addresses 0xF00000 - 0xFFFFFF)
+using the
+BIOS setup. Then the DigiBoard's address space can be set to this ``hole''.
+.\" XXX the following should be true for all serial drivers and
+.\" should not be repeated in the man pages for all serial drivers.
+.\" It was copied from sio.4. The only changes were s/sio/dgb/g.
+.Pp
+Serial ports controlled by the
+.Nm dgb
+driver can be used for both `callin' and `callout'.
+For each port there is a callin device and a callout device.
+The minor number of the callout device is 128 higher
+than that of the corresponding callin port.
+The callin device is general purpose.
+Processes opening it normally wait for carrier
+and for the callout device to become inactive.
+The callout device is used to steal the port from
+processes waiting for carrier on the callin device.
+Processes opening it do not wait for carrier
+and put any processes waiting for carrier on the callin device into
+a deeper sleep so that they do not conflict with the callout session.
+The callout device is abused for handling programs that are supposed
+to work on general ports and need to open the port without waiting
+but are too stupid to do so.
+.Pp
+The
+.Nm dgb
+driver also supports an initial-state and a lock-state control
+device for each of the callin and the callout "data" devices.
+The minor number of the initial-state device is 32 higher
+than that of the corresponding data device.
+The minor number of the lock-state device is 64 higher
+than that of the corresponding data device.
+The termios settings of a data device are copied
+from those of the corresponding initial-state device
+on first opens and are not inherited from previous opens.
+Use
+.Xr stty 1
+in the normal way on the initial-state devices to program
+initial termios states suitable for your setup.
+.sp
+The lock termios state acts as flags to disable changing
+the termios state. E.g., to lock a flag variable such as
+CRTSCTS, use
+.Nm stty crtscts
+on the lock-state device. Speeds and special characters
+may be locked by setting the corresponding value in the lock-state
+device to any nonzero value.
+.sp
+Correct programs talking to correctly wired external devices
+.\" XXX change next line in other man pages too, and rewrite this paragraph.
+work with almost arbitrary initial states and no locking,
+but other setups may benefit from changing some of the default
+initial state and locking the state.
+In particular, the initial states for non (POSIX) standard flags
+should be set to suit the devices attached and may need to be
+locked to prevent buggy programs from changing them.
+E.g., CRTSCTS should be locked on for devices that support
+RTS/CTS handshaking at all times and off for devices that don't
+support it at all. CLOCAL should be locked on for devices
+that don't support carrier. HUPCL may be locked off if you don't
+want to hang up for some reason. In general, very bad things happen
+if something is locked to the wrong state, and things should not
+be locked for devices that support more than one setting. The
+CLOCAL flag on callin ports should be locked off for logins
+to avoid certain security holes, but this needs to be done by
+getty if the callin port is used for anything else.
+.Sh FILES
+.Bl -tag -width /dev/ttyiD?? -compact
+.It Pa /dev/ttyD??
+for callin ports
+.It Pa /dev/ttyiD??
+.It Pa /dev/ttylD??
+corresponding callin initial-state and lock-state devices
+.sp
+.It Pa /dev/cuaD??
+for callout ports
+.It Pa /dev/cuaiD??
+.It Pa /dev/cualD??
+corresponding callout initial-state and lock-state devices
+.El
+.sp
+.Bl -tag -width /etc/rc.serial -compact
+.It Pa /etc/rc.serial
+examples of setting the initial-state and lock-state devices
+.El
+.Pp
+The first question mark in these device names
+means the number of the card from the set [0-9] and the
+second question mark means the number of the port on the card from the set
+[0-9a-v].
+.Sh DIAGNOSTICS
+You may enable extended diagnostics by defining DEBUG at the
+start of the source file dgb.c.
+.Bl -diag
+.It dgb\fIX\fB: warning: address \fIN\fB truncated to \fIM\fB
+The memory address for the PC/Xe's 8K window is misaligned (it should be
+on an 8K boundary) or outside of the first megabyte.
+.El
+.Bl -diag
+.It dgb\fIX\fB: 1st reset failed
+Problems with accessing I/O port of the card, probably
+the wrong \fBport\fR value is specified in the kernel config file.
+.El
+.Bl -diag
+.It dgb\fIX\fB: 2nd reset failed
+Problems with hardware.
+.El
+.Bl -diag
+.It dgb\fIX\fB: \fIN\fB[st,nd,rd,th] memory test failed
+Problems with accessing the memory of the card, probably
+the wrong \fBiomem\fR value is specified in the kernel config file.
+.El
+.Bl -diag
+.It dgb\fIX\fB: BIOS start failed
+Problems with starting the on-board BIOS. Probably the memory addresses of the
+DigiBoard overlap with some other device or with RAM.
+.El
+.Bl -diag
+.It dgb\fIX\fB: BIOS download failed
+Problems with the on-board BIOS. Probably the memory addresses of the
+DigiBoard overlap with some other device or with RAM.
+.El
+.Bl -diag
+.It dgb\fIX\fB: FEP code download failed
+Problems with downloading of the Front-End Processor's micro-OS.
+Probably the memory addresses of the
+DigiBoard overlap with some other device or with RAM.
+.El
+.Bl -diag
+.It dgb\fIX\fB: FEP/OS start failed
+Problems with starting of the Front-End Processor's micro-OS.
+Probably the memory addresses of the
+DigiBoard overlap with some other device or with RAM.
+.El
+.Bl -diag
+.It dgb\fIX\fB: too many ports
+This DigiBoard reports that it has more than 32 ports.
+Perhaps a hardware problem or
+the memory addresses of the
+DigiBoard overlap with some other device or with RAM.
+.El
+.Bl -diag
+.It dgb\fIX\fB: only \fIN\fB ports are usable
+The NDGBPORTS parameter is too small and there is only enough space allocated
+for \fIN\fR ports on this card.
+.El
+.Bl -diag
+.It dgb\fIX\fB: port \fIY\fB is broken
+The on-board diagnostic has reported that the specified port has hardware
+problems.
+.El
+.Bl -diag
+.It dgb\fIX\fB: polling of disabled board stopped
+Internal problems in the polling logic of driver.
+.El
+.Bl -diag
+.It dgb\fIX\fB: event queue's head or tail is wrong!
+Internal problems in the driver or hardware.
+.El
+.Bl -diag
+.It dgb\fIX\fB: port \fIY\fB: got event on nonexisting port
+Some status changed on a port that is physically present but is
+unusable due to misconfiguration.
+.El
+.Bl -diag
+.It dgb\fIX\fB: port \fIY\fB: event \fIN\fB mstat \fIM\fB lstat \fIK\fB
+The driver got a strange event from card. Probably this means that you have a
+newer card with an extended list of events or some other hardware problem.
+.El
+.Bl -diag
+.It dgb\fIX\fB: port \fIY\fB: overrun
+Input buffer has filled up. Problems in polling logic of driver.
+.El
+.Bl -diag
+.It dgb\fIX\fB: port \fIY\fB: FEP command on disabled port
+Internal problems in driver.
+.El
+.Bl -diag
+.It dgb\fIX\fB: port \fIY\fB: timeout on FEP command
+Problems in hardware.
+.Sh SEE ALSO
+.Xr tty 4 ,
+.Xr termios 4 ,
+.Xr comcontrol 8 ,
+.\" XXX add next line to many other drivers.
+.Xr MAKEDEV 8 ,
+.Xr stty 1 .
+.Sh HISTORY
+The
+.Nm
+driver is derived from the
+.Nm sio
+driver and the DigiBoard driver from
+.Nm Linux
+and is
+.Ud
+.Sh BUGS
+The implementation of sending BREAK is broken. BREAK of fixed length of 1/4 s
+is sent anyway.
+.Pp
+There was a bug in implementation of
+.Xr select 2 .
+It is fixed now but not widely tested yet.
+.Pp
+There is no ditty command. Most of its functions (alternate pinout,
+speed up to 115200 baud, etc.) are implemented in the driver itself. Some
+other functions are missing.
diff --git a/share/man/man4/man4.i386/si.4 b/share/man/man4/man4.i386/si.4
new file mode 100644
index 000000000000..aa346f614167
--- /dev/null
+++ b/share/man/man4/man4.i386/si.4
@@ -0,0 +1,169 @@
+.\" $Id$
+.\" The following requests are required for all man pages.
+.Dd September 16, 1995
+.Os FreeBSD
+.Dt SI 4
+.Sh NAME
+.Nm si
+- Driver for Specialix International SI/XIO 8-32 port intelligent serial card.
+.Sh SYNOPSIS
+.Nm "device si0 at isa? tty irq 12 iomem 0xd0000 vector siintr"
+.Sh DESCRIPTION
+The Specialix SI and XIO hardware makes up an 8 to 32 port RS-232 serial
+multiplexor.
+.Pp
+This driver was ported and tested on an ISA bus machine, and has rudimentry
+support for operation on an EISA bus system as well, but as of this time the
+EISA version has not been tested by the Author - it may or may not work.
+.Pp
+The system uses two components.. A "Host adapter", which is plugged into
+an ISA/EISA slot and provides intelligence and buffering/processing
+capabilities, as well as an external bus in the form of a 50 pin cable.
+.Pp
+On this cable, "modules" are connected. The "SI" module comes in a 4 and 8
+port version, and has simple UARTS. The "XIO" module comes only in an 8 port
+version, and has two powerful RISC-like UARTS as well.
+.Pp
+The host adapter polls and transfers data between the modules and the main
+Operating system. The Host adapter provides a 256 byte transmit and 256 byte
+receive FIFO for each of the 32 ports that it can maintain.
+.Pp
+The XIO module panels can operate each of their 8 ports at 115,200 baud, while
+the SI version can run at 57,600 baud.
+.Pp
+The host adapter uses a shared memory block in the traditional ISA bus
+"hole" betweem 0xA0000 and 0xEFFFF. The adapter can be configured outside
+range, but requires the memory range to be explicitly non-cached. The
+driver does not yet support this mode of operation.
+.Pp
+The adapter can use Irq's 11, 12 or 15. It is rumoured that the ISA adapter
+cards provide their own tri-state drivers and pullups, and may be able to
+share an IRQ between all SI/XIO host cards. This has not been tested, and
+the driver does not support this mode of operation. The actual IRQ used is
+soft-configured onto the host card at boot time, but automatic selection
+of a free IRQ is not yet implemented in the FreeBSD version.
+.Pp
+The si device driver may have some of it's configuration settings changed
+at run-time with the
+.Xr sicontrol 8
+utility.
+.Pp
+The si device driver also responds to the
+.Xr comcontrol 8
+utility for configuring drain-on-close timeouts.
+.Pp
+An open on a /dev device node controlled by the si driver obeys the same
+semantics as the
+.Xr sio 4
+driver. It fully supports the usual semantics of the cua ports, and the
+"initial termios" and "locked termios" settings. In summary, an open on a
+tty port will block until DCD is raised, unless O_NONBLOCK is specified.
+CLOCAL is honored. An open on a cua port will always succeed, but DCD
+transitions will be honored after DCD rises for the first time.
+by the si driver obeys the same
+semantics as the
+.Xr sio 4
+driver. It fully supports the usual semantics of the cua ports, and the
+"initial termios" and "locked termios" settings. In summary, an open on a
+tty port will block until DCD is raised, unless O_NONBLOCK is specified.
+CLOCAL is honored. An open on a cua port will always succeed, but DCD
+transitions will be honored after DCD rises for the first time.
+.Pp
+Normally, up to four SI/XIO host cards may be controlled by the si driver,
+but due to the lack of available interrupts that the card can be configured
+to use, only three may be presently used. Polling operation is not currently
+implemented, although it is a standard mode of operation for Specialix shipped
+drivers. Once this is implemented, all four cards may be used.
+.Pp
+The lowest 5 bits of the minor device number are used to select the port
+number on the mudule cluster.
+si driver,
+but due to the lack of available interrupts that the card can be configured
+to use, only three may be presently used. Polling operation is not currently
+implemented, although it is a standard mode of operation for Specialix shipped
+drivers. Once this is implemented, all four cards may be used.
+.Pp
+The lowest 5 bits of the minor device number are used to select the port
+number on the mudule cluster. The next 2 bits select which of 4 host adapter
+cards. This allows a maximum of 128 ports on this driver.
+.Pp
+Bit 7 is used to differentiate a tty/dialin port (bit 7=0) and a
+cua/callout port (bit 7=1).
+.Pp
+Bit 8 through 15 (on FreeBSD) are unavailable as they are a shadow of the
+major device number.
+.Pp
+If bit 16 is a 1, the device node is referring to the "initial state" device.
+This "initial state" is used to prime the
+.Xr termios 4
+settings of the device when it is initially opened.
+If bit 17 is a 1, the device node is referring to the "locked state" device.
+The "locked state" is used to prevent the
+.Xr termios 4
+settings from being changed.
+.Pp
+To manipulate the initial/locked settings, the
+.Xr stty 1
+command is useful. When setting the "locked" variables, enabling the mode
+on the lock device will lock the termios mode, while disabling the mode will
+unlock it.
+.\" The following requests should be uncommented and used where appropriate.
+.\" This next request is for sections 2 and 3 function return values only.
+.\" .Sh RETURN VALUES
+.\" This next request is for sections 1, 6, 7 & 8 only
+.\" .Sh ENVIRONMENT
+.Sh FILES
+.Bl -tag -width /dev/si_control -compact
+.It Pa /dev/si_control
+global driver control file for
+.Xr sicontrol 8
+.It Pa /dev/ttyA*
+terminal/dialin ports
+.It Pa /dev/cuaA*
+dialout ports
+.It Pa /dev/ttyiA*
+initial termios state devices
+.It Pa /dev/ttylA*
+locked termios state devices
+.El
+.\" .Sh EXAMPLES
+.\" This next request is for sections 1, 6, 7 & 8 only
+.\" (command return values (to shell) and fprintf/stderr type diagnostics)
+.\" .Sh DIAGNOSTICS
+.\" The next request is for sections 2 and 3 error and signal handling only.
+.\" .Sh ERRORS
+.Sh SEE ALSO
+.Xr stty 1 ,
+.Xr termios 4 ,
+.Xr tty 4 ,
+.Xr sio 4 ,
+.Xr sicontrol 8 ,
+.Xr comcontrol 8 .
+.\" .Sh STANDARDS
+.Sh HISTORY
+This driver is loosely based on driver code originating at Specialix, which
+was ported to run on BSDI by
+.Nm Andy Rutter <andy@specialix.co.uk> .
+The System V driver source is/was available by ftp from
+.Nm ftp.specialix.co.uk .
+.Pp
+This driver is not supported by Specialix International.
+.Sh AUTHORS
+.Nm Peter Wemm <peter@freebsd.org>
+obtained the code from Andy Rutter and ported it to FreeBSD, with a large
+amount of invalueable assistance from
+.Nm Bruce Evans <bde@zeta.org.au>
+.Pp
+Man page by Peter Wemm.
+.Sh BUGS
+The EISA support is untested.
+.Pp
+The interrupt tuning rate is not believed to be optimal at this time for
+maximum efficiency.
+.Pp
+Receiver tty buffer flushing is not yet enabled, like many other drivers.
+.Pp
+POLL mode is not implemented yet.
+.Pp
+Operation outside the traditional ISA "hole" is not yet supported, although it
+should work if the test is removed from the probe routine.
diff --git a/sys/i386/boot/kzipboot/tail.S b/sys/i386/boot/kzipboot/tail.S
new file mode 100644
index 000000000000..1a345412fa2f
--- /dev/null
+++ b/sys/i386/boot/kzipboot/tail.S
@@ -0,0 +1,12 @@
+/*
+ * Boot unpacker startup routine.
+ * Copyright (C) Serge Vakulenko
+ */
+ .text
+ .globl start
+start:
+ popl %eax # remove return addr
+ pushl 4(%esp) # pass howto arg
+ call _boot # unpack the kernel image
+ popl %eax # discard howto arg
+ ljmp $CSEG, $KADDR # jump to unpacked kernel
diff --git a/sys/i386/isa/atapi.c b/sys/i386/isa/atapi.c
new file mode 100644
index 000000000000..540c2bd2d26b
--- /dev/null
+++ b/sys/i386/isa/atapi.c
@@ -0,0 +1,856 @@
+/*
+ * Device-independent level for ATAPI drivers.
+ *
+ * Copyright (C) 1995 Cronyx Ltd.
+ * Author Serge Vakulenko, <vak@cronyx.ru>
+ *
+ * This software is distributed with NO WARRANTIES, not even the implied
+ * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Authors grant any other persons or organisations permission to use
+ * or modify this software as long as this message is kept with the software,
+ * all derivative works or modified versions.
+ *
+ * Version 1.5, Thu Sep 21 23:08:11 MSD 1995
+ */
+
+/*
+ * The ATAPI level is implemented as a machine-dependent layer
+ * between the device driver and the IDE controller.
+ * All the machine- and controller dependency is isolated inside
+ * the ATAPI level, while all the device dependency is located
+ * in the device subdriver.
+ *
+ * It seems that an ATAPI bus will became popular for medium-speed
+ * storage devices such as CD-ROMs, magneto-optical disks, tape streamers etc.
+ *
+ * To ease the development of new ATAPI drivers, the subdriver
+ * interface was designed to be as simple as possible.
+ *
+ * Three routines are available for the subdriver to access the device:
+ *
+ * struct atapires atapi_request_wait (ata, unit, cmd, a1, a2, a3, a4, a5,
+ * a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, addr, count);
+ * struct atapi *ata; -- atapi controller descriptor
+ * int unit; -- device unit number on the IDE bus
+ * u_char cmd; -- ATAPI command code
+ * u_char a1..a15; -- ATAPI command arguments
+ * char *addr; -- address of the data buffer for i/o
+ * int count; -- data length, >0 for read ops, <0 for write ops
+ *
+ * The atapi_request_wait() function puts the op in the queue of ATAPI
+ * commands for the IDE controller, starts the controller, the waits for
+ * operation to be completed (using tsleep).
+ * The function should be called from the user phase only (open(), close(),
+ * ioctl() etc).
+ * Ata and unit args are the values which the subdriver gets from the ATAPI
+ * level via attach() call.
+ * Buffer pointed to by *addr should be placed in core memory, static
+ * or dynamic, but not in stack.
+ * The function returns the error code structure, which consists of:
+ * - atapi driver code value
+ * - controller status port value
+ * - controller error port value
+ *
+ * struct atapires atapi_request_immediate (ata, unit, cmd, a1, a2, a3,
+ * a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15,
+ * addr, count);
+ *
+ * The atapi_request_immediate() function is similar to atapi_request_wait(),
+ * but it does not use interrupts for performing the request.
+ * It should be used during an attach phase to get parameters from the device.
+ *
+ * void atapi_request_callback (ata, unit, cmd, a1, a2, a3, a4, a5,
+ * a6, a7, a8, a9, a10, a11, a12, a13, a14, a15,
+ * addr, count, done, x, y);
+ * struct atapi *ata; -- atapi controller descriptor
+ * int unit; -- device unit number on the IDE bus
+ * u_char cmd; -- ATAPI command code
+ * u_char a1..a15; -- ATAPI command arguments
+ * char *addr; -- address of the data buffer for i/o
+ * int count; -- data length, >0 for read ops, <0 for write ops
+ * void (*done)(); -- function to call when op finished
+ * void *x, *y; -- arguments for done() function
+ *
+ * The atapi_request_callback() function puts the op in the queue of ATAPI
+ * commands for the IDE controller, starts the controller, then returns.
+ * When the operation finishes, then the callback function done()
+ * will be called on the interrupt level.
+ * The function is designed to be callable from the interrupt phase.
+ * The done() functions is called with the following arguments:
+ * (void) (*done) (x, y, count, errcode)
+ * void *x, *y; -- arguments from the atapi_request_callback()
+ * int count; -- the data residual count
+ * struct atapires errcode; -- error code structure, see above
+ *
+ * The new driver could be added in three steps:
+ * 1. Add entries for the new driver to bdevsw and cdevsw tables in conf.c.
+ * You will need to make at least three routines: open(), close(),
+ * strategy() and possibly ioctl().
+ * 2. Make attach() routine, which should allocate all the needed data
+ * structures and print the device description string (see wcdattach()).
+ * 3. Add an appropriate case to the switch in atapi_attach() routine,
+ * call attach() routine of the new driver here. Add the appropriate
+ * #include line at the top of attach.c.
+ * That's all!
+ *
+ * Use #define DEBUG in atapi.c to enable tracing of all i/o operations
+ * on the IDE bus.
+ */
+#undef DEBUG
+
+#include "wdc.h"
+#include "wcd.h"
+/* #include "wmt.h" -- add your driver here */
+/* #include "wmd.h" -- add your driver here */
+
+#if NWDC > 0 && defined (ATAPI)
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <i386/include/cpufunc.h>
+#include <i386/include/clock.h>
+#include <i386/isa/atapi.h>
+
+#ifdef DEBUG
+# define print(s) printf s
+#else
+# define print(s) {/*void*/}
+#endif
+
+#define MAXCMD (8*NWDC)
+
+/*
+ * ATAPI packet command phase.
+ */
+#define PHASE_CMDOUT (ARS_DRQ | ARI_CMD)
+#define PHASE_DATAIN (ARS_DRQ | ARI_IN)
+#define PHASE_DATAOUT ARS_DRQ
+#define PHASE_COMPLETED (ARI_IN | ARI_CMD)
+#define PHASE_ABORTED 0 /* nonstandard - for NEC 260 */
+
+struct atapicmd { /* ATAPI command block */
+ struct atapicmd *next; /* next command in queue */
+ int busy; /* busy flag */
+ u_char cmd[16]; /* command and args */
+ int unit; /* drive unit number */
+ int count; /* byte count, >0 - read, <0 - write */
+ char *addr; /* data to transfer */
+ void (*callback) (); /* call when done */
+ void *cbarg1; /* callback arg 1 */
+ void *cbarg2; /* callback arg 1 */
+ struct atapires result; /* resulting error code */
+};
+
+struct atapi { /* ATAPI controller data */
+ u_short port; /* i/o port base */
+ u_char ctrlr; /* physical controller number */
+ u_char debug : 1; /* trace enable flag */
+ u_char cmd16 : 1; /* 16-byte command flag */
+ u_char intrcmd : 1; /* interrupt before cmd flag */
+ u_char slow : 1; /* slow reaction device */
+ struct atapicmd *queue; /* queue of commands to perform */
+ struct atapicmd *tail; /* tail of queue */
+ struct atapicmd *free; /* queue of free command blocks */
+ struct atapicmd cmdrq[MAXCMD]; /* pool of command requests */
+};
+
+struct atapi atapitab[NWDC];
+
+static struct atapi_params *atapi_probe (int port, int unit);
+static int atapi_wait (int port, u_char bits_wanted);
+static void atapi_send_cmd (struct atapi *ata, struct atapicmd *ac);
+static int atapi_io (struct atapi *ata, struct atapicmd *ac);
+static int atapi_start_cmd (struct atapi *ata, struct atapicmd *ac);
+static int atapi_wait_cmd (struct atapi *ata, struct atapicmd *ac);
+
+extern int wdstart (int ctrlr);
+
+void atapi_attach (int ctlr, int unit, int port, struct kern_devconf *parent)
+{
+ struct atapi *ata = atapitab + ctlr;
+ struct atapi_params *ap;
+ char buf [sizeof(ap->model) + 1];
+ char revbuf [sizeof(ap->revision) + 1];
+ struct atapicmd *ac;
+
+ print (("atapi%d.%d at 0x%x: attach called\n", ctlr, unit, port));
+ ap = atapi_probe (port, unit);
+ if (! ap)
+ return;
+
+ bcopy (ap->model, buf, sizeof(buf)-1);
+ buf[sizeof(buf)-1] = 0;
+
+ bcopy (ap->revision, revbuf, sizeof(revbuf)-1);
+ revbuf[sizeof(revbuf)-1] = 0;
+
+ printf ("wdc%d: unit %d (atapi): <%s/%s>", ctlr, unit, buf, revbuf);
+
+ /* device is removable */
+ if (ap->removable)
+ printf (", removable");
+
+ /* packet command size */
+ switch (ap->cmdsz) {
+ case AT_PSIZE_12: break;
+ case AT_PSIZE_16: printf (", cmd16"); ata->cmd16 = 1; break;
+ default: printf (", cmd%d", ap->cmdsz);
+ }
+
+ /* DRQ type */
+ switch (ap->drqtype) {
+ case AT_DRQT_MPROC: ata->slow = 1; break;
+ case AT_DRQT_INTR: printf (", intr"); ata->intrcmd = 1; break;
+ case AT_DRQT_ACCEL: printf (", accel"); break;
+ default: printf (", drq%d", ap->drqtype);
+ }
+
+ /* overlap operation supported */
+ if (ap->ovlapflag)
+ printf (", ovlap");
+
+ /* interleaved DMA supported */
+ if (ap->idmaflag)
+ printf (", idma");
+ /* DMA supported */
+ else if (ap->dmaflag)
+ printf (", dma");
+
+ /* IORDY can be disabled */
+ if (ap->iordydis)
+ printf (", iordis");
+ /* IORDY supported */
+ else if (ap->iordyflag)
+ printf (", iordy");
+
+ printf ("\n");
+
+ ata->port = port;
+ ata->ctrlr = ctlr;
+#ifdef DEBUG
+ ata->debug = 1;
+#else
+ ata->debug = 0;
+#endif
+ /* Initialize free queue. */
+ ata->cmdrq[MAXCMD-1].next = 0;
+ for (ac = ata->cmdrq+MAXCMD-2; ac >= ata->cmdrq; --ac)
+ ac->next = ac+1;
+ ata->free = ata->cmdrq;
+
+ if (ap->proto != AT_PROTO_ATAPI) {
+ printf ("wdc%d: unit %d: unknown ATAPI protocol=%d\n",
+ ctlr, unit, ap->proto);
+ free (ap, M_TEMP);
+ return;
+ }
+ switch (ap->devtype) {
+ default:
+ /* unknown ATAPI device */
+ printf ("wdc%d: unit %d: unknown ATAPI type=%d\n",
+ ctlr, unit, ap->devtype);
+ break;
+
+ case AT_TYPE_DIRECT: /* direct-access */
+ case AT_TYPE_CDROM: /* CD-ROM device */
+#if NWCD > 0
+ /* ATAPI CD-ROM */
+ {
+ int wcdattach (struct atapi*, int, struct atapi_params*,
+ int, struct kern_devconf*);
+ if (wcdattach (ata, unit, ap, ata->debug, parent) < 0)
+ break;
+ }
+ /* Device attached successfully. */
+ return;
+#else
+ printf ("wdc%d: ATAPI CD-ROMs not configured\n", ctlr);
+ break;
+#endif
+
+ case AT_TYPE_TAPE: /* streaming tape (QIC-121 model) */
+#if NWMT > 0
+ /* Add your driver here */
+#else
+ printf ("wdc%d: ATAPI streaming tapes not supported yet\n", ctlr);
+ break;
+#endif
+
+ case AT_TYPE_OPTICAL: /* optical disk */
+#if NWMD > 0
+ /* Add your driver here */
+#else
+ printf ("wdc%d: ATAPI optical disks not supported yet\n", ctlr);
+ break;
+#endif
+ }
+ /* Attach failed. */
+ free (ap, M_TEMP);
+}
+
+static void bswap (char *buf, int len)
+{
+ u_short *p = (u_short*) (buf + len);
+ while (--p >= (u_short*) buf)
+ *p = ntohs (*p);
+}
+
+static void btrim (char *buf, int len)
+{
+ char *p;
+
+ /* Remove the trailing spaces. */
+ for (p=buf; p<buf+len; ++p)
+ if (! *p)
+ *p = ' ';
+ for (p=buf+len-1; p>=buf && *p==' '; --p)
+ *p = 0;
+}
+
+/*
+ * Issue IDENTIFY command to ATAPI drive to ask it what it is.
+ */
+static struct atapi_params *atapi_probe (int port, int unit)
+{
+ struct atapi_params *ap;
+ char tb [DEV_BSIZE];
+
+ /* Wait for controller not busy. */
+ if (atapi_wait (port, 0) < 0) {
+ print (("atapiX.%d at 0x%x: controller busy, status=%b\n",
+ unit, port, inb (port + AR_STATUS), ARS_BITS));
+ return (0);
+ }
+
+ /* Issue ATAPI IDENTIFY command. */
+ outb (port + AR_DRIVE, unit ? ARD_DRIVE1 : ARD_DRIVE0);
+ outb (port + AR_COMMAND, ATAPIC_IDENTIFY);
+
+ /* Check that device is present. */
+ if (inb (port + AR_STATUS) == 0xff) {
+ print (("atapiX.%d at 0x%x: no device\n", unit, port));
+ if (unit == 1)
+ /* Select unit 0. */
+ outb (port + AR_DRIVE, ARD_DRIVE0);
+ return (0);
+ }
+
+ /* Wait for data ready. */
+ if (atapi_wait (port, ARS_DRQ) != 0) {
+ print (("atapiX.%d at 0x%x: identify not ready, status=%b\n",
+ unit, port, inb (port + AR_STATUS), ARS_BITS));
+ if (unit == 1)
+ /* Select unit 0. */
+ outb (port + AR_DRIVE, ARD_DRIVE0);
+ return (0);
+ }
+
+ /* Obtain parameters. */
+ insw (port + AR_DATA, tb, sizeof(tb) / sizeof(short));
+
+ ap = malloc (sizeof *ap, M_TEMP, M_NOWAIT);
+ if (! ap)
+ return (0);
+ bcopy (tb, ap, sizeof *ap);
+
+ /*
+ * Shuffle string byte order.
+ * Mitsumi and NEC drives don't need this.
+ */
+ if (! ((ap->model[0] == 'N' && ap->model[1] == 'E') ||
+ (ap->model[0] == 'F' && ap->model[1] == 'X'))) {
+ bswap (ap->model, sizeof(ap->model));
+ bswap (ap->serial, sizeof(ap->serial));
+ bswap (ap->revision, sizeof(ap->revision));
+ }
+
+ /* Clean up the model name, serial and revision numbers. */
+ btrim (ap->model, sizeof(ap->model));
+ btrim (ap->serial, sizeof(ap->serial));
+ btrim (ap->revision, sizeof(ap->revision));
+ return (ap);
+}
+
+/*
+ * Wait uninterruptibly until controller is not busy and certain
+ * status bits are set.
+ * The wait is usually short unless it is for the controller to process
+ * an entire critical command.
+ * Return 1 for (possibly stale) controller errors, -1 for timeout errors,
+ * or 0 for no errors.
+ */
+static int atapi_wait (int port, u_char bits_wanted)
+{
+ int cnt;
+ u_char s;
+
+ /* Wait 5 sec for BUSY deassert. */
+ for (cnt=500000; cnt>0; --cnt) {
+ s = inb (port + AR_STATUS);
+ if (! (s & ARS_BSY))
+ break;
+ DELAY (10);
+ }
+ if (cnt <= 0)
+ return (-1);
+ if (! bits_wanted)
+ return (s & ARS_CHECK);
+
+ /* Wait 50 msec for bits wanted. */
+ for (cnt=5000; cnt>0; --cnt) {
+ s = inb (port + AR_STATUS);
+ if ((s & bits_wanted) == bits_wanted)
+ return (s & ARS_CHECK);
+ DELAY (10);
+ }
+ return (-1);
+}
+
+void atapi_debug (struct atapi *ata, int on)
+{
+ ata->debug = on;
+}
+
+static struct atapicmd *atapi_alloc (struct atapi *ata)
+{
+ struct atapicmd *ac;
+
+ while (! ata->free)
+ tsleep ((caddr_t)ata, PRIBIO, "atacmd", 0);
+ ac = ata->free;
+ ata->free = ac->next;
+ ac->busy = 1;
+ return (ac);
+}
+
+static void atapi_free (struct atapi *ata, struct atapicmd *ac)
+{
+ if (! ata->free)
+ wakeup ((caddr_t)&ata);
+ ac->busy = 0;
+ ac->next = ata->free;
+ ata->free = ac;
+}
+
+/*
+ * Add new command request to the end of the queue.
+ */
+static void atapi_enqueue (struct atapi *ata, struct atapicmd *ac)
+{
+ ac->next = 0;
+ if (ata->tail)
+ ata->tail->next = ac;
+ else
+ ata->queue = ac;
+ ata->tail = ac;
+}
+
+static void atapi_done (struct atapi *ata)
+{
+ struct atapicmd *ac = ata->queue;
+
+ if (! ac)
+ return; /* cannot happen */
+
+ ata->queue = ac->next;
+ if (! ata->queue)
+ ata->tail = 0;
+
+ if (ac->callback) {
+ (*ac->callback) (ac->cbarg1, ac->cbarg2, ac->count, ac->result);
+ atapi_free (ata, ac);
+ } else
+ wakeup ((caddr_t)ac);
+}
+
+/*
+ * Start new packet op. Called from wdstart().
+ * Return 1 if op started, and we are waiting for interrupt.
+ * Return 0 when idle.
+ */
+int atapi_start (int ctrlr)
+{
+ struct atapi *ata = atapitab + ctrlr;
+ struct atapicmd *ac;
+again:
+ ac = ata->queue;
+ if (! ac)
+ return (0);
+
+ /* Start packet command. */
+ if (atapi_start_cmd (ata, ac) < 0) {
+ atapi_done (ata);
+ goto again;
+ }
+
+ if (ata->intrcmd)
+ /* Wait for interrupt before sending packet command */
+ return (1);
+
+ /* Wait for DRQ. */
+ if (atapi_wait_cmd (ata, ac) < 0) {
+ atapi_done (ata);
+ goto again;
+ }
+
+ /* Send packet command. */
+ atapi_send_cmd (ata, ac);
+ return (1);
+}
+
+/*
+ * Start new packet op. Returns -1 on errors.
+ */
+int atapi_start_cmd (struct atapi *ata, struct atapicmd *ac)
+{
+ ac->result.error = 0;
+ ac->result.status = 0;
+
+ outb (ata->port + AR_DRIVE, ac->unit ? ARD_DRIVE1 : ARD_DRIVE0);
+ if (atapi_wait (ata->port, 0) < 0) {
+ printf ("atapi%d.%d: controller not ready for cmd\n",
+ ata->ctrlr, ac->unit);
+ ac->result.code = RES_NOTRDY;
+ return (-1);
+ }
+
+ /* Set up the controller registers. */
+ outb (ata->port + AR_FEATURES, 0);
+ outb (ata->port + AR_IREASON, 0);
+ outb (ata->port + AR_TAG, 0);
+ outb (ata->port + AR_CNTLO, ac->count & 0xff);
+ outb (ata->port + AR_CNTHI, ac->count >> 8);
+ outb (ata->port + AR_COMMAND, ATAPIC_PACKET);
+
+ if (ata->debug)
+ printf ("atapi%d.%d: start\n", ata->ctrlr, ac->unit);
+ return (0);
+}
+
+/*
+ * Wait for DRQ before sending packet cmd. Returns -1 on errors.
+ */
+int atapi_wait_cmd (struct atapi *ata, struct atapicmd *ac)
+{
+ /* Wait for DRQ from 50 usec to 3 msec for slow devices */
+ int cnt = ata->intrcmd ? 10000 : ata->slow ? 3000 : 50;
+
+ for (; cnt>0; cnt-=10) {
+ ac->result.status = inb (ata->port + AR_STATUS);
+ if (ac->result.status & ARS_DRQ)
+ break;
+ DELAY (10);
+ }
+ if (! (ac->result.status & ARS_DRQ)) {
+ printf ("atapi%d.%d: no cmd drq\n", ata->ctrlr, ac->unit);
+ ac->result.code = RES_NODRQ;
+ ac->result.error = inb (ata->port + AR_ERROR);
+ return (-1);
+ }
+ return (0);
+}
+
+/*
+ * Send packet cmd.
+ */
+void atapi_send_cmd (struct atapi *ata, struct atapicmd *ac)
+{
+ outsw (ata->port + AR_DATA, ac->cmd, ata->cmd16 ? 8 : 6);
+ if (ata->debug)
+ printf ("atapi%d.%d: send cmd %x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x\n",
+ ata->ctrlr, ac->unit, ac->cmd[0], ac->cmd[1],
+ ac->cmd[2], ac->cmd[3], ac->cmd[4], ac->cmd[5],
+ ac->cmd[6], ac->cmd[7], ac->cmd[8], ac->cmd[9],
+ ac->cmd[10], ac->cmd[11], ac->cmd[12],
+ ac->cmd[13], ac->cmd[14], ac->cmd[15]);
+}
+
+/*
+ * Interrupt routine for the controller. Called from wdintr().
+ * Finish the started op, wakeup wait-type commands,
+ * run callbacks for callback-type commands, then return.
+ * Do not start new op here, it will be done by wdstart,
+ * which is called just after us.
+ * Return 1 if op continues, and we are waiting for new interrupt.
+ * Return 0 when idle.
+ */
+int atapi_intr (int ctrlr)
+{
+ struct atapi *ata = atapitab + ctrlr;
+ struct atapicmd *ac = ata->queue;
+
+ if (! ac) {
+ printf ("atapi%d: stray interrupt\n", ata->ctrlr);
+ return (0);
+ }
+ if (atapi_io (ata, ac) > 0)
+ return (1);
+ atapi_done (ata);
+ return (0);
+}
+
+/*
+ * Process the i/o phase, transferring the command/data to/from the device.
+ * Return 1 if op continues, and we are waiting for new interrupt.
+ * Return 0 when idle.
+ */
+int atapi_io (struct atapi *ata, struct atapicmd *ac)
+{
+ u_char ireason;
+ u_short len, i;
+
+ if (atapi_wait (ata->port, 0) < 0) {
+ ac->result.status = inb (ata->port + AR_STATUS);
+ ac->result.error = inb (ata->port + AR_ERROR);
+ ac->result.code = RES_NOTRDY;
+ printf ("atapi%d.%d: controller not ready, status=%b, error=%b\n",
+ ata->ctrlr, ac->unit, ac->result.status, ARS_BITS,
+ ac->result.error, AER_BITS);
+ return (0);
+ }
+
+ ac->result.status = inb (ata->port + AR_STATUS);
+ ac->result.error = inb (ata->port + AR_ERROR);
+ len = inb (ata->port + AR_CNTLO);
+ len |= inb (ata->port + AR_CNTHI) << 8;
+ ireason = inb (ata->port + AR_IREASON);
+
+ if (ata->debug) {
+ printf ("atapi%d.%d: intr ireason=0x%x, len=%d, status=%b, error=%b\n",
+ ata->ctrlr, ac->unit, ireason, len,
+ ac->result.status, ARS_BITS,
+ ac->result.error, AER_BITS);
+ }
+ switch ((ireason & (ARI_CMD | ARI_IN)) | (ac->result.status & ARS_DRQ)) {
+ default:
+ printf ("atapi%d.%d: unknown phase\n", ata->ctrlr, ac->unit);
+ ac->result.code = RES_ERR;
+ break;
+
+ case PHASE_CMDOUT:
+ /* Send packet command. */
+ if (! (ac->result.status & ARS_DRQ)) {
+ printf ("atapi%d.%d: no cmd drq\n",
+ ata->ctrlr, ac->unit);
+ ac->result.code = RES_NODRQ;
+ break;
+ }
+ atapi_send_cmd (ata, ac);
+ return (1);
+
+ case PHASE_DATAOUT:
+ /* Write data */
+ if (ac->count > 0) {
+ printf ("atapi%d.%d: invalid data direction\n",
+ ata->ctrlr, ac->unit);
+ ac->result.code = RES_INVDIR;
+ break;
+ }
+ if (-ac->count < len) {
+ print (("atapi%d.%d: send data underrun, %d bytes left\n",
+ ata->ctrlr, ac->unit, -ac->count));
+ ac->result.code = RES_UNDERRUN;
+ outsw (ata->port + AR_DATA, ac->addr,
+ -ac->count / sizeof(short));
+ for (i= -ac->count; i<len; i+=sizeof(short))
+ outw (ata->port + AR_DATA, 0);
+ } else
+ outsw (ata->port + AR_DATA, ac->addr,
+ len / sizeof(short));
+ ac->addr += len;
+ ac->count += len;
+ return (1);
+
+ case PHASE_DATAIN:
+ /* Read data */
+ if (ac->count < 0) {
+ printf ("atapi%d.%d: invalid data direction\n",
+ ata->ctrlr, ac->unit);
+ ac->result.code = RES_INVDIR;
+ break;
+ }
+ if (ac->count < len) {
+ print (("atapi%d.%d: recv data overrun, %d bytes left\n",
+ ata->ctrlr, ac->unit, ac->count));
+ ac->result.code = RES_OVERRUN;
+ insw (ata->port + AR_DATA, ac->addr,
+ ac->count / sizeof(short));
+ for (i=ac->count; i<len; i+=sizeof(short))
+ inw (ata->port + AR_DATA);
+ } else
+ insw (ata->port + AR_DATA, ac->addr,
+ len / sizeof(short));
+ ac->addr += len;
+ ac->count -= len;
+ return (1);
+
+ case PHASE_ABORTED:
+ case PHASE_COMPLETED:
+ if (ac->result.status & (ARS_CHECK | ARS_DF))
+ ac->result.code = RES_ERR;
+ else if (ac->count < 0) {
+ print (("atapi%d.%d: send data overrun, %d bytes left\n",
+ ata->ctrlr, ac->unit, -ac->count));
+ ac->result.code = RES_OVERRUN;
+ } else if (ac->count > 0) {
+ print (("atapi%d.%d: recv data underrun, %d bytes left\n",
+ ata->ctrlr, ac->unit, ac->count));
+ ac->result.code = RES_UNDERRUN;
+ bzero (ac->addr, ac->count);
+ } else
+ ac->result.code = RES_OK;
+ break;
+ }
+ return (0);
+}
+
+/*
+ * Queue new packet request, then call wdstart().
+ * Called on splbio().
+ */
+void atapi_request_callback (struct atapi *ata, int unit,
+ u_char cmd, u_char a1, u_char a2, u_char a3, u_char a4,
+ u_char a5, u_char a6, u_char a7, u_char a8, u_char a9,
+ u_char a10, u_char a11, u_char a12, u_char a13, u_char a14, u_char a15,
+ char *addr, int count, void (*done)(), void *x, void *y)
+{
+ struct atapicmd *ac;
+
+ ac = atapi_alloc (ata);
+ ac->cmd[0] = cmd; ac->cmd[1] = a1;
+ ac->cmd[2] = a2; ac->cmd[3] = a3;
+ ac->cmd[4] = a4; ac->cmd[5] = a5;
+ ac->cmd[6] = a6; ac->cmd[7] = a7;
+ ac->cmd[8] = a8; ac->cmd[9] = a9;
+ ac->cmd[10] = a10; ac->cmd[11] = a11;
+ ac->cmd[12] = a12; ac->cmd[13] = a13;
+ ac->cmd[14] = a14; ac->cmd[15] = a15;
+ ac->unit = unit;
+ ac->addr = addr;
+ ac->count = count;
+ ac->callback = done;
+ ac->cbarg1 = x;
+ ac->cbarg2 = y;
+
+ if (ata->debug)
+ printf ("atapi%d.%d: req cb %x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x len=%d\n",
+ ata->ctrlr, ac->unit, ac->cmd[0], ac->cmd[1],
+ ac->cmd[2], ac->cmd[3], ac->cmd[4], ac->cmd[5],
+ ac->cmd[6], ac->cmd[7], ac->cmd[8], ac->cmd[9],
+ ac->cmd[10], ac->cmd[11], ac->cmd[12],
+ ac->cmd[13], ac->cmd[14], ac->cmd[15], count);
+ atapi_enqueue (ata, ac);
+ wdstart (ata->ctrlr);
+}
+
+/*
+ * Queue new packet request, then call wdstart().
+ * Wait until the request is finished.
+ * Called on spl0().
+ * Return atapi error.
+ * Buffer pointed to by *addr should be placed in core memory, not in stack!
+ */
+struct atapires atapi_request_wait (struct atapi *ata, int unit,
+ u_char cmd, u_char a1, u_char a2, u_char a3, u_char a4,
+ u_char a5, u_char a6, u_char a7, u_char a8, u_char a9,
+ u_char a10, u_char a11, u_char a12, u_char a13, u_char a14, u_char a15,
+ char *addr, int count)
+{
+ struct atapicmd *ac;
+ int x = splbio ();
+ struct atapires result;
+
+ ac = atapi_alloc (ata);
+ ac->cmd[0] = cmd; ac->cmd[1] = a1;
+ ac->cmd[2] = a2; ac->cmd[3] = a3;
+ ac->cmd[4] = a4; ac->cmd[5] = a5;
+ ac->cmd[6] = a6; ac->cmd[7] = a7;
+ ac->cmd[8] = a8; ac->cmd[9] = a9;
+ ac->cmd[10] = a10; ac->cmd[11] = a11;
+ ac->cmd[12] = a12; ac->cmd[13] = a13;
+ ac->cmd[14] = a14; ac->cmd[15] = a15;
+ ac->unit = unit;
+ ac->addr = addr;
+ ac->count = count;
+ ac->callback = 0;
+ ac->cbarg1 = 0;
+ ac->cbarg2 = 0;
+
+ if (ata->debug)
+ printf ("atapi%d.%d: req w %x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x len=%d\n",
+ ata->ctrlr, ac->unit, ac->cmd[0], ac->cmd[1],
+ ac->cmd[2], ac->cmd[3], ac->cmd[4], ac->cmd[5],
+ ac->cmd[6], ac->cmd[7], ac->cmd[8], ac->cmd[9],
+ ac->cmd[10], ac->cmd[11], ac->cmd[12],
+ ac->cmd[13], ac->cmd[14], ac->cmd[15], count);
+ atapi_enqueue (ata, ac);
+ wdstart (ata->ctrlr);
+ tsleep ((caddr_t)ac, PRIBIO, "atareq", 0);
+
+ result = ac->result;
+ atapi_free (ata, ac);
+ splx (x);
+ return (result);
+}
+
+/*
+ * Perform a packet command on the device.
+ * Should be called on splbio().
+ * Return atapi error.
+ */
+struct atapires atapi_request_immediate (struct atapi *ata, int unit,
+ u_char cmd, u_char a1, u_char a2, u_char a3, u_char a4,
+ u_char a5, u_char a6, u_char a7, u_char a8, u_char a9,
+ u_char a10, u_char a11, u_char a12, u_char a13, u_char a14, u_char a15,
+ char *addr, int count)
+{
+ struct atapicmd cmdbuf, *ac = &cmdbuf;
+ int cnt;
+
+ ac->cmd[0] = cmd; ac->cmd[1] = a1;
+ ac->cmd[2] = a2; ac->cmd[3] = a3;
+ ac->cmd[4] = a4; ac->cmd[5] = a5;
+ ac->cmd[6] = a6; ac->cmd[7] = a7;
+ ac->cmd[8] = a8; ac->cmd[9] = a9;
+ ac->cmd[10] = a10; ac->cmd[11] = a11;
+ ac->cmd[12] = a12; ac->cmd[13] = a13;
+ ac->cmd[14] = a14; ac->cmd[15] = a15;
+ ac->unit = unit;
+ ac->addr = addr;
+ ac->count = count;
+ ac->callback = 0;
+ ac->cbarg1 = 0;
+ ac->cbarg2 = 0;
+
+ if (ata->debug)
+ printf ("atapi%d.%d: req im %x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x len=%d\n",
+ ata->ctrlr, ac->unit, ac->cmd[0], ac->cmd[1],
+ ac->cmd[2], ac->cmd[3], ac->cmd[4], ac->cmd[5],
+ ac->cmd[6], ac->cmd[7], ac->cmd[8], ac->cmd[9],
+ ac->cmd[10], ac->cmd[11], ac->cmd[12],
+ ac->cmd[13], ac->cmd[14], ac->cmd[15], count);
+
+ /* Start packet command, wait for DRQ. */
+ if (atapi_start_cmd (ata, ac) >= 0 && atapi_wait_cmd (ata, ac) >= 0) {
+ /* Send packet command. */
+ atapi_send_cmd (ata, ac);
+
+ /* Wait for data i/o phase. */
+ for (cnt=20000; cnt>0; --cnt)
+ if (((inb (ata->port + AR_IREASON) & (ARI_CMD | ARI_IN)) |
+ (inb (ata->port + AR_STATUS) & ARS_DRQ)) != PHASE_CMDOUT)
+ break;
+
+ /* Do all needed i/o. */
+ while (atapi_io (ata, ac))
+ /* Wait for DRQ deassert. */
+ for (cnt=2000; cnt>0; --cnt)
+ if (! (inb (ata->port + AR_STATUS) & ARS_DRQ))
+ break;
+ }
+ return (ac->result);
+}
+#endif /* NWDC && ATAPI */
diff --git a/sys/i386/isa/atapi.h b/sys/i386/isa/atapi.h
new file mode 100644
index 000000000000..cb46dccea0aa
--- /dev/null
+++ b/sys/i386/isa/atapi.h
@@ -0,0 +1,215 @@
+/*
+ * Device-independent level for ATAPI drivers.
+ *
+ * Copyright (C) 1995 Cronyx Ltd.
+ * Author Serge Vakulenko, <vak@cronyx.ru>
+ *
+ * This software is distributed with NO WARRANTIES, not even the implied
+ * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Authors grant any other persons or organisations permission to use
+ * or modify this software as long as this message is kept with the software,
+ * all derivative works or modified versions.
+ *
+ * Version 1.8, Thu Sep 28 20:24:38 MSK 1995
+ */
+
+/*
+ * Disk Controller ATAPI register definitions.
+ */
+#define AR_DATA 0x0 /* RW - data register (16 bits) */
+#define AR_ERROR 0x1 /* R - error register */
+#define AR_FEATURES 0x1 /* W - features */
+#define AR_IREASON 0x2 /* RW - interrupt reason */
+#define AR_TAG 0x3 /* - reserved for SAM TAG byte */
+#define AR_CNTLO 0x4 /* RW - byte count, low byte */
+#define AR_CNTHI 0x5 /* RW - byte count, high byte */
+#define AR_DRIVE 0x6 /* RW - drive select */
+#define AR_COMMAND 0x7 /* W - command register */
+#define AR_STATUS 0x7 /* R - immediate status */
+
+/*
+ * Status register bits
+ */
+#define ARS_CHECK 0x01 /* error occured, see sense key/code */
+ /* bit 0x02 reserved */
+#define ARS_CORR 0x04 /* correctable error occured */
+#define ARS_DRQ 0x08 /* data request / ireason valid */
+#define ARS_DSC 0x10 /* immediate operation completed */
+#define ARS_DF 0x20 /* drive fault */
+#define ARS_DRDY 0x40 /* ready to get command */
+#define ARS_BSY 0x80 /* registers busy */
+ /* for overlap mode only: */
+#define ARS_SERVICE 0x10 /* service is requested */
+#define ARS_DMARDY 0x20 /* ready to start a DMA transfer */
+#define ARS_BITS "\20\010busy\7ready\6fault\5opdone\4drq\3corr\1check"
+
+/*
+ * Error register bits
+ */
+#define AER_ILI 0x01 /* illegal length indication */
+#define AER_EOM 0x02 /* end of media detected */
+#define AER_ABRT 0x04 /* command aborted */
+#define AER_MCR 0x08 /* media change requested */
+#define AER_SKEY 0xf0 /* sense key mask */
+#define AER_SK_NO_SENSE 0x00 /* no spesific sense key info */
+#define AER_SK_RECOVERED_ERROR 0x10 /* command succeeded, data recovered */
+#define AER_SK_NOT_READY 0x20 /* no access to drive */
+#define AER_SK_MEDIUM_ERROR 0x30 /* non-recovered data error */
+#define AER_SK_HARDWARE_ERROR 0x40 /* non-recoverable hardware failure */
+#define AER_SK_ILLEGAL_REQUEST 0x50 /* invalid command parameter(s) */
+#define AER_SK_UNIT_ATTENTION 0x60 /* media changed */
+#define AER_SK_DATA_PROTECT 0x70 /* reading read-protected sector */
+#define AER_SK_ABORTED_COMMAND 0xb0 /* command aborted, try again */
+#define AER_SK_MISCOMPARE 0xe0 /* data did not match the medium */
+#define AER_BITS "\20\4mchg\3abort\2eom\1ili"
+
+/*
+ * Feature register bits
+ */
+#define ARF_DMA 0x01 /* transfer data via DMA */
+#define ARF_OVERLAP 0x02 /* release the bus until completion */
+
+/*
+ * Interrupt reason register bits
+ */
+#define ARI_CMD 0x01 /* command(1) or data(0) */
+#define ARI_IN 0x02 /* transfer to(1) or from(0) the host */
+#define ARI_RELEASE 0x04 /* bus released until completion */
+
+/*
+ * Drive register values
+ */
+#define ARD_DRIVE0 0xa0 /* drive 0 selected */
+#define ARD_DRIVE1 0xb0 /* drive 1 selected */
+
+/*
+ * ATA commands
+ */
+#define ATAPIC_IDENTIFY 0xa1 /* get drive parameters */
+#define ATAPIC_PACKET 0xa0 /* execute packet command */
+
+/*
+ * Mandatory packet commands
+ */
+#define ATAPI_TEST_UNIT_READY 0x00 /* check if the device is ready */
+#define ATAPI_REQUEST_SENSE 0x03 /* get sense data */
+#define ATAPI_START_STOP 0x1b /* start/stop the media */
+#define ATAPI_PREVENT_ALLOW 0x1e /* prevent/allow media removal */
+#define ATAPI_READ_CAPACITY 0x25 /* get volume capacity */
+#define ATAPI_READ_BIG 0x28 /* read data */
+#define ATAPI_READ_TOC 0x43 /* get table of contents */
+#define ATAPI_READ_SUBCHANNEL 0x42 /* get subchannel info */
+#define ATAPI_MODE_SELECT_BIG 0x55 /* set device parameters */
+#define ATAPI_MODE_SENSE 0x5a /* get device parameters */
+#define ATAPI_PLAY_CD 0xb4 /* universal play command */
+
+/*
+ * Optional packet commands
+ */
+#define ATAPI_PLAY_MSF 0x47 /* play by MSF address */
+#define ATAPI_PAUSE 0x4b /* stop/start audio operation */
+
+/*
+ * Nonstandard packet commands
+ */
+#define ATAPI_PLAY_TRACK 0x48 /* play by track number */
+#define ATAPI_PLAY_BIG 0xa5 /* play by logical block address */
+
+/*
+ * Drive parameter information
+ */
+struct atapi_params {
+ unsigned cmdsz : 2; /* packet command size */
+#define AT_PSIZE_12 0 /* 12 bytes */
+#define AT_PSIZE_16 1 /* 16 bytes */
+ unsigned : 3;
+ unsigned drqtype : 2; /* DRQ type */
+#define AT_DRQT_MPROC 0 /* microprocessor DRQ - 3 msec delay */
+#define AT_DRQT_INTR 1 /* interrupt DRQ - 10 msec delay */
+#define AT_DRQT_ACCEL 2 /* accelerated DRQ - 50 usec delay */
+ unsigned removable : 1; /* device is removable */
+ unsigned devtype : 5; /* device type */
+#define AT_TYPE_DIRECT 0 /* direct-access (magnetic disk) */
+#define AT_TYPE_TAPE 1 /* streaming tape (QIC-121 model) */
+#define AT_TYPE_CDROM 5 /* CD-ROM device */
+#define AT_TYPE_OPTICAL 7 /* optical disk */
+ unsigned : 1;
+ unsigned proto : 2; /* command protocol */
+#define AT_PROTO_ATAPI 2
+ short reserved1[9];
+ char serial[20]; /* serial number - optional */
+ short reserved2[3];
+ char revision[8]; /* firmware revision */
+ char model[40]; /* model name */
+ short reserved3[2];
+ u_char vendor_cap; /* vendor unique capabilities */
+ unsigned dmaflag : 1; /* DMA supported */
+ unsigned lbaflag : 1; /* LBA supported - always 1 */
+ unsigned iordydis : 1; /* IORDY can be disabled */
+ unsigned iordyflag : 1; /* IORDY supported */
+ unsigned : 1;
+ unsigned ovlapflag : 1; /* overlap operation supported */
+ unsigned : 1;
+ unsigned idmaflag : 1; /* interleaved DMA supported */
+ short reserved4;
+ u_short pio_timing; /* PIO cycle timing */
+ u_short dma_timing; /* DMA cycle timing */
+ u_short flags;
+#define AT_FLAG_54_58 1 /* words 54-58 valid */
+#define AT_FLAG_64_70 2 /* words 64-70 valid */
+ short reserved5[8];
+ u_char swdma_flag; /* singleword DMA mode supported */
+ u_char swdma_active; /* singleword DMA mode active */
+ u_char mwdma_flag; /* multiword DMA mode supported */
+ u_char mwdma_active; /* multiword DMA mode active */
+ u_char apio_flag; /* advanced PIO mode supported */
+ u_char reserved6;
+ u_short mwdma_min; /* min. M/W DMA time per word (ns) */
+ u_short mwdma_dflt; /* recommended M/W DMA time (ns) - optional */
+ u_short pio_nfctl_min; /* min. PIO cycle time w/o flow ctl - optional */
+ u_short pio_iordy_min; /* min. PIO c/t with IORDY flow ctl - optional */
+ short reserved7[2];
+ u_short rls_ovlap; /* release time (us) for overlap cmd - optional */
+ u_short rls_service; /* release time (us) for service cmd - optional */
+};
+
+/*
+ * ATAPI operation result structure
+ */
+struct atapires {
+ u_char code; /* result code */
+#define RES_OK 0 /* i/o done */
+#define RES_ERR 1 /* i/o finished with error */
+#define RES_NOTRDY 2 /* controller not ready */
+#define RES_NODRQ 3 /* no data request */
+#define RES_INVDIR 4 /* invalid bus phase direction */
+#define RES_OVERRUN 5 /* data overrun */
+#define RES_UNDERRUN 6 /* data underrun */
+ u_char status; /* status register contents */
+ u_char error; /* error register contents */
+};
+
+#ifdef KERNEL
+struct atapi;
+struct kern_devconf;
+void atapi_attach (int ctlr, int unit, int port, struct kern_devconf*);
+int atapi_start (int ctrlr);
+int atapi_intr (int ctrlr);
+void atapi_debug (struct atapi *ata, int on);
+struct atapires atapi_request_wait (struct atapi *ata, int unit,
+ u_char cmd, u_char a1, u_char a2, u_char a3, u_char a4,
+ u_char a5, u_char a6, u_char a7, u_char a8, u_char a9,
+ u_char a10, u_char a11, u_char a12, u_char a13, u_char a14, u_char a15,
+ char *addr, int count);
+void atapi_request_callback (struct atapi *ata, int unit,
+ u_char cmd, u_char a1, u_char a2, u_char a3, u_char a4,
+ u_char a5, u_char a6, u_char a7, u_char a8, u_char a9,
+ u_char a10, u_char a11, u_char a12, u_char a13, u_char a14, u_char a15,
+ char *addr, int count, void (*done)(), void *x, void *y);
+struct atapires atapi_request_immediate (struct atapi *ata, int unit,
+ u_char cmd, u_char a1, u_char a2, u_char a3, u_char a4,
+ u_char a5, u_char a6, u_char a7, u_char a8, u_char a9,
+ u_char a10, u_char a11, u_char a12, u_char a13, u_char a14, u_char a15,
+ char *addr, int count);
+#endif
diff --git a/sys/i386/isa/wcd.c b/sys/i386/isa/wcd.c
new file mode 100644
index 000000000000..a5a2dffc5a24
--- /dev/null
+++ b/sys/i386/isa/wcd.c
@@ -0,0 +1,984 @@
+/*
+ * IDE CD-ROM driver for FreeBSD.
+ * Supports ATAPI-compatible drives.
+ *
+ * Copyright (C) 1995 Cronyx Ltd.
+ * Author Serge Vakulenko, <vak@cronyx.ru>
+ *
+ * This software is distributed with NO WARRANTIES, not even the implied
+ * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Authors grant any other persons or organisations permission to use
+ * or modify this software as long as this message is kept with the software,
+ * all derivative works or modified versions.
+ *
+ * Version 1.8, Thu Sep 28 21:04:16 MSK 1995
+ */
+
+#include "wdc.h"
+#include "wcd.h"
+#if NWCD > 0 && NWDC > 0 && defined (ATAPI)
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#include <sys/ioctl.h>
+#include <sys/devconf.h>
+#include <sys/disklabel.h>
+#include <sys/cdio.h>
+#include <i386/include/cpufunc.h>
+#include <i386/isa/atapi.h>
+
+#define NUNIT (NWDC*2) /* Max. number of devices */
+#define UNIT(d) ((minor(d) >> 3) & 3) /* Unit part of minor device number */
+#define SECSIZE 2048 /* CD-ROM sector size in bytes */
+
+#define F_OPEN 0x0001 /* The drive os opened */
+#define F_MEDIA_CHANGED 0x0002 /* The media have changed since open */
+#define F_DEBUG 0x0004 /* The media have changed since open */
+#define F_NOPLAYCD 0x0008 /* The PLAY_CD op not supported */
+
+/*
+ * Disc table of contents.
+ */
+#define MAXTRK 99
+struct toc {
+ struct ioc_toc_header hdr;
+ struct cd_toc_entry tab[MAXTRK+1]; /* One extra for the leadout */
+};
+
+/*
+ * Volume size info.
+ */
+struct volinfo {
+ u_long volsize; /* Volume size in blocks */
+ u_long blksize; /* Block size in bytes */
+} info;
+
+/*
+ * Current subchannel status.
+ */
+struct subchan {
+ u_char void0;
+ u_char audio_status;
+ u_short data_length;
+ u_char data_format;
+ u_char control;
+ u_char track;
+ u_char indx;
+ u_long abslba;
+ u_long rellba;
+};
+
+/*
+ * Audio Control Parameters Page
+ */
+struct audiopage {
+ /* Mode data header */
+ u_short data_length;
+ u_char medium_type;
+ u_char reserved1[5];
+
+ /* Audio control page */
+ u_char page_code;
+#define AUDIO_PAGE 0x0e
+#define AUDIO_PAGE_MASK 0x4e /* changeable values */
+ u_char param_len;
+ u_char flags;
+#define CD_PA_SOTC 0x02 /* mandatory */
+#define CD_PA_IMMED 0x04 /* always 1 */
+ u_char reserved3[3];
+ u_short lb_per_sec;
+ struct port_control {
+ u_char channels : 4;
+#define CHANNEL_0 1 /* mandatory */
+#define CHANNEL_1 2 /* mandatory */
+#define CHANNEL_2 4 /* optional */
+#define CHANNEL_3 8 /* optional */
+ u_char volume;
+ } port[4];
+};
+
+/*
+ * CD-ROM Capabilities and Mechanical Status Page
+ */
+struct cappage {
+ /* Mode data header */
+ u_short data_length;
+ u_char medium_type;
+#define MDT_UNKNOWN 0x00
+#define MDT_DATA_120 0x01
+#define MDT_AUDIO_120 0x02
+#define MDT_COMB_120 0x03
+#define MDT_PHOTO_120 0x04
+#define MDT_DATA_80 0x05
+#define MDT_AUDIO_80 0x06
+#define MDT_COMB_80 0x07
+#define MDT_PHOTO_80 0x08
+#define MDT_NO_DISC 0x70
+#define MDT_DOOR_OPEN 0x71
+#define MDT_FMT_ERROR 0x72
+ u_char reserved1[5];
+
+ /* Capabilities page */
+ u_char page_code;
+#define CAP_PAGE 0x2a
+ u_char param_len;
+ u_char reserved2[2];
+
+ u_char audio_play : 1; /* audio play supported */
+ u_char composite : 1; /* composite audio/video supported */
+ u_char dport1 : 1; /* digital audio on port 1 */
+ u_char dport2 : 1; /* digital audio on port 2 */
+ u_char mode2_form1 : 1; /* mode 2 form 1 (XA) read */
+ u_char mode2_form2 : 1; /* mode 2 form 2 format */
+ u_char multisession : 1; /* multi-session photo-CD */
+ u_char : 1;
+ u_char cd_da : 1; /* audio-CD read supported */
+ u_char cd_da_stream : 1; /* CD-DA streaming */
+ u_char rw : 1; /* combined R-W subchannels */
+ u_char rw_corr : 1; /* R-W subchannel data corrected */
+ u_char c2 : 1; /* C2 error pointers supported */
+ u_char isrc : 1; /* can return the ISRC info */
+ u_char upc : 1; /* can return the catalog number UPC */
+ u_char : 1;
+ u_char lock : 1; /* could be locked */
+ u_char locked : 1; /* current lock state */
+ u_char prevent : 1; /* prevent jumper installed */
+ u_char eject : 1; /* can eject */
+ u_char : 1;
+ u_char mech : 3; /* loading mechanism type */
+#define MECH_CADDY 0
+#define MECH_TRAY 1
+#define MECH_POPUP 2
+#define MECH_CHANGER 4
+#define MECH_CARTRIDGE 5
+ u_char sep_vol : 1; /* independent volume of channels */
+ u_char sep_mute : 1; /* independent mute of channels */
+ u_char : 6;
+
+ u_short max_speed; /* max raw data rate in bytes/1000 */
+ u_short max_vol_levels; /* number of discrete volume levels */
+ u_short buf_size; /* internal buffer size in bytes/1024 */
+ u_short cur_speed; /* current data rate in bytes/1000 */
+
+ /* Digital drive output format description (optional?) */
+ u_char reserved3;
+ u_char bckf : 1; /* data valid on failing edge of BCK */
+ u_char rch : 1; /* high LRCK indicates left channel */
+ u_char lsbf : 1; /* set if LSB first */
+ u_char dlen: 2;
+#define DLEN_32 0 /* 32 BCKs */
+#define DLEN_16 1 /* 16 BCKs */
+#define DLEN_24 2 /* 24 BCKs */
+#define DLEN_24_I2S 3 /* 24 BCKs (I2S) */
+ u_char : 3;
+ u_char reserved4[2];
+};
+
+struct wcd {
+ struct atapi *ata; /* Controller structure */
+ int unit; /* IDE bus drive unit */
+ int lun; /* Logical device unit */
+ int flags; /* Device state flags */
+ struct buf queue; /* Queue of i/o requests */
+ struct atapi_params *param; /* Drive parameters table */
+ struct toc toc; /* Table of disc contents */
+ struct volinfo info; /* Volume size info */
+ struct audiopage au; /* Audio page info */
+ struct cappage cap; /* Capabilities page info */
+ struct audiopage aumask; /* Audio page mask */
+ struct subchan subchan; /* Subchannel info */
+ struct kern_devconf cf; /* Driver configuration info */
+ char description[80]; /* Device description */
+};
+
+struct wcd *wcdtab[NUNIT]; /* Drive info by unit number */
+static int wcdnlun = 0; /* Number of configured drives */
+
+static void wcd_start (struct wcd *t);
+static void wcd_done (struct wcd *t, struct buf *bp, int resid,
+ struct atapires result);
+static void wcd_error (struct wcd *t, struct atapires result);
+static int wcd_read_toc (struct wcd *t);
+static int wcd_request_wait (struct wcd *t, u_char cmd, u_char a1, u_char a2,
+ u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
+ u_char a9, char *addr, int count);
+static int wcd_externalize (struct proc*, struct kern_devconf*, void*, size_t);
+static int wcd_goaway (struct kern_devconf *kdc, int force);
+static void wcd_describe (struct wcd *t);
+static int wcd_setchan (struct wcd *t,
+ u_char c0, u_char c1, u_char c2, u_char c3);
+
+static struct kern_devconf cftemplate = {
+ 0, 0, 0, "wcd", 0, { MDDT_DISK, 0 },
+ wcd_externalize, 0, wcd_goaway, DISK_EXTERNALLEN,
+ 0, 0, DC_IDLE, "ATAPI compact disc",
+};
+
+/*
+ * Dump the array in hexadecimal format for debugging purposes.
+ */
+static void wcd_dump (int lun, char *label, void *data, int len)
+{
+ u_char *p = data;
+
+ printf ("wcd%d: %s %x", lun, label, *p++);
+ while (--len > 0)
+ printf ("-%x", *p++);
+ printf ("\n");
+}
+
+static int wcd_externalize (struct proc *p, struct kern_devconf *kdc,
+ void *userp, size_t len)
+{
+ return disk_externalize (wcdtab[kdc->kdc_unit]->unit, userp, &len);
+}
+
+static int wcd_goaway (struct kern_devconf *kdc, int force)
+{
+ dev_detach (kdc);
+ return 0;
+}
+
+void wcdattach (struct atapi *ata, int unit, struct atapi_params *ap, int debug,
+ struct kern_devconf *parent)
+{
+ struct wcd *t;
+ struct atapires result;
+
+ if (wcdnlun >= NUNIT) {
+ printf ("wcd: too many units\n");
+ return;
+ }
+ t = malloc (sizeof (struct wcd), M_TEMP, M_NOWAIT);
+ if (! t) {
+ printf ("wcd: out of memory\n");
+ return;
+ }
+ wcdtab[wcdnlun] = t;
+ bzero (t, sizeof (struct wcd));
+ t->ata = ata;
+ t->unit = unit;
+ t->lun = wcdnlun++;
+ t->param = ap;
+ t->flags = F_MEDIA_CHANGED;
+ if (debug) {
+ t->flags |= F_DEBUG;
+ /* Print params. */
+ wcd_dump (t->lun, "info", ap, sizeof *ap);
+ }
+
+ /* Get drive capabilities. */
+ result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE,
+ 0, CAP_PAGE, 0, 0, 0, 0, sizeof (t->cap) >> 8, sizeof (t->cap),
+ 0, 0, 0, 0, 0, 0, 0, (char*) &t->cap, sizeof (t->cap));
+
+ /* Do it twice to avoid the stale media changed state. */
+ if (result.code == RES_ERR &&
+ (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)
+ result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE,
+ 0, CAP_PAGE, 0, 0, 0, 0, sizeof (t->cap) >> 8,
+ sizeof (t->cap), 0, 0, 0, 0, 0, 0, 0,
+ (char*) &t->cap, sizeof (t->cap));
+
+ /* Some drives have shorter capabilities page. */
+ if (result.code == RES_UNDERRUN)
+ result.code = 0;
+
+ if (result.code == 0) {
+ wcd_describe (t);
+ if (t->flags & F_DEBUG)
+ wcd_dump (t->lun, "cap", &t->cap, sizeof t->cap);
+ }
+
+ /* Register driver */
+ t->cf = cftemplate;
+ t->cf.kdc_unit = t->lun;
+ t->cf.kdc_parent = parent;
+ t->cf.kdc_description = t->description;
+ strcpy (t->description, cftemplate.kdc_description);
+ strcat (t->description, ": ");
+ strncpy (t->description + strlen(t->description),
+ ap->model, sizeof(ap->model));
+ dev_attach (&t->cf);
+}
+
+void wcd_describe (struct wcd *t)
+{
+ char *m;
+
+ t->cap.max_speed = ntohs (t->cap.max_speed);
+ t->cap.max_vol_levels = ntohs (t->cap.max_vol_levels);
+ t->cap.buf_size = ntohs (t->cap.buf_size);
+ t->cap.cur_speed = ntohs (t->cap.cur_speed);
+
+ printf ("wcd%d: ", t->lun);
+ if (t->cap.cur_speed != t->cap.max_speed)
+ printf ("%d/", t->cap.cur_speed * 1000 / 1024);
+ printf ("%dKb/sec", t->cap.max_speed * 1000 / 1024);
+ if (t->cap.buf_size)
+ printf (", %dKb cache", t->cap.buf_size);
+
+ if (t->cap.audio_play)
+ printf (", audio play");
+ if (t->cap.max_vol_levels)
+ printf (", %d volume levels", t->cap.max_vol_levels);
+
+ switch (t->cap.mech) {
+ default: m = 0; break;
+ case MECH_CADDY: m = "caddy"; break;
+ case MECH_TRAY: m = "tray"; break;
+ case MECH_POPUP: m = "popup"; break;
+ case MECH_CHANGER: m = "changer"; break;
+ case MECH_CARTRIDGE: m = "cartridge"; break;
+ }
+ if (m)
+ printf (", %s%s", t->cap.eject ? "ejectable " : "", m);
+ else if (t->cap.eject)
+ printf (", eject");
+ printf ("\n");
+
+ printf ("wcd%d: ", t->lun);
+ switch (t->cap.medium_type) {
+ case MDT_UNKNOWN: printf ("medium type unknown"); break;
+ case MDT_DATA_120: printf ("120mm data disc loaded"); break;
+ case MDT_AUDIO_120: printf ("120mm audio disc loaded"); break;
+ case MDT_COMB_120: printf ("120mm data/audio disc loaded"); break;
+ case MDT_PHOTO_120: printf ("120mm photo disc loaded"); break;
+ case MDT_DATA_80: printf ("80mm data disc loaded"); break;
+ case MDT_AUDIO_80: printf ("80mm audio disc loaded"); break;
+ case MDT_COMB_80: printf ("80mm data/audio disc loaded"); break;
+ case MDT_PHOTO_80: printf ("80mm photo disc loaded"); break;
+ case MDT_NO_DISC: printf ("no disc inside"); break;
+ case MDT_DOOR_OPEN: printf ("door open"); break;
+ case MDT_FMT_ERROR: printf ("medium format error"); break;
+ default: printf ("medium type=0x%x", t->cap.medium_type); break;
+ }
+ if (t->cap.lock)
+ printf (t->cap.locked ? ", locked" : ", unlocked");
+ if (t->cap.prevent)
+ printf (", lock protected");
+ printf ("\n");
+}
+
+int wcdopen (dev_t dev, int flags, int fmt, struct proc *p)
+{
+ int lun = UNIT(dev);
+ struct wcd *t;
+ struct atapires result;
+
+ /* Check the unit is legal. */
+ if (lun >= wcdnlun)
+ return (ENXIO);
+ t = wcdtab[lun];
+
+ /* If already opened, that's all. */
+ if (t->flags & F_OPEN) {
+ /* If it's been invalidated, forbid re-entry.
+ * (may have changed media) */
+ if (t->flags & F_MEDIA_CHANGED)
+ return (ENXIO);
+ return (0);
+ }
+
+ /* On the first open: check for the media.
+ * Do it twice to avoid the stale media changed state. */
+ result = atapi_request_wait (t->ata, t->unit, ATAPI_TEST_UNIT_READY,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+ if (result.code == RES_ERR &&
+ (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION) {
+ t->flags |= F_MEDIA_CHANGED;
+ result = atapi_request_wait (t->ata, t->unit,
+ ATAPI_TEST_UNIT_READY, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ }
+ if (result.code) {
+ wcd_error (t, result);
+ return (ENXIO);
+ }
+
+ /* Read table of contents. */
+ if (wcd_read_toc (t) != 0)
+ bzero (&t->toc, sizeof (t->toc));
+
+ /* Read disc capacity. */
+ if (wcd_request_wait (t, ATAPI_READ_CAPACITY, 0, 0, 0, 0, 0, 0,
+ 0, sizeof(t->info), 0, (char*)&t->info, sizeof(t->info)) != 0)
+ bzero (&t->info, sizeof (t->info));
+ t->info.volsize = ntohl (t->info.volsize);
+ t->info.blksize = ntohl (t->info.blksize);
+
+ /* Print the disc description string on every disc change.
+ * It would help to track the history of disc changes. */
+ if (t->info.volsize && t->toc.hdr.ending_track &&
+ (t->flags & F_MEDIA_CHANGED) && (t->flags & F_DEBUG)) {
+ printf ("wcd%d: ", t->lun);
+ if (t->toc.tab[0].control & 4)
+ printf ("%ldMB ", t->info.volsize / 512);
+ else
+ printf ("%ld:%ld audio ", t->info.volsize/75/60,
+ t->info.volsize/75%60);
+ printf ("(%ld sectors), %d tracks\n", t->info.volsize,
+ t->toc.hdr.ending_track - t->toc.hdr.starting_track + 1);
+ }
+ /* Lock the media. */
+ wcd_request_wait (t, ATAPI_PREVENT_ALLOW,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
+
+ t->flags &= ~F_MEDIA_CHANGED;
+ t->flags |= F_OPEN;
+ return (0);
+}
+
+/*
+ * Close the device. Only called if we are the LAST
+ * occurence of an open device.
+ */
+int wcdclose (dev_t dev, int flags, int fmt, struct proc *p)
+{
+ int lun = UNIT(dev);
+ struct wcd *t = wcdtab[lun];
+
+ /* If we were the last open of the entire device, release it. */
+ wcd_request_wait (t, ATAPI_PREVENT_ALLOW,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ t->flags &= ~F_OPEN;
+ return (0);
+}
+
+/*
+ * Actually translate the requested transfer into one the physical driver can
+ * understand. The transfer is described by a buf and will include only one
+ * physical transfer.
+ */
+void wcdstrategy (struct buf *bp)
+{
+ int lun = UNIT(bp->b_dev);
+ struct wcd *t = wcdtab[lun];
+ int x;
+
+ /* If the device has been made invalid, error out
+ * maybe the media changed. */
+ if (t->flags & F_MEDIA_CHANGED) {
+ bp->b_error = EIO;
+ bp->b_flags |= B_ERROR;
+ biodone (bp);
+ return;
+ }
+
+ /* Can't ever write to a CD. */
+ if (! (bp->b_flags & B_READ)) {
+ bp->b_error = EROFS;
+ bp->b_flags |= B_ERROR;
+ biodone (bp);
+ return;
+ }
+
+ /* If it's a null transfer, return immediatly. */
+ if (bp->b_bcount == 0) {
+ bp->b_resid = 0;
+ biodone (bp);
+ return;
+ }
+
+ /* Process transfer request. */
+ bp->b_pblkno = bp->b_blkno;
+ bp->b_resid = bp->b_bcount;
+ x = splbio();
+
+ /* Place it in the queue of disk activities for this disk. */
+ disksort (&t->queue, bp);
+
+ /* Tell the device to get going on the transfer if it's
+ * not doing anything, otherwise just wait for completion. */
+ wcd_start (t);
+ splx(x);
+}
+
+/*
+ * Look to see if there is a buf waiting for the device
+ * and that the device is not already busy. If both are true,
+ * It dequeues the buf and creates an ATAPI command to perform the
+ * transfer in the buf.
+ * The bufs are queued by the strategy routine (wcdstrategy).
+ * Must be called at the correct (splbio) level.
+ */
+static void wcd_start (struct wcd *t)
+{
+ struct buf *bp = t->queue.b_actf;
+ u_long blkno, nblk;
+
+ /* See if there is a buf to do and we are not already doing one. */
+ if (! bp)
+ return;
+
+ /* Unqueue the request. */
+ t->queue.b_actf = bp->b_actf;
+
+ /* Should reject all queued entries if media have changed. */
+ if (t->flags & F_MEDIA_CHANGED) {
+ bp->b_error = EIO;
+ bp->b_flags |= B_ERROR;
+ biodone (bp);
+ return;
+ }
+
+ /* We have a buf, now we should make a command
+ * First, translate the block to absolute and put it in terms of the
+ * logical blocksize of the device.
+ * What if something asks for 512 bytes not on a 2k boundary? */
+ blkno = bp->b_blkno / (SECSIZE / 512);
+ nblk = (bp->b_bcount + (SECSIZE - 1)) / SECSIZE;
+
+ atapi_request_callback (t->ata, t->unit, ATAPI_READ_BIG, 0,
+ blkno>>24, blkno>>16, blkno>>8, blkno, 0, nblk>>8, nblk, 0, 0,
+ 0, 0, 0, 0, 0, (u_char*) bp->b_un.b_addr, bp->b_bcount,
+ wcd_done, t, bp);
+ t->cf.kdc_state = DC_BUSY;
+}
+
+static void wcd_done (struct wcd *t, struct buf *bp, int resid,
+ struct atapires result)
+{
+ if (result.code) {
+ wcd_error (t, result);
+ bp->b_error = EIO;
+ bp->b_flags |= B_ERROR;
+ } else
+ bp->b_resid = resid;
+ biodone (bp);
+ t->cf.kdc_state = DC_IDLE;
+ wcd_start (t);
+}
+
+static void wcd_error (struct wcd *t, struct atapires result)
+{
+ if (result.code != RES_ERR)
+ return;
+ switch (result.error & AER_SKEY) {
+ case AER_SK_NOT_READY:
+ if (result.error & ~AER_SKEY) {
+ /* Audio disc. */
+ printf ("wcd%d: cannot read audio disc\n", t->lun);
+ return;
+ }
+ /* Tray open. */
+ if (! (t->flags & F_MEDIA_CHANGED))
+ printf ("wcd%d: tray open\n", t->lun);
+ t->flags |= F_MEDIA_CHANGED;
+ return;
+
+ case AER_SK_UNIT_ATTENTION:
+ /* Media changed. */
+ if (! (t->flags & F_MEDIA_CHANGED))
+ printf ("wcd%d: media changed\n", t->lun);
+ t->flags |= F_MEDIA_CHANGED;
+ return;
+
+ case AER_SK_ILLEGAL_REQUEST:
+ /* Unknown command or invalid command arguments. */
+ if (t->flags & F_DEBUG)
+ printf ("wcd%d: invalid command\n", t->lun);
+ return;
+ }
+ printf ("wcd%d: i/o error, status=%b, error=%b\n", t->lun,
+ result.status, ARS_BITS, result.error, AER_BITS);
+}
+
+static int wcd_request_wait (struct wcd *t, u_char cmd, u_char a1, u_char a2,
+ u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
+ u_char a9, char *addr, int count)
+{
+ struct atapires result;
+
+ t->cf.kdc_state = DC_BUSY;
+ result = atapi_request_wait (t->ata, t->unit, cmd,
+ a1, a2, a3, a4, a5, a6, a7, a8, a9, 0, 0, 0, 0, 0, 0,
+ addr, count);
+ t->cf.kdc_state = DC_IDLE;
+ if (result.code) {
+ wcd_error (t, result);
+ return (EIO);
+ }
+ return (0);
+}
+
+static int wcd_play (struct wcd *t, u_char cmd, u_char a1, u_char a2,
+ u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
+ u_char a9, char *addr, int count)
+{
+ struct atapires result;
+
+ if (! (t->flags & F_NOPLAYCD)) {
+ t->cf.kdc_state = DC_BUSY;
+ result = atapi_request_wait (t->ata, t->unit, ATAPI_PLAY_CD,
+ cmd == ATAPI_PLAY_MSF ? 2 : 0, a2, a3, a4, a5, a6,
+ a7, a8, a9, 0, 0, 0, 0, 0, 0, addr, count);
+ t->cf.kdc_state = DC_IDLE;
+ if (result.code == RES_ERR &&
+ (result.error & AER_SKEY) == AER_SK_ILLEGAL_REQUEST) {
+ /* Some drives don't support a PLAY_CD command.
+ * Remember this and use PLAY_MSF instead. */
+ t->flags |= F_NOPLAYCD;
+ result.code = 0;
+ }
+ if (result.code) {
+ wcd_error (t, result);
+ return (EIO);
+ }
+ }
+ return wcd_request_wait (t, cmd, a1, a2, a3, a4, a5, a6,
+ a7, a8, a9, addr, count);
+}
+
+static inline void lba2msf (int lba, u_char *m, u_char *s, u_char *f)
+{
+ lba += 150; /* offset of first logical frame */
+ lba &= 0xffffff; /* negative lbas use only 24 bits */
+ *m = lba / (60 * 75);
+ lba %= (60 * 75);
+ *s = lba / 75;
+ *f = lba % 75;
+}
+
+/*
+ * Perform special action on behalf of the user.
+ * Knows about the internals of this device
+ */
+int wcdioctl (dev_t dev, int cmd, caddr_t addr, int flags, struct proc *p)
+{
+ int lun = UNIT(dev);
+ struct wcd *t = wcdtab[lun];
+ int error = 0;
+
+ /* If the device is not valid.. abandon ship. */
+ if (t->flags & F_MEDIA_CHANGED)
+ return (EIO);
+ switch (cmd) {
+ default:
+ return (ENOTTY);
+
+ case CDIOCSETDEBUG:
+ if (p->p_cred->pc_ucred->cr_uid)
+ return (EPERM);
+ t->flags |= F_DEBUG;
+ atapi_debug (t->ata, 1);
+ return 0;
+
+ case CDIOCCLRDEBUG:
+ if (p->p_cred->pc_ucred->cr_uid)
+ return (EPERM);
+ t->flags &= ~F_DEBUG;
+ atapi_debug (t->ata, 0);
+ return 0;
+
+ case CDIOCRESUME:
+ return wcd_request_wait (t, ATAPI_PAUSE,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0);
+
+ case CDIOCPAUSE:
+ return wcd_request_wait (t, ATAPI_PAUSE,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+ case CDIOCSTART:
+ return wcd_request_wait (t, ATAPI_START_STOP,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
+
+ case CDIOCSTOP:
+ return wcd_request_wait (t, ATAPI_START_STOP,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+ case CDIOCALLOW:
+ return wcd_request_wait (t, ATAPI_PREVENT_ALLOW,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+ case CDIOCPREVENT:
+ return wcd_request_wait (t, ATAPI_PREVENT_ALLOW,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
+
+ case CDIOCRESET:
+ if (p->p_cred->pc_ucred->cr_uid)
+ return (EPERM);
+ return wcd_request_wait (t, ATAPI_TEST_UNIT_READY,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+ case CDIOCEJECT:
+ /* Stop the disc. */
+ error = wcd_request_wait (t, ATAPI_START_STOP,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ if (error)
+ return (error);
+ /* Give it some time to stop spinning. */
+ tsleep ((caddr_t)&lbolt, PRIBIO, "wcdejct", 0);
+ tsleep ((caddr_t)&lbolt, PRIBIO, "wcdejct", 0);
+ /* Eject. */
+ return wcd_request_wait (t, ATAPI_START_STOP,
+ 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0);
+
+ case CDIOREADTOCHEADER:
+ if (! t->toc.hdr.ending_track)
+ return (ENODEV);
+ bcopy (&t->toc.hdr, addr, sizeof t->toc.hdr);
+ break;
+
+ case CDIOREADTOCENTRYS: {
+ struct ioc_read_toc_entry *te =
+ (struct ioc_read_toc_entry*) addr;
+ struct toc *toc = &t->toc;
+ struct toc buf;
+ u_long len;
+
+ if (! t->toc.hdr.ending_track)
+ return (ENODEV);
+ if (te->starting_track < toc->hdr.starting_track ||
+ te->starting_track > toc->hdr.ending_track)
+ return (EINVAL);
+
+ len = (toc->hdr.ending_track - te->starting_track + 2) *
+ sizeof(toc->tab[0]);
+ if (te->data_len < len)
+ len = te->data_len;
+ if (len <= 0)
+ return (EINVAL);
+
+ /* Convert to MSF format, if needed. */
+ if (te->address_format == CD_MSF_FORMAT) {
+ struct cd_toc_entry *e;
+
+ buf = t->toc;
+ toc = &buf;
+ e = toc->tab + toc->hdr.ending_track -
+ te->starting_track + 2;
+ while (--e >= toc->tab)
+ lba2msf (e->addr.lba, &e->addr.msf.minute,
+ &e->addr.msf.second, &e->addr.msf.frame);
+ }
+ if (copyout (toc->tab + te->starting_track -
+ toc->hdr.starting_track, te->data, len) != 0)
+ error = EFAULT;
+ break;
+ }
+ case CDIOCREADSUBCHANNEL: {
+ struct ioc_read_subchannel *args =
+ (struct ioc_read_subchannel*) addr;
+ struct cd_sub_channel_info data;
+ u_long len = args->data_len;
+ int abslba, rellba;
+
+ if (len > sizeof(data) ||
+ len < sizeof(struct cd_sub_channel_header))
+ return (EINVAL);
+
+ if (wcd_request_wait (t, ATAPI_READ_SUBCHANNEL, 0, 0x40, 1, 0,
+ 0, 0, sizeof (t->subchan) >> 8, sizeof (t->subchan),
+ 0, (char*)&t->subchan, sizeof (t->subchan)) != 0)
+ return (EIO);
+ if (t->flags & F_DEBUG)
+ wcd_dump (t->lun, "subchan", &t->subchan, sizeof t->subchan);
+
+ abslba = ntohl (t->subchan.abslba);
+ rellba = ntohl (t->subchan.rellba);
+ if (args->address_format == CD_MSF_FORMAT) {
+ lba2msf (abslba,
+ &data.what.position.absaddr.msf.minute,
+ &data.what.position.absaddr.msf.second,
+ &data.what.position.absaddr.msf.frame);
+ lba2msf (rellba,
+ &data.what.position.reladdr.msf.minute,
+ &data.what.position.reladdr.msf.second,
+ &data.what.position.reladdr.msf.frame);
+ } else {
+ data.what.position.absaddr.lba = abslba;
+ data.what.position.reladdr.lba = rellba;
+ }
+ data.header.audio_status = t->subchan.audio_status;
+ data.what.position.control = t->subchan.control & 0xf;
+ data.what.position.track_number = t->subchan.track;
+ data.what.position.index_number = t->subchan.indx;
+
+ if (copyout (&data, args->data, len) != 0)
+ error = EFAULT;
+ break;
+ }
+ case CDIOCPLAYMSF: {
+ struct ioc_play_msf *args = (struct ioc_play_msf*) addr;
+
+ return wcd_play (t, ATAPI_PLAY_MSF, 0, 0,
+ args->start_m, args->start_s, args->start_f,
+ args->end_m, args->end_s, args->end_f, 0, 0, 0);
+ }
+ case CDIOCPLAYBLOCKS: {
+ struct ioc_play_blocks *args = (struct ioc_play_blocks*) addr;
+
+ return wcd_play (t, ATAPI_PLAY_BIG, 0,
+ args->blk >> 24 & 0xff, args->blk >> 16 & 0xff,
+ args->blk >> 8 & 0xff, args->blk & 0xff,
+ args->len >> 24 & 0xff, args->len >> 16 & 0xff,
+ args->len >> 8 & 0xff, args->len & 0xff, 0, 0);
+ }
+ case CDIOCPLAYTRACKS: {
+ struct ioc_play_track *args = (struct ioc_play_track*) addr;
+ u_long start, len;
+ int t1, t2;
+
+ if (! t->toc.hdr.ending_track)
+ return (ENODEV);
+
+ /* Ignore index fields,
+ * play from start_track to end_track inclusive. */
+ if (args->end_track < t->toc.hdr.ending_track+1)
+ ++args->end_track;
+ if (args->end_track > t->toc.hdr.ending_track+1)
+ args->end_track = t->toc.hdr.ending_track+1;
+ t1 = args->start_track - t->toc.hdr.starting_track;
+ t2 = args->end_track - t->toc.hdr.starting_track;
+ if (t1 < 0 || t2 < 0)
+ return (EINVAL);
+ start = t->toc.tab[t1].addr.lba;
+ len = t->toc.tab[t2].addr.lba - start;
+
+ return wcd_play (t, ATAPI_PLAY_BIG, 0,
+ start >> 24 & 0xff, start >> 16 & 0xff,
+ start >> 8 & 0xff, start & 0xff,
+ len >> 24 & 0xff, len >> 16 & 0xff,
+ len >> 8 & 0xff, len & 0xff, 0, 0);
+ }
+ case CDIOCGETVOL: {
+ struct ioc_vol *arg = (struct ioc_vol*) addr;
+
+ error = wcd_request_wait (t, ATAPI_MODE_SENSE, 0, AUDIO_PAGE,
+ 0, 0, 0, 0, sizeof (t->au) >> 8, sizeof (t->au), 0,
+ (char*) &t->au, sizeof (t->au));
+ if (error)
+ return (error);
+ if (t->flags & F_DEBUG)
+ wcd_dump (t->lun, "au", &t->au, sizeof t->au);
+ if (t->au.page_code != AUDIO_PAGE)
+ return (EIO);
+ arg->vol[0] = t->au.port[0].volume;
+ arg->vol[1] = t->au.port[1].volume;
+ arg->vol[2] = t->au.port[2].volume;
+ arg->vol[3] = t->au.port[3].volume;
+ break;
+ }
+ case CDIOCSETVOL: {
+ struct ioc_vol *arg = (struct ioc_vol*) addr;
+
+ error = wcd_request_wait (t, ATAPI_MODE_SENSE, 0, AUDIO_PAGE,
+ 0, 0, 0, 0, sizeof (t->au) >> 8, sizeof (t->au), 0,
+ (char*) &t->au, sizeof (t->au));
+ if (error)
+ return (error);
+ if (t->flags & F_DEBUG)
+ wcd_dump (t->lun, "au", &t->au, sizeof t->au);
+ if (t->au.page_code != AUDIO_PAGE)
+ return (EIO);
+
+ error = wcd_request_wait (t, ATAPI_MODE_SENSE, 0,
+ AUDIO_PAGE_MASK, 0, 0, 0, 0, sizeof (t->aumask) >> 8,
+ sizeof (t->aumask), 0, (char*) &t->aumask,
+ sizeof (t->aumask));
+ if (error)
+ return (error);
+ if (t->flags & F_DEBUG)
+ wcd_dump (t->lun, "mask", &t->aumask, sizeof t->aumask);
+
+ t->au.port[0].channels = CHANNEL_0;
+ t->au.port[1].channels = CHANNEL_1;
+ t->au.port[0].volume = arg->vol[0] & t->aumask.port[0].volume;
+ t->au.port[1].volume = arg->vol[1] & t->aumask.port[1].volume;
+ t->au.port[2].volume = arg->vol[2] & t->aumask.port[2].volume;
+ t->au.port[3].volume = arg->vol[3] & t->aumask.port[3].volume;
+ return wcd_request_wait (t, ATAPI_MODE_SELECT_BIG, 0x10,
+ 0, 0, 0, 0, 0, sizeof (t->au) >> 8, sizeof (t->au),
+ 0, (char*) &t->au, - sizeof (t->au));
+ }
+ case CDIOCSETPATCH: {
+ struct ioc_patch *arg = (struct ioc_patch*) addr;
+
+ return wcd_setchan (t, arg->patch[0], arg->patch[1],
+ arg->patch[2], arg->patch[3]);
+ }
+ case CDIOCSETMONO:
+ return wcd_setchan (t, CHANNEL_0 | CHANNEL_1,
+ CHANNEL_0 | CHANNEL_1, 0, 0);
+
+ case CDIOCSETSTERIO:
+ return wcd_setchan (t, CHANNEL_0, CHANNEL_1, 0, 0);
+
+ case CDIOCSETMUTE:
+ return wcd_setchan (t, 0, 0, 0, 0);
+
+ case CDIOCSETLEFT:
+ return wcd_setchan (t, CHANNEL_0, CHANNEL_0, 0, 0);
+
+ case CDIOCSETRIGHT:
+ return wcd_setchan (t, CHANNEL_1, CHANNEL_1, 0, 0);
+ }
+ return (error);
+}
+
+/*
+ * Read the entire TOC for the disc into our internal buffer.
+ */
+static int wcd_read_toc (struct wcd *t)
+{
+ int ntracks, len, i;
+
+ /* First read just the header, so we know how long the TOC is. */
+ len = sizeof(struct ioc_toc_header) + sizeof(struct cd_toc_entry);
+ if (wcd_request_wait (t, ATAPI_READ_TOC, 0, 0, 0, 0, 0, 0,
+ len >> 8, len & 0xff, 0, (char*)&t->toc, len) != 0)
+ return (EIO);
+
+ ntracks = t->toc.hdr.ending_track - t->toc.hdr.starting_track + 1;
+ if (ntracks <= 0)
+ return (EIO);
+ if (ntracks > MAXTRK)
+ ntracks = MAXTRK;
+
+ /* Now read the whole schmeer. */
+ len = sizeof(struct ioc_toc_header) +
+ (ntracks+1) * sizeof(struct cd_toc_entry);
+ if (wcd_request_wait (t, ATAPI_READ_TOC, 0, 0, 0, 0, 0, 0,
+ len >> 8, len & 0xff, 0, (char*)&t->toc, len) & 0xff)
+ return (EIO);
+
+ t->toc.hdr.len = ntohs (t->toc.hdr.len);
+ for (i=0; i<=ntracks; i++)
+ t->toc.tab[i].addr.lba = ntohl (t->toc.tab[i].addr.lba);
+ return (0);
+}
+
+/*
+ * Set up the audio channel masks.
+ */
+static int wcd_setchan (struct wcd *t,
+ u_char c0, u_char c1, u_char c2, u_char c3)
+{
+ int error;
+
+ error = wcd_request_wait (t, ATAPI_MODE_SENSE, 0, AUDIO_PAGE,
+ 0, 0, 0, 0, sizeof (t->au) >> 8, sizeof (t->au), 0,
+ (char*) &t->au, sizeof (t->au));
+ if (error)
+ return (error);
+ if (t->flags & F_DEBUG)
+ wcd_dump (t->lun, "au", &t->au, sizeof t->au);
+ if (t->au.page_code != AUDIO_PAGE)
+ return (EIO);
+
+ t->au.port[0].channels = c0;
+ t->au.port[1].channels = c1;
+ t->au.port[2].channels = c2;
+ t->au.port[3].channels = c3;
+ return wcd_request_wait (t, ATAPI_MODE_SELECT_BIG, 0x10,
+ 0, 0, 0, 0, 0, sizeof (t->au) >> 8, sizeof (t->au),
+ 0, (char*) &t->au, - sizeof (t->au));
+}
+#endif /* NWCD && NWDC && ATAPI */
diff --git a/usr.bin/ee/nls/de_DE.ISO_8859-1/ee.msg b/usr.bin/ee/nls/de_DE.ISO_8859-1/ee.msg
new file mode 100644
index 000000000000..f1aa1014bd75
--- /dev/null
+++ b/usr.bin/ee/nls/de_DE.ISO_8859-1/ee.msg
@@ -0,0 +1,170 @@
+$ This file contains the messages for ee ("easy editor"). See the file
+$ ee.i18n.guide for more information
+$
+$ For ee patchlevel 3
+$
+$ $Header$
+$
+$set 1
+$quote "
+1 "Modus-Menü"
+2 "Tab -> Leerzeichen "
+3 "Suche ohne Groß/Klein"
+4 "Ränder beachten "
+5 "Automatische Absätze "
+6 "8-Bit Zeichen (Uml.) "
+7 "Hilfefenster "
+8 "rechter Rand "
+9 "Ende-Menü"
+10 "Speichern"
+11 "Verwerfen"
+12 "Dateimenü"
+13 "Öffnen"
+14 "Schreiben in Datei"
+15 "Speichern"
+16 "Aktuellen Inhalt drucken"
+17 "Textsuche"
+18 "Suche nach ..."
+19 "Suchen"
+20 "Rechtschreibung"
+21 "'spell' benutzen"
+22 "'ispell' benutzen"
+23 "Verschiedenes"
+24 "Absatz formatieren"
+25 "Unix-Kommando"
+26 "Rechtschreibung prüfen"
+27 "Hauptmenü"
+28 "Editor beenden"
+29 "Hilfe"
+30 "Dateioperationen"
+31 "Bildschirm regenerieren"
+32 "Einstellungen"
+33 "Suche"
+34 "Verschiedenes"
+35 "Steuertasten: "
+36 "^a ASCII-Code direkt ^i Tabulator ^r nach rechts "
+37 "^b Ende des Textes ^j neue Zeile ^t Anfang des Textes "
+38 "^c Befehl ^k Zeichen löschen ^u hoch "
+39 "^d runter ^l nach links ^v Wort zurückholen "
+40 "^e Textsuche (Menü) ^m neue Zeile ^w Wort löschen "
+41 "^f Zeichen zurückholen ^n nächste Seite ^x Weitersuchen "
+42 "^g zum Zeilenanfang ^o zum Zeilenende ^y Zeile löschen "
+43 "^h Rückschritt ^p vorige Seite ^z Zeile zurückholen "
+44 "^[ (Escape) Menü "
+45 " "
+46 "Befehle: "
+47 "hilfe : diese Hilfe anzeigen datei : Dateinamen anzeigen "
+48 "lesen : Datei öffnen zeichen : ASCII-Code anzeigen "
+49 "schreiben:Datei schreiben grosskl : Suche mit Groß/Kleinschr."
+50 "ende : Sichern und Beenden klein : Suche ohne Groß/Klein. "
+51 "abbruch : Abbruch ohne Sichern !bef : Unix-Befehl \"bef\" ausf. "
+52 "zeile : Zeilennummer anzeigen 0-9 : Zur angegebenen Zeile "
+53 "leer : Tabulat. in Leerz. wandeln tabs : Tabulatoren belassen "
+54 " "
+55 " ee [-i] [-e] [-h] [datei(en)] "
+56 " -i : ohne Hilfefenster -e : Tabulatoren lassen -h : k. Hervorheb."
+57 "^[ (Escape) Menü ^e Textsuche ^y Zeile löschen ^u hoch ^p Seite zur. "
+58 "^a ASCII-Code ^x Weitersuchen ^z Zeile rückhl. ^d runter ^n Seite vor "
+59 "^b Textende ^g Zeilenanfang ^w Wort löschen ^l links "
+60 "^t Textanfang ^o Zeilenende ^v Wort rückhol. ^r rechts "
+61 "^c Befehl ^k Zeichen lösch. ^f Zeichen rückholen "
+62 "hilfe: Hilfe |datei : Dateiname anzeigen |zeile: Zeilennumer "
+63 "lesen: Datei lesen |zeichen:ASCII-Code des Zeichens |0-9 : zur Zeile "
+64 "schre: Datei schreib. |grosskl:Suche mit Groß/Klein |ende : Speichern,Ende "
+65 "!bef : Unix-\"bef\" |klein: Suche ohne Groß/Klein |abbr : Abbruch "
+66 "leer : Tab -> Leerz. |tabs : Tabulatoren belassen "
+67 " Escape (^[) drücken für Menü"
+68 "Keine Datei"
+69 "ASCII-Code: "
+70 "Pufferinhalt nach \"%s\" schreiben "
+71 "Befehl: "
+72 "Dateiname zum Schreiben: "
+73 "Dateiname zum Lesen: "
+74 "Zeichen = %d"
+75 "Unbekannter Befehl \"%s\""
+76 "Angegebener Befehl ist nicht eindeutig"
+77 "Zeile %d "
+78 "Länge = %d"
+79 "Aktuelle Datei ist \"%s\" "
+80 "Benutzung: %s [-i] [-e] [-h] [+zeilennummer] [dateien]\n"
+81 " -i Hilfefenster ausschalten\n"
+82 " -e Tabulatoren nicht in Leerzeichen wandeln\"
+83 " -h keine Hervorhebungen\n"
+84 "Datei \"%s\" ist ein Verzeichnis"
+85 "Neue Datei \"%s\""
+86 "Datei \"%s\" kann nicht geöffnet werden"
+87 "Datei \"%s\", %d Zeilen"
+88 "Lesen der Datei \"%s\" beendet"
+89 "Lese die Datei \"%s\""
+90 ", schreibgeschützt"
+91 "Datei \"%s\", %d Zeilen"
+92 "Dateinamen eingeben: "
+93 "Kein Name angegeben; Datei nicht gespeichert"
+94 "Pufferinhalt geändert, wirklich verlassen? (j/n [n]) "
+95 "j"
+96 "Datei existiert bereits, überschreiben? (j/n) [n] "
+97 "Datei \"%s\" kann nicht erzeugt werden"
+98 "Schreibe Datei \"%s\""
+99 "\"%s\" %d Zeilen, %d Zeichen"
+100 " ...Suche läuft"
+101 "Zeichenfolge \"%s\" nicht gefunden"
+102 "Suchen nach: "
+103 "Kann %s nicht ausführen\n"
+104 "Bitte die Eingabetaste drücken "
+105 "Escape zum Beenden"
+106 "Menü ist zu groß für das Fenster"
+107 "eine beliebige Taste drücken "
+108 "Unix-Befehl: "
+109 "...formatiere Absatz..."
+110 "<!echo 'Liste der nicht gefundenen Wörter'; echo -=-=-=-=-=-"
+111 "Sende den Pufferinhalt an 'spell'"
+112 "Rechter Rand: "
+113 "Eingeschränkter Modus: gewünschte Operation unzulässig"
+114 "EIN"
+115 "AUS"
+116 "HILFE"
+117 "SCHREIBEN"
+118 "LESEN"
+119 "ZEILE"
+120 "DATEI"
+121 "ZEICHEN"
+122 "REGENERIEREN"
+123 "UMNUMERIEREN"
+124 "AUTOR"
+125 "VERSION"
+126 "GROSSKL"
+127 "KLEIN"
+128 "LEER"
+129 "TABS"
+130 "ENDE"
+131 "ABBRUCH"
+132 "INFO"
+133 "[INFO]"
+134 "RAND"
+135 "[RAND]"
+136 "FORMAT."
+137 "[FORMAT.]"
+138 "ECHO"
+139 "DRUCKBEFEHL"
+140 "RECHTERRAND"
+141 "HERVORHEB."
+142 "[HERVORHEB.]"
+143 "8-BIT"
+144 "[8-BIT]"
+145 "Emacs-Tastenbelegung "
+146 "^a Zeilenanfang ^i Tabulator ^r Wort zurückholen "
+147 "^b ein Zeichen zurück ^j Zeichen zurückholen ^t Textanfang "
+148 "^c Befehl ^k Zeile löschen ^u Textende "
+149 "^d Zeichen löschen ^l Zeile zurückholen ^v nächste Seite "
+150 "^e Zeilenendee ^m neue Zeile ^w Wort löschen "
+151 "^f ein Zeichen vorwärts ^n neue Zeile ^x Weitersuchen "
+152 "^g vorige Seite ^o ASCII-Zeichen einfü. ^y Textsuche "
+153 "^h Rückschritt ^p vorige Zeile ^z nächstes Wort "
+154 "^[ (Escape) Menü ^y Suchtext eing. ^k Zeile löschen ^p vor.Zeile ^g vor.Seite"
+155 "^o ASCII-Zeichen ^x Weitersuchen ^l Zeile rückhol ^n nä. Zeile ^v nä. Seite"
+156 "^u Textende ^a Zeilenanfang ^w Wort löschen ^b ein Zeichen zurück "
+157 "^t Textanfang ^e Zeilenende ^r Wort rückhol. ^f ein Zeichen vor "
+158 "^c Befehl ^d Zeichen lösch. ^j Zeich. rückh. ^z nächstes Wort "
+159 "EMACS"
+160 "[EMACS]"
+161 " +<zahl> Zeiger auf Zeile <zahl> setzen"
diff --git a/usr.sbin/sicontrol/sicontrol.8 b/usr.sbin/sicontrol/sicontrol.8
new file mode 100644
index 000000000000..ce25794a004b
--- /dev/null
+++ b/usr.sbin/sicontrol/sicontrol.8
@@ -0,0 +1,113 @@
+.\" $Id$
+.\" The following requests are required for all man pages.
+.Dd September 26,1995
+.Dt SICONTROL 8
+.Os FreeBSD
+.Sh NAME
+.Nm sicontrol
+.Nd Specialix SI/XIO driver configuration and debugging
+.Sh SYNOPSIS
+.Nm sicontrol
+device
+.Ar command Op Cm Ar param ...
+.Sh DESCRIPTION
+.Nm sicontrol
+is used to configure and monitor the SI/XIO device driver.
+.Pp
+.Nm sicontrol
+operates on the specified
+.Ar device
+to indicate which port is to be used.
+.Pp
+The special
+.Ar device
+string `-' is used to indicate the global driver settings instead.
+.Pp
+A '/dev/' is included if necessary.
+.Pp
+The following commands are used for the global settings and should be
+specified with the '-' device name.
+.Bl -tag -width 4n
+.It Cm int_throttle Op Cm value
+Configure the `aggregate interrupt throttle value'.
+The maximum number of host adapter interrupts per second is determined by:
+.Pp
+.Ar "controller CPU clock / (8 * int_throttle)"
+.Pp
+The default value at boot time is 25000. The host adapter cpu clock is
+25Mhz. This gives a maximum interrupt rate of about 125 interrupts per
+second.
+.Pp
+Lowering this value will increase the rate in which the host adapter can
+interrupt the operating system for attention.
+.\"
+.It Cm rxint_throttle Op Cm value
+Configure the receiver interrupt throttle value.
+The default value of 4 at boot time allows an interrupt rate of
+approximately 25.
+.Pp
+Lowering this value will increase the rate in which the host adapter can
+interrupt the operating system to empty the receviver fifos.
+.\"
+.It Cm nport
+Returns the number of ports under the control of the device driver.
+.El
+.Pp
+The following commands are used for the individual ports and should be
+specified with a device name from /dev.
+.Bl -tag -width 4n
+.It Cm mstate
+Shows the current incoming modem control signals.
+.It Cm ccbstat
+Shows the current "ccb" structure for the specified port. This is not of
+much use outside of debugging the driver and determining why a port is
+wedged.
+.It Cm ttystat
+Shows the current "tty" structure that the kernel has for the specified port.
+This is not much use outside of debugging the driver.
+.El
+.\" The following requests should be uncommented and used where appropriate.
+.\" This next request is for sections 2 and 3 function return values only.
+.\" .Sh RETURN VALUES
+.\" This next request is for sections 1, 6, 7 & 8 only
+.\" .Sh ENVIRONMENT
+.Sh FILES
+.Bl -tag -width /dev/si_control -compact
+.It Pa /dev/si_control
+global driver control file for use by
+.Xr sicontrol 8 .
+.It Pa /dev/ttyA*
+terminal control ports
+.It Pa /dev/ttyiA*
+initial termios state devices, for use by
+.Xr stty 1
+.It Pa /dev/ttylA*
+locked termios state devices, for use by
+.Xr stty 1
+.El
+.\" .Sh EXAMPLES
+.\" This next request is for sections 1, 6, 7 & 8 only
+.\" (command return values (to shell) and fprintf/stderr type diagnostics)
+.Sh DIAGNOSTICS
+Generally self explanatory.....
+.\" The next request is for sections 2 and 3 error and signal handling only.
+.\" .Sh ERRORS
+.Sh SEE ALSO
+.Xr stty 1 ,
+.Xr termios 4 ,
+.Xr tty 4 ,
+.Xr si 4 ,
+.Xr comcontrol 8 .
+.\" .Sh STANDARDS
+.Sh HISTORY
+.Nm sicontrol
+is loosely based on a utility called
+.Nm siconfig
+which was written by
+.Nm "Andy Rutter <andy@acronym.co.uk>"
+.Pp
+Specialix International do not support this device driver in any way.
+.Sh AUTHORS
+Peter Wemm <peter@freebsd.org>
+.Sh BUGS
+Bound to be many... :-)