summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/libc/string/strlcpy.3149
-rw-r--r--release/sysinstall/dhcp.c156
-rw-r--r--sbin/ifconfig/ifvlan.c156
-rw-r--r--share/man/man4/intpm.464
-rw-r--r--share/man/man4/man4.i386/ste.4149
-rw-r--r--sys/dev/bktr/bktr_i2c.h34
-rw-r--r--sys/i386/i386/i686_mem.c588
-rw-r--r--sys/i386/i386/k6_mem.c190
-rw-r--r--sys/i386/include/i4b_rbch_ioctl.h53
-rw-r--r--sys/i4b/MAINTAINER1
-rw-r--r--sys/i4b/driver/i4b_bsdi_ibc.c559
-rw-r--r--sys/i4b/layer1/i4b_asuscom_ipac.c510
-rw-r--r--sys/i4b/layer1/i4b_avm_fritz_pci.c1732
-rw-r--r--sys/i4b/layer1/i4b_avm_fritz_pnp.c1268
-rw-r--r--sys/i4b/layer1/i4b_siemens_isurf.c317
-rw-r--r--sys/i4b/layer1/pci_isic.h53
-rw-r--r--sys/pci/alpm.c666
-rw-r--r--sys/pci/intpmreg.h77
-rw-r--r--sys/pci/xmaciireg.h393
-rw-r--r--sys/sys/memrange.h67
-rw-r--r--usr.sbin/i4b/dtmfdecode/Makefile15
-rw-r--r--usr.sbin/i4b/dtmfdecode/dtmfdecode.164
-rw-r--r--usr.sbin/i4b/dtmfdecode/dtmfdecode.c150
-rw-r--r--usr.sbin/i4b/g711conv/Makefile14
-rw-r--r--usr.sbin/i4b/g711conv/g711conv.196
-rw-r--r--usr.sbin/i4b/g711conv/g711conv.c304
-rw-r--r--usr.sbin/inetd/builtins.c682
-rw-r--r--usr.sbin/inetd/inetd.h134
-rw-r--r--usr.sbin/memcontrol/memcontrol.c341
-rw-r--r--usr.sbin/ppp/nat_cmd.h15
-rw-r--r--usr.sbin/pw/pw_vpw.c316
31 files changed, 9313 insertions, 0 deletions
diff --git a/lib/libc/string/strlcpy.3 b/lib/libc/string/strlcpy.3
new file mode 100644
index 000000000000..c7f1006fbda4
--- /dev/null
+++ b/lib/libc/string/strlcpy.3
@@ -0,0 +1,149 @@
+.\" $OpenBSD: strlcpy.3,v 1.5 1999/06/06 15:17:32 aaron Exp $
+.\"
+.\" Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.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.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+.\" AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+.\" THE AUTHOR 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 22, 1998
+.Dt STRLCPY 3
+.Os
+.Sh NAME
+.Nm strlcpy ,
+.Nm strlcat
+.Nd size-bounded string copying and concatenation
+.Sh SYNOPSIS
+.Fd #include <string.h>
+.Ft size_t
+.Fn strlcpy "char *dst" "const char *src" "size_t size"
+.Ft size_t
+.Fn strlcat "char *dst" "const char *src" "size_t size"
+.Sh DESCRIPTION
+The
+.Fn strlcpy
+and
+.Fn strlcat
+functions copy and concatenate strings respectively. They are designed
+to be safer, more consistent, and less error prone replacements for
+.Xr strncpy 3
+and
+.Xr strncat 3 .
+Unlike those functions,
+.Fn strlcpy
+and
+.Fn strlcat
+take the full size of the buffer (not just the length) and guarantee to
+NUL-terminate the result (as long as
+.Fa size
+is larger than 0). Note that you should include a byte for the NUL in
+.Fa size .
+.Pp
+The
+.Fn strlcpy
+function copies up to
+.Fa size
+- 1 characters from the NUL-terminated string
+.Fa src
+to
+.Fa dst ,
+NUL-terminating the result.
+.Pp
+The
+.Fn strlcat
+function appends the NUL-terminated string
+.Fa src
+to the end of
+.Fa dst .
+It will append at most
+.Fa size
+- strlen(dst) - 1 bytes, NUL-terminating the result.
+.Sh RETURN VALUES
+The
+.Fn strlcpy
+and
+.Fn strlcat
+functions return the total length of the string they tried to
+create. For
+.Fn strlcpy
+that means the length of
+.Fa src .
+For
+.Fn strlcat
+that means the initial length of
+.Fa dst
+plus
+the length of
+.Fa src .
+While this may seem somewhat confusing it was done to make
+truncation detection simple.
+.Sh EXAMPLES
+The following code fragment illustrates the simple case:
+.Bd -literal -offset indent
+char *s, *p, buf[BUFSIZ];
+
+.Li ...
+
+(void)strlcpy(buf, s, sizeof(buf));
+(void)strlcat(buf, p, sizeof(buf));
+.Ed
+.Pp
+To detect truncation, perhaps while building a pathname, something
+like the following might be used:
+.Bd -literal -offset indent
+char *dir, *file, pname[MAXPATHNAMELEN];
+
+.Li ...
+
+if (strlcpy(pname, dir, sizeof(pname)) >= sizeof(pname))
+ goto toolong;
+if (strlcat(pname, file, sizeof(pname)) >= sizeof(pname))
+ goto toolong;
+.Ed
+.Pp
+Since we know how many characters we copied the first time, we can
+speed things up a bit by using a copy instead on an append:
+.Bd -literal -offset indent
+char *dir, *file, pname[MAXPATHNAMELEN];
+size_t n;
+
+.Li ...
+
+n = strlcpy(pname, dir, sizeof(pname));
+if (n >= sizeof(pname))
+ goto toolong;
+if (strlcpy(pname + n, file, sizeof(pname) - n) >= sizeof(pname) - n)
+ goto toolong;
+.Ed
+.Pp
+However, one may question the validity of such optimizations, as they
+defeat the whole purpose of
+.Fn strlcpy
+and
+.Fn strlcat .
+As a matter of fact, the first version of this manual page got it wrong.
+.Sh SEE ALSO
+.Xr snprintf 3 ,
+.Xr strncat 3 ,
+.Xr strncpy 3
diff --git a/release/sysinstall/dhcp.c b/release/sysinstall/dhcp.c
new file mode 100644
index 000000000000..22eeeeb72e0f
--- /dev/null
+++ b/release/sysinstall/dhcp.c
@@ -0,0 +1,156 @@
+/*
+ * $FreeBSD$
+ *
+ * Copyright (c) 1999
+ * C. Stone. 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,
+ * verbatim and that no modifications are made prior to this
+ * point in the file.
+ * 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 C. STONE ``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 C STONE OR HIS BODILY PARASITES 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, LIFE 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 BY THE VOICES IN YOUR HEAD BEFOREHAND.
+ *
+ */
+
+#include "sysinstall.h"
+
+#include <ctype.h>
+
+int
+dhcpParseLeases(char *file, char *hostname, char *domain, char *nameserver,
+ char *ipaddr, char *gateway, char *netmask)
+{
+ char tempbuf[1024];
+ char optbuf[1024], *optname = NULL;
+ char *tptr;
+ int endedflag = 0;
+ int leaseflag = 0;
+ FILE *fp;
+ enum { P_NOSTMT, P_NOSTMT1, P_STMT, P_STMTLINE } state;
+
+ if ((fp = fopen(file, "r")) == NULL) {
+ msgDebug("error opening file %s: %s\n", file, strerror(errno));
+ return -1;
+ }
+
+ state = P_NOSTMT;
+ while (fscanf(fp, "%1023s", tempbuf) > 0) {
+ switch (state) {
+ case P_NOSTMT:
+ state = P_NOSTMT1;
+ if (!strncasecmp(tempbuf, "lease", 5)) {
+ if (!leaseflag)
+ leaseflag = 1;
+ else {
+ fclose(fp);
+ return 0;
+ }
+ }
+ break;
+
+ case P_NOSTMT1:
+ if (tempbuf[0] != '{') {
+ msgWarn("dhcpParseLeases: '{' expected");
+ fclose(fp);
+ return -1;
+ }
+ state = P_STMT;
+ break;
+
+ case P_STMT:
+ if (!strncasecmp("option", tempbuf, 6))
+ continue;
+ if (tempbuf[0] == '}') {
+ state = P_NOSTMT;
+ leaseflag = 0;
+ continue;
+ }
+ if (!leaseflag)
+ break;
+ if (tempbuf[0] == ';') { /* play it safe */
+ state = P_STMT;
+ continue;
+ }
+ if ((tptr = (char *)strchr(tempbuf, ';')) && (*(tptr + 1) == 0)) {
+ *tptr = NULL;
+ endedflag = 1;
+ }
+ if (!isalnum(tempbuf[0])) {
+ msgWarn("dhcpParseLeases: bad option");
+ fclose(fp);
+ return -1;
+ }
+ if (optname)
+ free(optname);
+ optname = strdup(tempbuf);
+ if (endedflag) {
+ state = P_STMT;
+ endedflag = 0;
+ continue;
+ }
+ state = P_STMTLINE;
+ break;
+
+ case P_STMTLINE:
+ if (tempbuf[0] == ';') {
+ state = P_STMT;
+ continue;
+ }
+ if ((tptr = (char *)strchr(tempbuf, ';')) && (*(tptr + 1) == 0)) {
+ *tptr = NULL;
+ endedflag = 1;
+ }
+ if (tempbuf[0] == '"') {
+ if (sscanf(tempbuf, "\"%[^\" ]\"", optbuf) < 1) {
+ msgWarn("dhcpParseLeases: bad option value");
+ fclose(fp);
+ return -1;
+ }
+ }
+ else
+ strcpy(optbuf, tempbuf);
+
+ if (!strcasecmp("host-name", optname)) {
+ strcpy(hostname, optbuf);
+ } else if (!strcasecmp("domain-name", optname)) {
+ strcpy(domain, optbuf);
+ } else if (!strcasecmp("fixed-address", optname)) {
+ strcpy(ipaddr, optbuf);
+ } else if (!strcasecmp("routers", optname)) {
+ strcpy(gateway, optbuf);
+ } else if (!strcasecmp("subnet-mask", optname)) {
+ strcpy(netmask, optbuf);
+ } else if (!strcasecmp("domain-name-servers", optname)) {
+ /* <jkh> ...one value per property */
+ if((tptr = (char *)strchr(optbuf, ',')))
+ *tptr = NULL;
+ strcpy(nameserver, optbuf);
+ }
+ if (endedflag) {
+ state = P_STMT;
+ endedflag = 0;
+ continue;
+ }
+ break;
+ }
+ }
+ fclose(fp);
+ return 0;
+}
diff --git a/sbin/ifconfig/ifvlan.c b/sbin/ifconfig/ifvlan.c
new file mode 100644
index 000000000000..3843821781c3
--- /dev/null
+++ b/sbin/ifconfig/ifvlan.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 1999
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_vlan_var.h>
+#include <net/route.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+
+#include "ifconfig.h"
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+static int __tag = 0;
+static int __have_tag = 0;
+
+void vlan_status(s, info)
+ int s;
+ struct rt_addrinfo *info __unused;
+{
+ struct vlanreq vreq;
+
+ bzero((char *)&vreq, sizeof(struct vlanreq));
+ ifr.ifr_data = (caddr_t)&vreq;
+
+ if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
+ return;
+
+ printf("\tvlan: %d parent interface: %s\n",
+ vreq.vlr_tag, vreq.vlr_parent[0] == '\0' ?
+ "<none>" : vreq.vlr_parent);
+
+ return;
+}
+
+void setvlantag(val, d, s, afp)
+ const char *val;
+ int d, s;
+ const struct afswtch *afp;
+{
+ u_int16_t tag;
+ struct vlanreq vreq;
+
+ __tag = tag = atoi(val);
+ __have_tag = 1;
+
+ bzero((char *)&vreq, sizeof(struct vlanreq));
+ ifr.ifr_data = (caddr_t)&vreq;
+
+ if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
+ err(1, "SIOCGETVLAN");
+
+ vreq.vlr_tag = tag;
+
+ if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSETVLAN");
+
+ return;
+}
+
+void setvlandev(val, d, s, afp)
+ const char *val;
+ int d, s;
+ const struct afswtch *afp;
+{
+ struct vlanreq vreq;
+
+ if (!__have_tag)
+ errx(1, "must specify both vlan tag and device");
+
+ bzero((char *)&vreq, sizeof(struct vlanreq));
+ ifr.ifr_data = (caddr_t)&vreq;
+
+ if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
+ err(1, "SIOCGETVLAN");
+
+ strncpy(vreq.vlr_parent, val, sizeof(vreq.vlr_parent));
+ vreq.vlr_tag = __tag;
+
+ if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSETVLAN");
+
+ return;
+}
+
+void unsetvlandev(val, d, s, afp)
+ const char *val;
+ int d, s;
+ const struct afswtch *afp;
+{
+ struct vlanreq vreq;
+
+ bzero((char *)&vreq, sizeof(struct vlanreq));
+ ifr.ifr_data = (caddr_t)&vreq;
+
+ if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
+ err(1, "SIOCGETVLAN");
+
+ bzero((char *)&vreq.vlr_parent, sizeof(vreq.vlr_parent));
+ vreq.vlr_tag = 0;
+
+ if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSETVLAN");
+
+ return;
+}
diff --git a/share/man/man4/intpm.4 b/share/man/man4/intpm.4
new file mode 100644
index 000000000000..0b973b7b34b9
--- /dev/null
+++ b/share/man/man4/intpm.4
@@ -0,0 +1,64 @@
+.\" Copyright (c) 1999 Takanori Watanabe
+.\" 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.\" Note: The date here should be updated whenever a non-trivial
+.\" change is made to the manual page.
+.Dd January 8, 1999
+.Dt INTPM 4 i386
+.\" Note: Only specify the operating system when the command
+.\" is FreeBSD specific, otherwise use the .Os macro with no
+.\" arguments.
+.Os FreeBSD 3.0
+.Sh NAME
+.Nm intpm
+.Nd Intel PIIX4 Power management controller driver.
+.Sh SYNOPSIS
+.Cd controller smbus0
+.Cd controller intpm0
+
+.Sh DESCRIPTION
+This driver provides access to
+.Tn Intel PIIX4 PCI Controller function 3 ,
+Power management controller. Currently, only smbus controller
+function is implemented. But it also have bus idle monitoring function. It
+will display mapped I/O address for bus monitoring function when attaching.
+
+.Sh SEE ALSO
+.Xr smb 4 ,
+.Xr smbus 4
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 3.0 .
+.Sh AUTHORS
+This
+manual page was written by
+.An Takanori Watanabe Aq takawata@shidahara1.planet.sci.kobe-u.ac.jp .
+.Sh BUGS
+This device requires IRQ 9 exclusively. To use this, you should enable
+ACPI function in BIOS configuration, or PnP mechanism assigns conflicted
+IRQ for PnP ISA card. And don't use IRQ 9 for Non-PnP ISA cards.
diff --git a/share/man/man4/man4.i386/ste.4 b/share/man/man4/man4.i386/ste.4
new file mode 100644
index 000000000000..3da3895c54a4
--- /dev/null
+++ b/share/man/man4/man4.i386/ste.4
@@ -0,0 +1,149 @@
+.\" Copyright (c) 1997, 1998, 1999
+.\" Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+.\" 4. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
+.\" 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 21, 1999
+.Dt STE 4 i386
+.Os FreeBSD
+.Sh NAME
+.Nm ste
+.Nd
+Sundance Technologies ST201 fast ethernet device driver
+.Sh SYNOPSIS
+.Cd "controller miibus0"
+.Cd "device ste0"
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for PCI ethernet adapters and embedded
+controllers based on the Sundance Technologies ST201 PCI fast
+ethernet controller chip. This includes the D-Link DFE-550TX.
+.Pp
+The Sundance ST201 uses bus master DMA and is designed to be a
+3Com Etherlink XL workalike. It uses the same DMA descriptor
+structure and is very similar in operation, however its register
+layout is different. The ST201 has a 64-bit multicast hash filter
+and a single perfect filter entry for the station address. IT
+supports both 10 and 100Mbps speeds in either full or half duplex
+using an MII transceiver.
+.Pp
+The
+.Nm
+driver supports the following media types:
+.Pp
+.Bl -tag -width xxxxxxxxxxxxxxxxxxxx
+.It autoselect
+Enable autoselection of the media type and options.
+The user can manually override
+the autoselected mode by adding media options to the
+.Pa /etc/rc.conf
+fine.
+.It 10baseT/UTP
+Set 10Mbps operation. The
+.Ar mediaopt
+option can also be used to select either
+.Ar full-duplex
+or
+.Ar half-duplex modes.
+.It 100baseTX
+Set 100Mbps (fast ethernet) operation. The
+.Ar mediaopt
+option can also be used to select either
+.Ar full-duplex
+or
+.Ar half-duplex
+modes.
+.El
+.Pp
+The
+.Nm
+driver supports the following media options:
+.Pp
+.Bl -tag -width xxxxxxxxxxxxxxxxxxxx
+.It full-duplex
+Force full duplex operation
+.It half-duplex
+Force half duplex operation.
+.El
+.Pp
+For more information on configuring this device, see
+.Xr ifconfig 8 .
+.Sh DIAGNOSTICS
+.Bl -diag
+.It "ste%d: couldn't map ports/memory"
+A fatal initialization error has occurred.
+.It "ste%d: couldn't map interrupt"
+A fatal initialization error has occurred.
+.It "ste%d: watchdog timeout"
+The device has stopped responding to the network, or there is a problem with
+the network connection (cable).
+.It "ste%d: no memory for rx list"
+The driver failed to allocate an mbuf for the receiver ring.
+.It "ste%d: no memory for tx list"
+The driver failed to allocate an mbuf for the transmitter ring when
+allocating a pad buffer or collapsing an mbuf chain into a cluster.
+.It "ste%d: chip is in D3 power state -- setting to D0"
+This message applies only to adapters which support power
+management. Some operating systems place the controller in low power
+mode when shutting down, and some PCI BIOSes fail to bring the chip
+out of this state before configuring it. The controller loses all of
+its PCI configuration in the D3 state, so if the BIOS does not set
+it back to full power mode in time, it won't be able to configure it
+correctly. The driver tries to detect this condition and bring
+the adapter back to the D0 (full power) state, but this may not be
+enough to return the driver to a fully operational condition. If
+you see this message at boot time and the driver fails to attach
+the device as a network interface, you will have to perform second
+warm boot to have the device properly configured.
+.Pp
+Note that this condition only occurs when warm booting from another
+operating system. If you power down your system prior to booting
+.Fx ,
+the card should be configured correctly.
+.El
+.Sh SEE ALSO
+.Xr arp 4 ,
+.Xr netintro 4 ,
+.Xr ifconfig 8
+.Rs
+.%T Sundance ST201 data sheet
+.%O http://www.sundanceti.com
+.Re
+.Sh HISTORY
+The
+.Nm
+device driver first appeared in
+.Fx 3.0 .
+.Sh AUTHORS
+The
+.Nm
+driver was written by
+.An Bill Paul Aq wpaul@ee.columbia.edu .
diff --git a/sys/dev/bktr/bktr_i2c.h b/sys/dev/bktr/bktr_i2c.h
new file mode 100644
index 000000000000..075e9885ae5d
--- /dev/null
+++ b/sys/dev/bktr/bktr_i2c.h
@@ -0,0 +1,34 @@
+/*-
+ * Copyright (c) 1998 Nicolas Souchu
+ * 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+#ifndef _BT848_I2C_H
+#define _BT848_I2C_H
+
+extern int bt848_i2c_attach(int, bt848_ptr_t, struct bktr_i2c_softc *);
+
+#endif
diff --git a/sys/i386/i386/i686_mem.c b/sys/i386/i386/i686_mem.c
new file mode 100644
index 000000000000..33342b92227c
--- /dev/null
+++ b/sys/i386/i386/i686_mem.c
@@ -0,0 +1,588 @@
+/*-
+ * Copyright (c) 1999 Michael Smith <msmith@freebsd.org>
+ * 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "opt_smp.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/ioccom.h>
+#include <sys/malloc.h>
+#include <sys/memrange.h>
+
+#include <machine/md_var.h>
+#include <machine/specialreg.h>
+
+#ifdef SMP
+#include "machine/smp.h"
+#endif
+
+/*
+ * i686 memory range operations
+ *
+ * This code will probably be impenetrable without reference to the
+ * Intel Pentium Pro documentation.
+ */
+
+static char *mem_owner_bios = "BIOS";
+
+#define MR686_FIXMTRR (1<<0)
+
+#define mrwithin(mr, a) \
+ (((a) >= (mr)->mr_base) && ((a) < ((mr)->mr_base + (mr)->mr_len)))
+#define mroverlap(mra, mrb) \
+ (mrwithin(mra, mrb->mr_base) || mrwithin(mrb, mra->mr_base))
+
+#define mrvalid(base, len) \
+ ((!(base & ((1 << 12) - 1))) && /* base is multiple of 4k */ \
+ ((len) >= (1 << 12)) && /* length is >= 4k */ \
+ powerof2((len)) && /* ... and power of two */ \
+ !((base) & ((len) - 1))) /* range is not discontiuous */
+
+#define mrcopyflags(curr, new) (((curr) & ~MDF_ATTRMASK) | ((new) & MDF_ATTRMASK))
+
+static void i686_mrinit(struct mem_range_softc *sc);
+static int i686_mrset(struct mem_range_softc *sc,
+ struct mem_range_desc *mrd,
+ int *arg);
+static void i686_mrAPinit(struct mem_range_softc *sc);
+
+static struct mem_range_ops i686_mrops = {
+ i686_mrinit,
+ i686_mrset,
+ i686_mrAPinit
+};
+
+/* XXX for AP startup hook */
+static u_int64_t mtrrcap, mtrrdef;
+
+static struct mem_range_desc *mem_range_match(struct mem_range_softc *sc,
+ struct mem_range_desc *mrd);
+static void i686_mrfetch(struct mem_range_softc *sc);
+static int i686_mtrrtype(int flags);
+static void i686_mrstore(struct mem_range_softc *sc);
+static void i686_mrstoreone(void *arg);
+static struct mem_range_desc *i686_mtrrfixsearch(struct mem_range_softc *sc,
+ u_int64_t addr);
+static int i686_mrsetlow(struct mem_range_softc *sc,
+ struct mem_range_desc *mrd,
+ int *arg);
+static int i686_mrsetvariable(struct mem_range_softc *sc,
+ struct mem_range_desc *mrd,
+ int *arg);
+
+/* i686 MTRR type to memory range type conversion */
+static int i686_mtrrtomrt[] = {
+ MDF_UNCACHEABLE,
+ MDF_WRITECOMBINE,
+ 0,
+ 0,
+ MDF_WRITETHROUGH,
+ MDF_WRITEPROTECT,
+ MDF_WRITEBACK
+};
+
+/*
+ * i686 MTRR conflict matrix for overlapping ranges
+ *
+ * Specifically, this matrix allows writeback and uncached ranges
+ * to overlap (the overlapped region is uncached). The array index
+ * is the translated i686 code for the flags (because they map well).
+ */
+static int i686_mtrrconflict[] = {
+ MDF_WRITECOMBINE | MDF_WRITETHROUGH | MDF_WRITEPROTECT,
+ MDF_ATTRMASK,
+ 0,
+ 0,
+ MDF_ATTRMASK,
+ MDF_ATTRMASK,
+ MDF_WRITECOMBINE | MDF_WRITETHROUGH | MDF_WRITEPROTECT
+};
+
+/*
+ * Look for an exactly-matching range.
+ */
+static struct mem_range_desc *
+mem_range_match(struct mem_range_softc *sc, struct mem_range_desc *mrd)
+{
+ struct mem_range_desc *cand;
+ int i;
+
+ for (i = 0, cand = sc->mr_desc; i < sc->mr_ndesc; i++, cand++)
+ if ((cand->mr_base == mrd->mr_base) &&
+ (cand->mr_len == mrd->mr_len))
+ return(cand);
+ return(NULL);
+}
+
+/*
+ * Fetch the current mtrr settings from the current CPU (assumed to all
+ * be in sync in the SMP case). Note that if we are here, we assume
+ * that MTRRs are enabled, and we may or may not have fixed MTRRs.
+ */
+static void
+i686_mrfetch(struct mem_range_softc *sc)
+{
+ struct mem_range_desc *mrd;
+ u_int64_t msrv;
+ int i, j, msr;
+
+ mrd = sc->mr_desc;
+
+ /* Get fixed-range MTRRs */
+ if (sc->mr_cap & MR686_FIXMTRR) {
+ msr = MSR_MTRR64kBase;
+ for (i = 0; i < (MTRR_N64K / 8); i++, msr++) {
+ msrv = rdmsr(msr);
+ for (j = 0; j < 8; j++, mrd++) {
+ mrd->mr_flags = (mrd->mr_flags & ~MDF_ATTRMASK) |
+ i686_mtrrtomrt[msrv & 0xff] |
+ MDF_ACTIVE;
+ if (mrd->mr_owner[0] == 0)
+ strcpy(mrd->mr_owner, mem_owner_bios);
+ msrv = msrv >> 8;
+ }
+ }
+ msr = MSR_MTRR16kBase;
+ for (i = 0; i < (MTRR_N16K / 8); i++, msr++) {
+ msrv = rdmsr(msr);
+ for (j = 0; j < 8; j++, mrd++) {
+ mrd->mr_flags = (mrd->mr_flags & ~MDF_ATTRMASK) |
+ i686_mtrrtomrt[msrv & 0xff] |
+ MDF_ACTIVE;
+ if (mrd->mr_owner[0] == 0)
+ strcpy(mrd->mr_owner, mem_owner_bios);
+ msrv = msrv >> 8;
+ }
+ }
+ msr = MSR_MTRR4kBase;
+ for (i = 0; i < (MTRR_N4K / 8); i++, msr++) {
+ msrv = rdmsr(msr);
+ for (j = 0; j < 8; j++, mrd++) {
+ mrd->mr_flags = (mrd->mr_flags & ~MDF_ATTRMASK) |
+ i686_mtrrtomrt[msrv & 0xff] |
+ MDF_ACTIVE;
+ if (mrd->mr_owner[0] == 0)
+ strcpy(mrd->mr_owner, mem_owner_bios);
+ msrv = msrv >> 8;
+ }
+ }
+ }
+
+ /* Get remainder which must be variable MTRRs */
+ msr = MSR_MTRRVarBase;
+ for (; (mrd - sc->mr_desc) < sc->mr_ndesc; msr += 2, mrd++) {
+ msrv = rdmsr(msr);
+ mrd->mr_flags = (mrd->mr_flags & ~MDF_ATTRMASK) |
+ i686_mtrrtomrt[msrv & 0xff];
+ mrd->mr_base = msrv & 0x0000000ffffff000LL;
+ msrv = rdmsr(msr + 1);
+ mrd->mr_flags = (msrv & 0x800) ?
+ (mrd->mr_flags | MDF_ACTIVE) :
+ (mrd->mr_flags & ~MDF_ACTIVE);
+ /* Compute the range from the mask. Ick. */
+ mrd->mr_len = (~(msrv & 0x0000000ffffff000LL) & 0x0000000fffffffffLL) + 1;
+ if (!mrvalid(mrd->mr_base, mrd->mr_len))
+ mrd->mr_flags |= MDF_BOGUS;
+ /* If unclaimed and active, must be the BIOS */
+ if ((mrd->mr_flags & MDF_ACTIVE) && (mrd->mr_owner[0] == 0))
+ strcpy(mrd->mr_owner, mem_owner_bios);
+ }
+}
+
+/*
+ * Return the MTRR memory type matching a region's flags
+ */
+static int
+i686_mtrrtype(int flags)
+{
+ int i;
+
+ flags &= MDF_ATTRMASK;
+
+ for (i = 0; i < (sizeof(i686_mtrrtomrt) / sizeof(i686_mtrrtomrt[0])); i++) {
+ if (i686_mtrrtomrt[i] == 0)
+ continue;
+ if (flags == i686_mtrrtomrt[i])
+ return(i);
+ }
+ return(-1);
+}
+
+/*
+ * Update running CPU(s) MTRRs to match the ranges in the descriptor
+ * list.
+ *
+ * XXX Must be called with interrupts enabled.
+ */
+static void
+i686_mrstore(struct mem_range_softc *sc)
+{
+#ifdef SMP
+ /*
+ * We should use all_but_self_ipi() to call other CPUs into a
+ * locking gate, then call a target function to do this work.
+ * The "proper" solution involves a generalised locking gate
+ * implementation, not ready yet.
+ */
+ smp_rendezvous(NULL, i686_mrstoreone, NULL, (void *)sc);
+#else
+ disable_intr(); /* disable interrupts */
+ i686_mrstoreone((void *)sc);
+ enable_intr();
+#endif
+}
+
+/*
+ * Update the current CPU's MTRRs with those represented in the
+ * descriptor list. Note that we do this wholesale rather than
+ * just stuffing one entry; this is simpler (but slower, of course).
+ */
+static void
+i686_mrstoreone(void *arg)
+{
+ struct mem_range_softc *sc = (struct mem_range_softc *)arg;
+ struct mem_range_desc *mrd;
+ u_int64_t msrv;
+ int i, j, msr;
+ u_int cr4save;
+
+ mrd = sc->mr_desc;
+
+ cr4save = rcr4(); /* save cr4 */
+ if (cr4save & CR4_PGE)
+ load_cr4(cr4save & ~CR4_PGE);
+ load_cr0((rcr0() & ~CR0_NW) | CR0_CD); /* disable caches (CD = 1, NW = 0) */
+ wbinvd(); /* flush caches, TLBs */
+ wrmsr(MSR_MTRRdefType, rdmsr(MSR_MTRRdefType) & ~0x800); /* disable MTRRs (E = 0) */
+
+ /* Set fixed-range MTRRs */
+ if (sc->mr_cap & MR686_FIXMTRR) {
+ msr = MSR_MTRR64kBase;
+ for (i = 0; i < (MTRR_N64K / 8); i++, msr++) {
+ msrv = 0;
+ for (j = 7; j >= 0; j--) {
+ msrv = msrv << 8;
+ msrv |= (i686_mtrrtype((mrd + j)->mr_flags) & 0xff);
+ }
+ wrmsr(msr, msrv);
+ mrd += 8;
+ }
+ msr = MSR_MTRR16kBase;
+ for (i = 0; i < (MTRR_N16K / 8); i++, msr++) {
+ msrv = 0;
+ for (j = 7; j >= 0; j--) {
+ msrv = msrv << 8;
+ msrv |= (i686_mtrrtype((mrd + j)->mr_flags) & 0xff);
+ }
+ wrmsr(msr, msrv);
+ mrd += 8;
+ }
+ msr = MSR_MTRR4kBase;
+ for (i = 0; i < (MTRR_N4K / 8); i++, msr++) {
+ msrv = 0;
+ for (j = 7; j >= 0; j--) {
+ msrv = msrv << 8;
+ msrv |= (i686_mtrrtype((mrd + j)->mr_flags) & 0xff);
+ }
+ wrmsr(msr, msrv);
+ mrd += 8;
+ }
+ }
+
+ /* Set remainder which must be variable MTRRs */
+ msr = MSR_MTRRVarBase;
+ for (; (mrd - sc->mr_desc) < sc->mr_ndesc; msr += 2, mrd++) {
+ /* base/type register */
+ if (mrd->mr_flags & MDF_ACTIVE) {
+ msrv = mrd->mr_base & 0x0000000ffffff000LL;
+ msrv |= (i686_mtrrtype(mrd->mr_flags) & 0xff);
+ } else {
+ msrv = 0;
+ }
+ wrmsr(msr, msrv);
+
+ /* mask/active register */
+ if (mrd->mr_flags & MDF_ACTIVE) {
+ msrv = 0x800 | (~(mrd->mr_len - 1) & 0x0000000ffffff000LL);
+ } else {
+ msrv = 0;
+ }
+ wrmsr(msr + 1, msrv);
+ }
+ wbinvd(); /* flush caches, TLBs */
+ wrmsr(MSR_MTRRdefType, rdmsr(MSR_MTRRdefType) | 0x800); /* restore MTRR state */
+ load_cr0(rcr0() & ~(CR0_CD | CR0_NW)); /* enable caches CD = 0 and NW = 0 */
+ load_cr4(cr4save); /* restore cr4 */
+}
+
+/*
+ * Hunt for the fixed MTRR referencing (addr)
+ */
+static struct mem_range_desc *
+i686_mtrrfixsearch(struct mem_range_softc *sc, u_int64_t addr)
+{
+ struct mem_range_desc *mrd;
+ int i;
+
+ for (i = 0, mrd = sc->mr_desc; i < (MTRR_N64K + MTRR_N16K + MTRR_N4K); i++, mrd++)
+ if ((addr >= mrd->mr_base) && (addr < (mrd->mr_base + mrd->mr_len)))
+ return(mrd);
+ return(NULL);
+}
+
+/*
+ * Try to satisfy the given range request by manipulating the fixed MTRRs that
+ * cover low memory.
+ *
+ * Note that we try to be generous here; we'll bloat the range out to the
+ * next higher/lower boundary to avoid the consumer having to know too much
+ * about the mechanisms here.
+ *
+ * XXX note that this will have to be updated when we start supporting "busy" ranges.
+ */
+static int
+i686_mrsetlow(struct mem_range_softc *sc, struct mem_range_desc *mrd, int *arg)
+{
+ struct mem_range_desc *first_md, *last_md, *curr_md;
+
+ /* range check */
+ if (((first_md = i686_mtrrfixsearch(sc, mrd->mr_base)) == NULL) ||
+ ((last_md = i686_mtrrfixsearch(sc, mrd->mr_base + mrd->mr_len - 1)) == NULL))
+ return(EINVAL);
+
+ /* set flags, clear set-by-firmware flag */
+ for (curr_md = first_md; curr_md <= last_md; curr_md++) {
+ curr_md->mr_flags = mrcopyflags(curr_md->mr_flags & ~MDF_FIRMWARE, mrd->mr_flags);
+ bcopy(mrd->mr_owner, curr_md->mr_owner, sizeof(mrd->mr_owner));
+ }
+
+ return(0);
+}
+
+
+/*
+ * Modify/add a variable MTRR to satisfy the request.
+ *
+ * XXX needs to be updated to properly support "busy" ranges.
+ */
+static int
+i686_mrsetvariable(struct mem_range_softc *sc, struct mem_range_desc *mrd, int *arg)
+{
+ struct mem_range_desc *curr_md, *free_md;
+ int i;
+
+ /*
+ * Scan the currently active variable descriptors, look for
+ * one we exactly match (straight takeover) and for possible
+ * accidental overlaps.
+ * Keep track of the first empty variable descriptor in case we
+ * can't perform a takeover.
+ */
+ i = (sc->mr_cap & MR686_FIXMTRR) ? MTRR_N64K + MTRR_N16K + MTRR_N4K : 0;
+ curr_md = sc->mr_desc + i;
+ free_md = NULL;
+ for (; i < sc->mr_ndesc; i++, curr_md++) {
+ if (curr_md->mr_flags & MDF_ACTIVE) {
+ /* exact match? */
+ if ((curr_md->mr_base == mrd->mr_base) &&
+ (curr_md->mr_len == mrd->mr_len)) {
+ /* whoops, owned by someone */
+ if (curr_md->mr_flags & MDF_BUSY)
+ return(EBUSY);
+ /* Ok, just hijack this entry */
+ free_md = curr_md;
+ break;
+ }
+ /* non-exact overlap ? */
+ if (mroverlap(curr_md, mrd)) {
+ /* between conflicting region types? */
+ if ((i686_mtrrconflict[i686_mtrrtype(curr_md->mr_flags)] & mrd->mr_flags) ||
+ (i686_mtrrconflict[i686_mtrrtype(mrd->mr_flags)] & curr_md->mr_flags))
+ return(EINVAL);
+ }
+ } else if (free_md == NULL) {
+ free_md = curr_md;
+ }
+ }
+ /* got somewhere to put it? */
+ if (free_md == NULL)
+ return(ENOSPC);
+
+ /* Set up new descriptor */
+ free_md->mr_base = mrd->mr_base;
+ free_md->mr_len = mrd->mr_len;
+ free_md->mr_flags = mrcopyflags(MDF_ACTIVE, mrd->mr_flags);
+ bcopy(mrd->mr_owner, free_md->mr_owner, sizeof(mrd->mr_owner));
+ return(0);
+}
+
+/*
+ * Handle requests to set memory range attributes by manipulating MTRRs.
+ *
+ */
+static int
+i686_mrset(struct mem_range_softc *sc, struct mem_range_desc *mrd, int *arg)
+{
+ struct mem_range_desc *targ;
+ int error = 0;
+
+ switch(*arg) {
+ case MEMRANGE_SET_UPDATE:
+ /* make sure that what's being asked for is even possible at all */
+ if (!mrvalid(mrd->mr_base, mrd->mr_len) ||
+ (i686_mtrrtype(mrd->mr_flags & MDF_ATTRMASK) == -1))
+ return(EINVAL);
+
+#define FIXTOP ((MTRR_N64K * 0x10000) + (MTRR_N16K * 0x4000) + (MTRR_N4K * 0x1000))
+
+ /* are the "low memory" conditions applicable? */
+ if ((sc->mr_cap & MR686_FIXMTRR) &&
+ ((mrd->mr_base + mrd->mr_len) <= FIXTOP)) {
+ if ((error = i686_mrsetlow(sc, mrd, arg)) != 0)
+ return(error);
+ } else {
+ /* it's time to play with variable MTRRs */
+ if ((error = i686_mrsetvariable(sc, mrd, arg)) != 0)
+ return(error);
+ }
+ break;
+
+ case MEMRANGE_SET_REMOVE:
+ if ((targ = mem_range_match(sc, mrd)) == NULL)
+ return(ENOENT);
+ if (targ->mr_flags & MDF_FIXACTIVE)
+ return(EPERM);
+ if (targ->mr_flags & MDF_BUSY)
+ return(EBUSY);
+ targ->mr_flags &= ~MDF_ACTIVE;
+ targ->mr_owner[0] = 0;
+ break;
+
+ default:
+ return(EOPNOTSUPP);
+ }
+
+ /* update the hardware */
+ i686_mrstore(sc);
+ i686_mrfetch(sc); /* refetch to see where we're at */
+ return(0);
+}
+
+/*
+ * Work out how many ranges we support, initialise storage for them,
+ * fetch the initial settings.
+ */
+static void
+i686_mrinit(struct mem_range_softc *sc)
+{
+ struct mem_range_desc *mrd;
+ int nmdesc = 0;
+ int i;
+
+ mtrrcap = rdmsr(MSR_MTRRcap);
+ mtrrdef = rdmsr(MSR_MTRRdefType);
+
+ /* For now, bail out if MTRRs are not enabled */
+ if (!(mtrrdef & 0x800)) {
+ if (bootverbose)
+ printf("CPU supports MTRRs but not enabled\n");
+ return;
+ }
+ nmdesc = mtrrcap & 0xff;
+ printf("Pentium Pro MTRR support enabled\n");
+
+ /* If fixed MTRRs supported and enabled */
+ if ((mtrrcap & 0x100) && (mtrrdef & 0x400)) {
+ sc->mr_cap = MR686_FIXMTRR;
+ nmdesc += MTRR_N64K + MTRR_N16K + MTRR_N4K;
+ }
+
+ sc->mr_desc =
+ (struct mem_range_desc *)malloc(nmdesc * sizeof(struct mem_range_desc),
+ M_MEMDESC, M_WAITOK);
+ bzero(sc->mr_desc, nmdesc * sizeof(struct mem_range_desc));
+ sc->mr_ndesc = nmdesc;
+
+ mrd = sc->mr_desc;
+
+ /* Populate the fixed MTRR entries' base/length */
+ if (sc->mr_cap & MR686_FIXMTRR) {
+ for (i = 0; i < MTRR_N64K; i++, mrd++) {
+ mrd->mr_base = i * 0x10000;
+ mrd->mr_len = 0x10000;
+ mrd->mr_flags = MDF_FIXBASE | MDF_FIXLEN | MDF_FIXACTIVE;
+ }
+ for (i = 0; i < MTRR_N16K; i++, mrd++) {
+ mrd->mr_base = i * 0x4000 + 0x80000;
+ mrd->mr_len = 0x4000;
+ mrd->mr_flags = MDF_FIXBASE | MDF_FIXLEN | MDF_FIXACTIVE;
+ }
+ for (i = 0; i < MTRR_N4K; i++, mrd++) {
+ mrd->mr_base = i * 0x1000 + 0xc0000;
+ mrd->mr_len = 0x1000;
+ mrd->mr_flags = MDF_FIXBASE | MDF_FIXLEN | MDF_FIXACTIVE;
+ }
+ }
+
+ /*
+ * Get current settings, anything set now is considered to have
+ * been set by the firmware. (XXX has something already played here?)
+ */
+ i686_mrfetch(sc);
+ mrd = sc->mr_desc;
+ for (i = 0; i < sc->mr_ndesc; i++, mrd++) {
+ if (mrd->mr_flags & MDF_ACTIVE)
+ mrd->mr_flags |= MDF_FIRMWARE;
+ }
+}
+
+/*
+ * Initialise MTRRs on an AP after the BSP has run the init code.
+ */
+static void
+i686_mrAPinit(struct mem_range_softc *sc)
+{
+ i686_mrstoreone((void *)sc); /* set MTRRs to match BSP */
+ wrmsr(MSR_MTRRdefType, mtrrdef); /* set MTRR behaviour to match BSP */
+}
+
+static void
+i686_mem_drvinit(void *unused)
+{
+ /* Try for i686 MTRRs */
+ if (!strcmp(cpu_vendor, "GenuineIntel") &&
+ cpu_feature & CPUID_MTRR &&
+ (cpu_id & 0xf00) == 0x600) {
+ mem_range_softc.mr_op = &i686_mrops;
+ }
+}
+
+SYSINIT(i686memdev,SI_SUB_DRIVERS,SI_ORDER_FIRST,i686_mem_drvinit,NULL)
+
+
diff --git a/sys/i386/i386/k6_mem.c b/sys/i386/i386/k6_mem.c
new file mode 100644
index 000000000000..1045b28c9f77
--- /dev/null
+++ b/sys/i386/i386/k6_mem.c
@@ -0,0 +1,190 @@
+/*-
+ * Copyright (c) 1999 Brian Fundakowski Feldman
+ * 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/ioccom.h>
+#include <sys/malloc.h>
+#include <sys/memrange.h>
+
+#include <machine/md_var.h>
+#include <machine/specialreg.h>
+
+/*
+ * A K6-2 MTRR is defined as the highest 15 bits having the address, the next
+ * 15 having the mask, the 1st bit being "write-combining" and the 0th bit
+ * being "uncacheable".
+ *
+ * Address Mask WC UC
+ * | XXXXXXXXXXXXXXX | XXXXXXXXXXXXXXX | X | X |
+ *
+ * There are two of these in the 64-bit UWCCR.
+ */
+
+/*
+ * NOTE: I do _not_ comment my code unless it's truly necessary. Don't
+ * expect anything frivolous here, and do NOT touch my bit-shifts
+ * unless you want to break this.
+ */
+
+#define UWCCR 0xc0000085
+
+#define k6_reg_get(reg, addr, mask, wc, uc) do { \
+ addr = (reg) & 0xfffe0000; \
+ mask = ((reg) & 0x1fffc) >> 2; \
+ wc = ((reg) & 0x2) >> 1; \
+ uc = (reg) & 0x1; \
+ } while (0)
+
+#define k6_reg_make(addr, mask, wc, uc) \
+ ((addr) | ((mask) << 2) | ((wc) << 1) | uc)
+
+static void k6_mrinit(struct mem_range_softc *sc);
+static int k6_mrset(struct mem_range_softc *, struct mem_range_desc *, int *);
+static __inline int k6_mrmake(struct mem_range_desc *, u_int32_t *);
+static void k6_mem_drvinit(void *);
+
+static struct mem_range_ops k6_mrops = {
+ k6_mrinit,
+ k6_mrset,
+ NULL
+};
+
+static __inline int
+k6_mrmake(struct mem_range_desc *desc, u_int32_t *mtrr) {
+ u_int32_t len = 0, wc, uc;
+ register int bit;
+
+ if (desc->mr_base &~ 0xfffe0000)
+ return EINVAL;
+ if (desc->mr_len < 131072 || !powerof2(desc->mr_len))
+ return EINVAL;
+ if (desc->mr_flags &~ (MDF_WRITECOMBINE|MDF_UNCACHEABLE))
+ return EOPNOTSUPP;
+
+ for (bit = ffs(desc->mr_len >> 17) - 1; bit < 15; bit++)
+ len |= 1 << (14 - bit);
+ wc = (desc->mr_flags & MDF_WRITECOMBINE) ? 1 : 0;
+ uc = (desc->mr_flags & MDF_UNCACHEABLE) ? 1 : 0;
+
+ *mtrr = k6_reg_make(desc->mr_base, len, wc, uc);
+ return 0;
+}
+
+static void
+k6_mrinit(struct mem_range_softc *sc) {
+ u_int64_t reg;
+ u_int32_t addr, mask, wc, uc;
+ int d;
+
+ sc->mr_cap = 0;
+ sc->mr_ndesc = 2; /* XXX (BFF) For now, we only have one msr for this */
+ sc->mr_desc = malloc(sc->mr_ndesc * sizeof(struct mem_range_desc),
+ M_MEMDESC, M_WAITOK);
+ bzero(sc->mr_desc, sc->mr_ndesc * sizeof(struct mem_range_desc));
+
+ reg = rdmsr(UWCCR);
+ for (d = 0; d < sc->mr_ndesc; d++) {
+ u_int32_t one = (reg & (0xffffffff << (32 * d))) >> (32 * d);
+
+ k6_reg_get(one, addr, mask, wc, uc);
+ sc->mr_desc[d].mr_base = addr;
+ sc->mr_desc[d].mr_len = ffs(mask) << 17;
+ if (wc)
+ sc->mr_desc[d].mr_flags |= MDF_WRITECOMBINE;
+ if (uc)
+ sc->mr_desc[d].mr_flags |= MDF_UNCACHEABLE;
+ }
+
+ printf("K6-family MTRR support enabled (%d registers)\n", sc->mr_ndesc);
+}
+
+static int
+k6_mrset(struct mem_range_softc *sc, struct mem_range_desc *desc, int *arg) {
+ u_int64_t reg;
+ u_int32_t mtrr;
+ int error, d;
+
+ switch (*arg) {
+ case MEMRANGE_SET_UPDATE:
+ error = k6_mrmake(desc, &mtrr);
+ if (error)
+ return error;
+ for (d = 0; d < sc->mr_ndesc; d++) {
+ if (!sc->mr_desc[d].mr_len) {
+ sc->mr_desc[d] = *desc;
+ goto out;
+ }
+ if (sc->mr_desc[d].mr_base == desc->mr_base &&
+ sc->mr_desc[d].mr_len == desc->mr_len)
+ return EEXIST;
+ }
+
+ return ENOSPC;
+ case MEMRANGE_SET_REMOVE:
+ mtrr = 0;
+ for (d = 0; d < sc->mr_ndesc; d++)
+ if (sc->mr_desc[d].mr_base == desc->mr_base &&
+ sc->mr_desc[d].mr_len == desc->mr_len) {
+ bzero(&sc->mr_desc[d], sizeof(sc->mr_desc[d]));
+ goto out;
+ }
+
+ return ENOENT;
+ default:
+ return EOPNOTSUPP;
+ }
+
+out:
+
+ disable_intr();
+ wbinvd();
+ reg = rdmsr(UWCCR);
+ reg &= ~(0xffffffff << (32 * d));
+ reg |= mtrr << (32 * d);
+ wrmsr(UWCCR, reg);
+ wbinvd();
+ enable_intr();
+
+ return 0;
+}
+
+static void
+k6_mem_drvinit(void *unused) {
+ if (!strcmp(cpu_vendor, "AuthenticAMD") &&
+ (cpu_id & 0xf00) == 0x500 &&
+ ((cpu_id & 0xf0) > 0x80 ||
+ ((cpu_id & 0xf0) == 0x80 &&
+ (cpu_id & 0xf) > 0x7))
+ )
+ mem_range_softc.mr_op = &k6_mrops;
+}
+
+SYSINIT(k6memdev, SI_SUB_DRIVERS, SI_ORDER_FIRST, k6_mem_drvinit, NULL)
diff --git a/sys/i386/include/i4b_rbch_ioctl.h b/sys/i386/include/i4b_rbch_ioctl.h
new file mode 100644
index 000000000000..62d2829b8b83
--- /dev/null
+++ b/sys/i386/include/i4b_rbch_ioctl.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1999 Hellmuth Michaelis. 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b_rbch_ioctl.h raw B-channel driver interface ioctls
+ * ------------------------------------------------------
+ *
+ * $FreeBSD$
+ *
+ * last edit-date: [Fri Jul 9 08:35:07 1999]
+ *
+ *---------------------------------------------------------------------------*/
+
+#ifndef _I4B_RBCH_IOCTL_H_
+#define _I4B_RBCH_IOCTL_H_
+
+/*---------------------------------------------------------------------------*
+ * instruct the rbch device to dial the given number
+ *---------------------------------------------------------------------------*/
+
+typedef char telno_t[TELNO_MAX];
+
+#define I4B_RBCH_DIALOUT _IOW('R', 1, telno_t)
+
+/*---------------------------------------------------------------------------*
+ * request version and release info from kernel part
+ *---------------------------------------------------------------------------*/
+
+#define I4B_RBCH_VR_REQ _IOR('R', 2, msg_vr_req_t)
+
+#endif /* _I4B_RBCH_IOCTL_H_ */
diff --git a/sys/i4b/MAINTAINER b/sys/i4b/MAINTAINER
new file mode 100644
index 000000000000..fae4d58f6898
--- /dev/null
+++ b/sys/i4b/MAINTAINER
@@ -0,0 +1 @@
+MAINTAINER = hm@freebsd.org
diff --git a/sys/i4b/driver/i4b_bsdi_ibc.c b/sys/i4b/driver/i4b_bsdi_ibc.c
new file mode 100644
index 000000000000..17d90c276f16
--- /dev/null
+++ b/sys/i4b/driver/i4b_bsdi_ibc.c
@@ -0,0 +1,559 @@
+/*
+ * Copyright (c) 1998, 1999 Bert Driehuis. All rights reserved.
+ *
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b_bsdi_ibc.c - isdn4bsd kernel BSD/OS point to point driver
+ * -------------------------------------------------------------
+ *
+ * $FreeBSD$
+ *
+ * last edit-date: [Fri Apr 23 10:27:57 1999]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "ibc.h"
+
+#if NIBC > 0
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/ioccom.h>
+#include <sys/ttycom.h>
+#include <sys/sockio.h>
+#include <sys/kernel.h>
+#include <sys/protosw.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/if_p2p.h>
+#include <net/netisr.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+
+#include <i4b/i4b_ioctl.h>
+#include <i4b/i4b_cause.h>
+#include <i4b/include/i4b_global.h>
+#include <i4b/include/i4b_mbuf.h>
+#include <i4b/include/i4b_l3l4.h>
+#include <i4b/layer4/i4b_l4.h>
+
+#define IFP2UNIT(ifp) (ifp)->if_unit
+
+#define IOCTL_CMD_T u_long
+
+void ibcattach(void *);
+
+#define IBCACCT 1 /* enable accounting messages */
+#define IBCACCTINTVL 2 /* accounting msg interval in secs */
+
+#define PPP_HDRLEN 4 /* 4 octets PPP header length */
+
+struct ibc_softc {
+ struct p2pcom sc_p2pcom;
+
+ int sc_state; /* state of the interface */
+ call_desc_t *sc_cdp; /* ptr to call descriptor */
+
+#ifdef IBCACCT
+ int sc_iinb; /* isdn driver # of inbytes */
+ int sc_ioutb; /* isdn driver # of outbytes */
+ int sc_inb; /* # of bytes rx'd */
+ int sc_outb; /* # of bytes tx'd */
+ int sc_linb; /* last # of bytes rx'd */
+ int sc_loutb; /* last # of bytes tx'd */
+ int sc_fn; /* flag, first null acct */
+#endif
+} ibc_softc[NIBC];
+
+static void ibc_init_linktab(int unit);
+
+static int ibc_start(struct ifnet *ifp);
+
+static int ibc_watchdog(int unit);
+static int ibc_mdmctl(struct p2pcom *pp, int flag);
+static int ibc_getmdm(struct p2pcom *pp, caddr_t arg);
+
+/* initialized by L4 */
+
+static drvr_link_t ibc_drvr_linktab[NIBC];
+static isdn_link_t *isdn_ibc_lt[NIBC];
+
+enum ibc_states {
+ ST_IDLE, /* initialized, ready, idle */
+ ST_DIALING, /* dialling out to remote */
+ ST_CONNECTED, /* connected to remote */
+};
+
+int ibcdebug = 0; /* Use bpatch to set this for debug printf's */
+#define DBG(x) if (ibcdebug) printf x
+
+/*===========================================================================*
+ * DEVICE DRIVER ROUTINES
+ *===========================================================================*/
+
+/*---------------------------------------------------------------------------*
+ * interface attach routine at kernel boot time
+ *---------------------------------------------------------------------------*/
+void
+ibcattach(void *dummy)
+{
+ struct ibc_softc *sc = ibc_softc;
+ struct ifnet *ifp;
+ int i;
+
+#ifndef HACK_NO_PSEUDO_ATTACH_MSG
+ printf("ibc: %d ISDN ibc device(s) attached\n",
+ NIBC);
+#endif
+
+ for(i = 0; i < NIBC; sc++, i++) {
+ ibc_init_linktab(i);
+
+ sc->sc_p2pcom.p2p_mdmctl = ibc_mdmctl;
+ sc->sc_p2pcom.p2p_getmdm = ibc_getmdm;
+ sc->sc_state = ST_IDLE;
+ ifp = &sc->sc_p2pcom.p2p_if;
+ ifp->if_name = "ibc";
+ ifp->if_next = NULL;
+ ifp->if_unit = i;
+ ifp->if_mtu = 1500 /*XXX*/;
+ ifp->if_baudrate = 64000;
+ ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT;
+ ifp->if_type = IFT_ISDNBASIC;
+ ifp->if_start = ibc_start;
+ ifp->if_output = 0;
+ ifp->if_ioctl = p2p_ioctl;
+
+ ifp->if_hdrlen = 0;
+ ifp->if_addrlen = 0;
+ ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
+
+ ifp->if_ipackets = 0;
+ ifp->if_ierrors = 0;
+ ifp->if_opackets = 0;
+ ifp->if_oerrors = 0;
+ ifp->if_collisions = 0;
+ ifp->if_ibytes = 0;
+ ifp->if_obytes = 0;
+ ifp->if_imcasts = 0;
+ ifp->if_omcasts = 0;
+ ifp->if_iqdrops = 0;
+ ifp->if_noproto = 0;
+#if IBCACCT
+ ifp->if_timer = 0;
+ ifp->if_watchdog = ibc_watchdog;
+ sc->sc_iinb = 0;
+ sc->sc_ioutb = 0;
+ sc->sc_inb = 0;
+ sc->sc_outb = 0;
+ sc->sc_linb = 0;
+ sc->sc_loutb = 0;
+ sc->sc_fn = 1;
+#endif
+ if_attach(ifp);
+ p2p_attach(&sc->sc_p2pcom);
+ }
+}
+
+static struct mbuf *
+p2p_dequeue(struct p2pcom *pp)
+{
+ struct ifqueue *ifq;
+ struct mbuf *m;
+
+ ifq = &pp->p2p_isnd;
+ m = ifq->ifq_head;
+ if (m == 0) {
+ ifq = &pp->p2p_if.if_snd;
+ m = ifq->ifq_head;
+ }
+ if (m == 0)
+ return 0;
+ IF_DEQUEUE(ifq, m);
+ return m;
+}
+
+/*---------------------------------------------------------------------------*
+ * start output to ISDN B-channel
+ *---------------------------------------------------------------------------*/
+static int
+ibc_start(struct ifnet *ifp)
+{
+ int unit = IFP2UNIT(ifp);
+ struct ibc_softc *sc = (struct ibc_softc *)&ibc_softc[unit];
+ struct p2pcom *pp = &sc->sc_p2pcom;
+ struct mbuf *m;
+ int s;
+
+ if(sc->sc_state != ST_CONNECTED) {
+ DBG(("ibc%d: ibc_start called with sc_state=%d\n",
+ unit, sc->sc_state));
+ return 0;
+ }
+
+ s = SPLI4B();
+
+ if (IF_QFULL(isdn_ibc_lt[unit]->tx_queue)) {
+ splx(s);
+ return 0;
+ }
+
+ m = p2p_dequeue(pp);
+ if (m == NULL) {
+ splx(s);
+ return 0;
+ }
+
+ do {
+ microtime(&ifp->if_lastchange);
+
+ IF_ENQUEUE(isdn_ibc_lt[unit]->tx_queue, m);
+
+ ifp->if_obytes += m->m_pkthdr.len;
+ sc->sc_outb += m->m_pkthdr.len;
+ ifp->if_opackets++;
+ } while (!IF_QFULL(isdn_ibc_lt[unit]->tx_queue) &&
+ (m = p2p_dequeue(pp)) != NULL);
+ isdn_ibc_lt[unit]->bch_tx_start(isdn_ibc_lt[unit]->unit,
+ isdn_ibc_lt[unit]->channel);
+ splx(s);
+ return 0;
+}
+
+#ifdef IBCACCT
+/*---------------------------------------------------------------------------*
+ * watchdog routine
+ *---------------------------------------------------------------------------*/
+static int
+ibc_watchdog(int unit)
+{
+ struct ibc_softc *sc = &ibc_softc[unit];
+ struct ifnet *ifp = &sc->sc_p2pcom.p2p_if;
+ bchan_statistics_t bs;
+
+ (*isdn_ibc_lt[unit]->bch_stat)
+ (isdn_ibc_lt[unit]->unit, isdn_ibc_lt[unit]->channel, &bs);
+
+ sc->sc_ioutb += bs.outbytes;
+ sc->sc_iinb += bs.inbytes;
+
+ if((sc->sc_iinb != sc->sc_linb) || (sc->sc_ioutb != sc->sc_loutb) || sc->sc_fn)
+ {
+ int ri = (sc->sc_iinb - sc->sc_linb)/IBCACCTINTVL;
+ int ro = (sc->sc_ioutb - sc->sc_loutb)/IBCACCTINTVL;
+
+ if((sc->sc_iinb == sc->sc_linb) && (sc->sc_ioutb == sc->sc_loutb))
+ sc->sc_fn = 0;
+ else
+ sc->sc_fn = 1;
+
+ sc->sc_linb = sc->sc_iinb;
+ sc->sc_loutb = sc->sc_ioutb;
+
+ i4b_l4_accounting(BDRV_IBC, unit, ACCT_DURING,
+ sc->sc_ioutb, sc->sc_iinb, ro, ri, sc->sc_outb, sc->sc_inb);
+ }
+ ifp->if_timer = IBCACCTINTVL;
+ return 0;
+}
+#endif /* IBCACCT */
+
+/*
+ *===========================================================================*
+ * P2P layer interface routines
+ *===========================================================================*
+ */
+
+#if 0
+/*---------------------------------------------------------------------------*
+ * PPP interface phase change
+ *---------------------------------------------------------------------------*
+ */
+static void
+ibc_state_changed(struct sppp *sp, int new_state)
+{
+ struct ibc_softc *sc = (struct ibc_softc *)sp;
+
+ i4b_l4_ifstate_changed(sc->sc_cdp, new_state);
+}
+
+/*---------------------------------------------------------------------------*
+ * PPP control protocol negotiation complete (run ip-up script now)
+ *---------------------------------------------------------------------------*
+ */
+static void
+ibc_negotiation_complete(struct sppp *sp)
+{
+ struct ibc_softc *sc = (struct ibc_softc *)sp;
+
+ i4b_l4_negcomplete(sc->sc_cdp);
+}
+#endif
+
+/*===========================================================================*
+ * ISDN INTERFACE ROUTINES
+ *===========================================================================*/
+
+/*---------------------------------------------------------------------------*
+ * this routine is called from L4 handler at connect time
+ *---------------------------------------------------------------------------*/
+static void
+ibc_connect(int unit, void *cdp)
+{
+ struct ibc_softc *sc = &ibc_softc[unit];
+ struct ifnet *ifp = &sc->sc_p2pcom.p2p_if;
+ int s;
+
+ DBG(("ibc%d: ibc_connect\n", unit));
+
+ s = splimp();
+
+ sc->sc_cdp = (call_desc_t *)cdp;
+ sc->sc_state = ST_CONNECTED;
+
+#if IBCACCT
+ sc->sc_iinb = 0;
+ sc->sc_ioutb = 0;
+ sc->sc_inb = 0;
+ sc->sc_outb = 0;
+ sc->sc_linb = 0;
+ sc->sc_loutb = 0;
+ ifp->if_timer = IBCACCTINTVL;
+#endif
+
+ splx(s);
+ if (sc->sc_p2pcom.p2p_modem)
+ (*sc->sc_p2pcom.p2p_modem)(&sc->sc_p2pcom, 1);
+
+ /* This is a lie... PPP is just starting to negociate :-) */
+ i4b_l4_negcomplete(sc->sc_cdp);
+}
+
+/*---------------------------------------------------------------------------*
+ * this routine is called from L4 handler at disconnect time
+ *---------------------------------------------------------------------------*/
+static void
+ibc_disconnect(int unit, void *cdp)
+{
+ call_desc_t *cd = (call_desc_t *)cdp;
+ struct ibc_softc *sc = &ibc_softc[unit];
+ struct ifnet *ifp = &sc->sc_p2pcom.p2p_if;
+ int s;
+
+ DBG(("ibc%d: ibc_disconnect\n", unit));
+
+ s = splimp();
+
+ /* new stuff to check that the active channel is being closed */
+ if (cd != sc->sc_cdp)
+ {
+ DBG(("ibc_disconnect: ibc%d channel%d not active\n",
+ cd->driver_unit, cd->channelid));
+ splx(s);
+ return;
+ }
+
+#if IBCACCT
+ ifp->if_timer = 0;
+#endif
+
+ i4b_l4_accounting(BDRV_IBC, unit, ACCT_FINAL,
+ sc->sc_ioutb, sc->sc_iinb, 0, 0, sc->sc_outb, sc->sc_inb);
+
+ if (sc->sc_state == ST_CONNECTED)
+ {
+ sc->sc_cdp = (call_desc_t *)0;
+ sc->sc_state = ST_IDLE;
+ if (sc->sc_p2pcom.p2p_modem)
+ (*sc->sc_p2pcom.p2p_modem)(&sc->sc_p2pcom, 0);
+ }
+
+ splx(s);
+}
+
+/*---------------------------------------------------------------------------*
+ * this routine is used to give a feedback from userland demon
+ * in case of dial problems
+ *---------------------------------------------------------------------------*/
+static void
+ibc_dialresponse(int unit, int status)
+{
+ DBG(("ibc%d: ibc_dialresponse %d\n", unit, status));
+/* struct ibc_softc *sc = &ibc_softc[unit]; */
+}
+
+/*---------------------------------------------------------------------------*
+ * interface up/down
+ *---------------------------------------------------------------------------*/
+static void
+ibc_updown(int unit, int updown)
+{
+ DBG(("ibc%d: ibc_updown %d\n", unit, updown));
+ /* could probably do something useful here */
+}
+
+/*---------------------------------------------------------------------------*
+ * this routine is called from the HSCX interrupt handler
+ * when a new frame (mbuf) has been received and was put on
+ * the rx queue.
+ *---------------------------------------------------------------------------*/
+static void
+ibc_rx_data_rdy(int unit)
+{
+ struct ibc_softc *sc = &ibc_softc[unit];
+ struct ifnet *ifp = &sc->sc_p2pcom.p2p_if;
+ struct mbuf *m, *m0;
+ char *buf;
+ int s;
+
+ if((m = *isdn_ibc_lt[unit]->rx_mbuf) == NULL)
+ return;
+
+ microtime(&ifp->if_lastchange);
+ ifp->if_ipackets++;
+
+ /* Walk the mbuf chain */
+ s = splimp();
+ for (m0 = m; m != 0; m = m->m_next) {
+ if (m->m_len == 0)
+ continue;
+ ifp->if_ibytes += m->m_len;
+#if IBCACCT
+ sc->sc_inb += m->m_len;
+#endif
+ buf = mtod(m, caddr_t);
+ if ((*sc->sc_p2pcom.p2p_hdrinput)(
+ &sc->sc_p2pcom, buf, m->m_len) >= 0)
+ (*sc->sc_p2pcom.p2p_input)(&sc->sc_p2pcom, 0);
+ }
+ splx(s);
+ m_freem(m0);
+}
+
+/*---------------------------------------------------------------------------*
+ * this routine is called from the HSCX interrupt handler
+ * when the last frame has been sent out and there is no
+ * further frame (mbuf) in the tx queue.
+ *---------------------------------------------------------------------------*/
+static void
+ibc_tx_queue_empty(int unit)
+{
+ ibc_start(&ibc_softc[unit].sc_p2pcom.p2p_if);
+}
+
+/*---------------------------------------------------------------------------*
+ * this routine is called from the HSCX interrupt handler
+ * each time a packet is received or transmitted. It should
+ * be used to implement an activity timeout mechanism.
+ *---------------------------------------------------------------------------*/
+static void
+ibc_activity(int unit, int rxtx)
+{
+ ibc_softc[unit].sc_cdp->last_active_time = SECOND;
+}
+
+/*---------------------------------------------------------------------------*
+ * return this drivers linktab address
+ *---------------------------------------------------------------------------*/
+drvr_link_t *
+ibc_ret_linktab(int unit)
+{
+ return(&ibc_drvr_linktab[unit]);
+}
+
+/*---------------------------------------------------------------------------*
+ * setup the isdn_ibc_lt for this driver
+ *---------------------------------------------------------------------------*/
+void
+ibc_set_linktab(int unit, isdn_link_t *ilt)
+{
+ isdn_ibc_lt[unit] = ilt;
+}
+
+/*---------------------------------------------------------------------------*
+ * initialize this drivers linktab
+ *---------------------------------------------------------------------------*/
+static void
+ibc_init_linktab(int unit)
+{
+ ibc_drvr_linktab[unit].unit = unit;
+ ibc_drvr_linktab[unit].bch_rx_data_ready = ibc_rx_data_rdy;
+ ibc_drvr_linktab[unit].bch_tx_queue_empty = ibc_tx_queue_empty;
+ ibc_drvr_linktab[unit].bch_activity = ibc_activity;
+ ibc_drvr_linktab[unit].line_connected = ibc_connect;
+ ibc_drvr_linktab[unit].line_disconnected = ibc_disconnect;
+ ibc_drvr_linktab[unit].dial_response = ibc_dialresponse;
+ ibc_drvr_linktab[unit].updown_ind = ibc_updown;
+}
+
+/*===========================================================================*/
+
+static int
+ibc_mdmctl(pp, flag)
+ struct p2pcom *pp;
+ int flag;
+{
+ register struct ifnet *ifp = &pp->p2p_if;
+ struct ibc_softc *sc = (struct ibc_softc *)&ibc_softc[ifp->if_unit];
+
+ DBG(("ibc%d: ibc_mdmctl called flags=%d\n", IFP2UNIT(ifp), flag));
+
+ if (flag == 1 && sc->sc_state == ST_IDLE) {
+ sc->sc_state = ST_DIALING;
+ i4b_l4_dialout(BDRV_IBC, IFP2UNIT(ifp));
+ } else if (flag == 0 && sc->sc_state != ST_IDLE) {
+ sc->sc_state = ST_IDLE;
+ i4b_l4_drvrdisc(BDRV_IBC, IFP2UNIT(ifp));
+ }
+ return 0;
+}
+
+static int
+ibc_getmdm(pp, arg)
+ struct p2pcom *pp;
+ caddr_t arg;
+{
+ register struct ifnet *ifp = &pp->p2p_if;
+ struct ibc_softc *sc = (struct ibc_softc *)&ibc_softc[ifp->if_unit];
+
+ if (sc->sc_state == ST_CONNECTED)
+ *(int *)arg = TIOCM_CAR;
+ else
+ *(int *)arg = 0;
+ return 0;
+
+ DBG(("ibc%d: ibc_getmdm called ret=%d\n", IFP2UNIT(ifp), *(int *)arg));
+}
+#endif
diff --git a/sys/i4b/layer1/i4b_asuscom_ipac.c b/sys/i4b/layer1/i4b_asuscom_ipac.c
new file mode 100644
index 000000000000..59f4211d7dd1
--- /dev/null
+++ b/sys/i4b/layer1/i4b_asuscom_ipac.c
@@ -0,0 +1,510 @@
+/*
+ * Copyright (c) 1999 Ari Suutari. All rights reserved.
+ * Copyright (c) 1997, 1999 Hellmuth Michaelis. 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * isic - I4B Siemens ISDN Chipset Driver for Asuscom ISDNlink 128K PnP
+ * =====================================================================
+ *
+ * This driver works with Asuscom ISDNlink 128K PnP ISA adapter,
+ * which is based on Siemens IPAC chip (my card probes as ASU1690).
+ * Older Asuscom ISA cards are based on different chipset
+ * (containing two chips) - for those cards, one might want
+ * to try the Dynalink driver.
+ *
+ * This driver is heavily based on ELSA Quickstep 1000pro PCI
+ * driver written by Hellmuth Michaelis. Card initialization
+ * code is modeled after Linux i4l driver written by Karsten
+ * Keil.
+ *
+ * $FreeBSD$
+ *
+ * last edit-date: [Mon May 31 20:53:17 EEST 1999]
+ *
+ *---------------------------------------------------------------------------*/
+
+#if defined(__FreeBSD__)
+#include "isic.h"
+#include "opt_i4b.h"
+#include "pnp.h"
+#else
+#define NISIC 1
+#define NPNP 1
+#endif
+
+#if (NISIC > 0) && (NPNP > 0) && defined(ASUSCOM_IPAC)
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#ifdef __FreeBSD__
+#if __FreeBSD__ >= 3
+#include <sys/ioccom.h>
+#else
+#include <sys/ioctl.h>
+#endif
+#include <machine/clock.h>
+#include <i386/isa/isa_device.h>
+#include <i386/isa/pnp.h>
+#else
+#include <machine/bus.h>
+#include <sys/device.h>
+#endif
+
+#ifdef __FreeBSD__
+#include <machine/i4b_debug.h>
+#include <machine/i4b_ioctl.h>
+#else
+#include <i4b/i4b_debug.h>
+#include <i4b/i4b_ioctl.h>
+#endif
+
+#include <i4b/include/i4b_global.h>
+#include <i4b/include/i4b_l1l2.h>
+#include <i4b/include/i4b_mbuf.h>
+
+#include <i4b/layer1/i4b_l1.h>
+#include <i4b/layer1/i4b_isac.h>
+#include <i4b/layer1/i4b_hscx.h>
+#include <i4b/layer1/i4b_ipac.h>
+
+#ifndef __FreeBSD__
+#include <i4b/layer1/pci_isic.h>
+#endif
+
+/* masks for register encoded in base addr */
+
+#define ASI_BASE_MASK 0x0ffff
+#define ASI_OFF_MASK 0xf0000
+
+/* register id's to be encoded in base addr */
+
+#define ASI_IDISAC 0x00000
+#define ASI_IDHSCXA 0x10000
+#define ASI_IDHSCXB 0x20000
+#define ASI_IDIPAC 0x40000
+
+/* offsets from base address */
+
+#define ASI_OFF_ALE 0x00
+#define ASI_OFF_RW 0x01
+
+/*---------------------------------------------------------------------------*
+ * Asuscom ISDNlink 128K PnP ISAC get fifo routine
+ *---------------------------------------------------------------------------*/
+#ifdef __FreeBSD__
+
+static void
+asi_read_fifo(void *buf, const void *base, size_t len)
+{
+ u_int asus_base;
+
+ asus_base = ((u_int) base) & ASI_BASE_MASK;
+ switch (((u_int) base) & ASI_OFF_MASK) {
+ case ASI_IDHSCXB:
+ outb(asus_base + ASI_OFF_ALE, IPAC_HSCXB_OFF);
+ insb(asus_base + ASI_OFF_RW, (u_char *)buf, (u_int)len);
+ break;
+ case ASI_IDHSCXA:
+ outb(asus_base + ASI_OFF_ALE, IPAC_HSCXA_OFF);
+ insb(asus_base + ASI_OFF_RW, (u_char *)buf, (u_int)len);
+ break;
+ case ASI_IDISAC:
+ outb(asus_base + ASI_OFF_ALE, IPAC_ISAC_OFF);
+ insb(asus_base + ASI_OFF_RW, (u_char *)buf, (u_int)len);
+ break;
+ }
+}
+
+#else
+
+static void
+asi_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size)
+{
+ bus_space_tag_t t = sc->sc_maps[1].t;
+ bus_space_handle_t h = sc->sc_maps[1].h;
+ switch (what) {
+ case ISIC_WHAT_ISAC:
+ bus_space_write_1(t, h, ASI_OFF_ALE, IPAC_ISAC_OFF);
+ bus_space_read_multi_1(t, h, ASI_OFF_RW, buf, size);
+ break;
+ case ISIC_WHAT_HSCXA:
+ bus_space_write_1(t, h, ASI_OFF_ALE, IPAC_HSCXA_OFF);
+ bus_space_read_multi_1(t, h, ASI_OFF_RW, buf, size);
+ break;
+ case ISIC_WHAT_HSCXB:
+ bus_space_write_1(t, h, ASI_OFF_ALE, IPAC_HSCXB_OFF);
+ bus_space_read_multi_1(t, h, ASI_OFF_RW, buf, size);
+ break;
+ }
+}
+
+#endif
+
+/*---------------------------------------------------------------------------*
+ * Asuscom ISDNlink 128K PnP ISAC put fifo routine
+ *---------------------------------------------------------------------------*/
+#ifdef __FreeBSD__
+
+static void
+asi_write_fifo(void *base, const void *buf, size_t len)
+{
+ u_int asus_base;
+
+ asus_base = ((u_int) base) & ASI_BASE_MASK;
+ switch (((u_int) base) & ASI_OFF_MASK) {
+ case ASI_IDHSCXB:
+ outb(asus_base + ASI_OFF_ALE, IPAC_HSCXB_OFF);
+ outsb(asus_base + ASI_OFF_RW, (u_char *)buf, (u_int)len);
+ break;
+ case ASI_IDHSCXA:
+ outb(asus_base + ASI_OFF_ALE, IPAC_HSCXA_OFF);
+ outsb(asus_base + ASI_OFF_RW, (u_char *)buf, (u_int)len);
+ break;
+ case ASI_IDISAC:
+ outb(asus_base + ASI_OFF_ALE, IPAC_ISAC_OFF);
+ outsb(asus_base + ASI_OFF_RW, (u_char *)buf, (u_int)len);
+ break;
+ }
+}
+
+#else
+
+static void
+asi_write_fifo(struct isic_softc *sc,
+ int what, const void *buf, size_t size)
+{
+ bus_space_tag_t t = sc->sc_maps[1].t;
+ bus_space_handle_t h = sc->sc_maps[1].h;
+ switch (what) {
+ case ISIC_WHAT_ISAC:
+ bus_space_write_1(t, h, ASI_OFF_ALE, IPAC_ISAC_OFF);
+ bus_space_write_multi_1(t, h, ASI_OFF_RW, (u_int8_t*)buf,size);
+ break;
+ case ISIC_WHAT_HSCXA:
+ bus_space_write_1(t, h, ASI_OFF_ALE, IPAC_HSCXA_OFF);
+ bus_space_write_multi_1(t, h, ASI_OFF_RW, (u_int8_t*)buf,size);
+ break;
+ case ISIC_WHAT_HSCXB:
+ bus_space_write_1(t, h, ASI_OFF_ALE, IPAC_HSCXB_OFF);
+ bus_space_write_multi_1(t, h, ASI_OFF_RW, (u_int8_t*)buf,size);
+ break;
+ }
+}
+#endif
+
+/*---------------------------------------------------------------------------*
+ * Asuscom ISDNlink 128K PnP ISAC put register routine
+ *---------------------------------------------------------------------------*/
+#ifdef __FreeBSD__
+
+static void
+asi_write_reg(u_char *base, u_int offset, u_int v)
+{
+ u_int asus_base;
+
+ asus_base = ((u_int) base) & ASI_BASE_MASK;
+ switch (((u_int) base) & ASI_OFF_MASK) {
+ case ASI_IDHSCXB:
+ outb(asus_base + ASI_OFF_ALE, (u_char)(offset+IPAC_HSCXB_OFF));
+ outb(asus_base + ASI_OFF_RW, (u_char)v);
+ break;
+ case ASI_IDHSCXA:
+ outb(asus_base + ASI_OFF_ALE, (u_char)(offset+IPAC_HSCXA_OFF));
+ outb(asus_base + ASI_OFF_RW, (u_char)v);
+ break;
+ case ASI_IDISAC:
+ outb(asus_base + ASI_OFF_ALE, (u_char)(offset+IPAC_ISAC_OFF));
+ outb(asus_base + ASI_OFF_RW, (u_char)v);
+ break;
+ case ASI_IDIPAC:
+ outb(asus_base + ASI_OFF_ALE, (u_char)(offset+IPAC_IPAC_OFF));
+ outb(asus_base + ASI_OFF_RW, (u_char)v);
+ break;
+ }
+}
+
+#else
+
+static void
+asi_write_reg(struct isic_softc *sc,
+ int what, bus_size_t offs, u_int8_t data)
+{
+ bus_space_tag_t t = sc->sc_maps[1].t;
+ bus_space_handle_t h = sc->sc_maps[1].h;
+ switch (what) {
+ case ISIC_WHAT_ISAC:
+ bus_space_write_1(t, h, ASI_OFF_ALE, IPAC_ISAC_OFF+offs);
+ bus_space_write_1(t, h, ASI_OFF_RW, data);
+ break;
+ case ISIC_WHAT_HSCXA:
+ bus_space_write_1(t, h, ASI_OFF_ALE, IPAC_HSCXA_OFF+offs);
+ bus_space_write_1(t, h, ASI_OFF_RW, data);
+ break;
+ case ISIC_WHAT_HSCXB:
+ bus_space_write_1(t, h, ASI_OFF_ALE, IPAC_HSCXB_OFF+offs);
+ bus_space_write_1(t, h, ASI_OFF_RW, data);
+ break;
+ case ISIC_WHAT_IPAC:
+ bus_space_write_1(t, h, ASI_OFF_ALE, IPAC_IPAC_OFF+offs);
+ bus_space_write_1(t, h, ASI_OFF_RW, data);
+ break;
+ }
+}
+#endif
+
+/*---------------------------------------------------------------------------*
+ * Asuscom ISDNlink 128K PnP ISAC get register routine
+ *---------------------------------------------------------------------------*/
+#ifdef __FreeBSD__
+
+static u_char
+asi_read_reg(u_char *base, u_int offset)
+{
+ u_int asus_base;
+
+ asus_base = ((u_int) base) & ASI_BASE_MASK;
+ switch (((u_int) base) & ASI_OFF_MASK) {
+ case ASI_IDHSCXB:
+ outb(asus_base + ASI_OFF_ALE, (u_char)(offset+IPAC_HSCXB_OFF));
+ return(inb(asus_base + ASI_OFF_RW));
+ case ASI_IDHSCXA:
+ outb(asus_base + ASI_OFF_ALE, (u_char)(offset+IPAC_HSCXA_OFF));
+ return(inb(asus_base + ASI_OFF_RW));
+ case ASI_IDISAC:
+ outb(asus_base + ASI_OFF_ALE, (u_char)(offset+IPAC_ISAC_OFF));
+ return(inb(asus_base + ASI_OFF_RW));
+ case ASI_IDIPAC:
+ outb(asus_base + ASI_OFF_ALE, (u_char)(offset+IPAC_IPAC_OFF));
+ return(inb(asus_base + ASI_OFF_RW));
+ }
+
+ return 0; /* NOTREACHED */
+}
+
+#else
+
+static u_int8_t
+asi_read_reg(struct isic_softc *sc, int what, bus_size_t offs)
+{
+ bus_space_tag_t t = sc->sc_maps[1].t;
+ bus_space_handle_t h = sc->sc_maps[1].h;
+ switch (what) {
+ case ISIC_WHAT_ISAC:
+ bus_space_write_1(t, h, ASI_OFF_ALE, IPAC_ISAC_OFF+offs);
+ return bus_space_read_1(t, h, ASI_OFF_RW);
+ case ISIC_WHAT_HSCXA:
+ bus_space_write_1(t, h, ASI_OFF_ALE, IPAC_HSCXA_OFF+offs);
+ return bus_space_read_1(t, h, ASI_OFF_RW);
+ case ISIC_WHAT_HSCXB:
+ bus_space_write_1(t, h, ASI_OFF_ALE, IPAC_HSCXB_OFF+offs);
+ return bus_space_read_1(t, h, ASI_OFF_RW);
+ case ISIC_WHAT_IPAC:
+ bus_space_write_1(t, h, ASI_OFF_ALE, IPAC_IPAC_OFF+offs);
+ return bus_space_read_1(t, h, ASI_OFF_RW);
+ }
+
+ return 0;
+}
+
+#endif
+
+/*---------------------------------------------------------------------------*
+ * isic_attach_asi - attach for Asuscom ISDNlink 128K PnP
+ *---------------------------------------------------------------------------*/
+#ifdef __FreeBSD__
+int
+isic_probe_asi(struct isa_device *dev, unsigned int iobase2)
+{
+ struct isic_softc *sc = &isic_sc[dev->id_unit];
+
+ /* check max unit range */
+
+ if(dev->id_unit >= ISIC_MAXUNIT)
+ {
+ printf("isic%d: Error, unit %d >= ISIC_MAXUNIT "
+ "for Asuscom ISDNlink 128K PnP!\n",
+ dev->id_unit, dev->id_unit);
+
+ return(0);
+ }
+ sc->sc_unit = dev->id_unit;
+
+ /* setup iobase */
+
+ if((dev->id_iobase <= 0) || (dev->id_iobase > 0xffff))
+ {
+ printf("isic%d: Error, invalid iobase 0x%x specified "
+ "for Asuscom ISDNlink 128K PnP\n",
+ dev->id_unit, iobase2);
+
+ return(0);
+ }
+
+ sc->sc_port = dev->id_iobase;
+
+ /* setup access routines */
+
+ sc->clearirq = NULL;
+ sc->readreg = asi_read_reg;
+ sc->writereg = asi_write_reg;
+
+ sc->readfifo = asi_read_fifo;
+ sc->writefifo = asi_write_fifo;
+
+ /* setup card type */
+
+ sc->sc_cardtyp = CARD_TYPEP_ASUSCOMIPAC;
+
+ /* setup IOM bus type */
+
+ sc->sc_bustyp = BUS_TYPE_IOM2;
+
+ /* setup chip type = IPAC ! */
+
+ sc->sc_ipac = 1;
+ sc->sc_bfifolen = IPAC_BFIFO_LEN;
+
+ /* setup ISAC and HSCX base addr */
+
+ ISAC_BASE = (caddr_t) ((u_int)dev->id_iobase | ASI_IDISAC);
+ HSCX_A_BASE = (caddr_t) ((u_int)dev->id_iobase | ASI_IDHSCXA);
+ HSCX_B_BASE = (caddr_t) ((u_int)dev->id_iobase | ASI_IDHSCXB);
+ IPAC_BASE = (caddr_t) ((u_int)dev->id_iobase | ASI_IDIPAC);
+
+ return (1);
+}
+
+int
+isic_attach_asi(struct isa_device *dev, unsigned int iobase2)
+{
+ struct isic_softc *sc = &isic_sc[dev->id_unit];
+ /* enable hscx/isac irq's */
+#if 0
+/*
+ * This is for ELSA driver
+ */
+ IPAC_WRITE(IPAC_MASK, (IPAC_MASK_INT1 | IPAC_MASK_INT0));
+
+ IPAC_WRITE(IPAC_ACFG, 0); /* outputs are open drain */
+ IPAC_WRITE(IPAC_AOE, /* aux 5..2 are inputs, 7, 6 outputs */
+ (IPAC_AOE_OE5 | IPAC_AOE_OE4 | IPAC_AOE_OE3 | IPAC_AOE_OE2));
+ IPAC_WRITE(IPAC_ATX, 0xff); /* set all output lines high */
+
+ outb(dev->id_iobase + 0x4c, 0x41); /* enable card interrupt */
+#endif
+/*
+ * This has been taken from Linux driver.
+ * XXX Figure out bits to use defines as original driver did.
+ */
+ IPAC_WRITE (IPAC_CONF, 0x0);
+ IPAC_WRITE (IPAC_ACFG, 0xff);
+ IPAC_WRITE (IPAC_AOE, 0x0);
+ IPAC_WRITE (IPAC_MASK, 0xc0);
+ IPAC_WRITE (IPAC_PCFG, 0x12);
+
+ return (1);
+}
+
+#else /* !FreeBSD */
+
+void
+isic_attach_asi(psc, pa)
+ struct pci_isic_softc *psc;
+ struct pci_attach_args *pa;
+{
+ struct isic_softc *sc = &psc->sc_isic;
+
+ /* setup io mappings */
+ sc->sc_num_mappings = 2;
+ MALLOC_MAPS(sc);
+ sc->sc_maps[0].size = 0;
+ if (pci_mapreg_map(pa, ASI_PORT0_MAPOFF, PCI_MAPREG_TYPE_IO, 0,
+ &sc->sc_maps[0].t, &sc->sc_maps[0].h, NULL, NULL)) {
+ printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname);
+ return;
+ }
+ sc->sc_maps[1].size = 0;
+ if (pci_mapreg_map(pa, ASI_PORT1_MAPOFF, PCI_MAPREG_TYPE_IO, 0,
+ &sc->sc_maps[1].t, &sc->sc_maps[1].h, NULL, NULL)) {
+ printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname);
+ return;
+ }
+
+ /* setup access routines */
+
+ sc->clearirq = NULL;
+ sc->readreg = asi_read_reg;
+ sc->writereg = asi_write_reg;
+
+ sc->readfifo = asi_read_fifo;
+ sc->writefifo = asi_write_fifo;
+
+ /* setup card type */
+
+ sc->sc_cardtyp = CARD_TYPEP_ASUSCOMIPAC;
+
+ /* setup IOM bus type */
+
+ sc->sc_bustyp = BUS_TYPE_IOM2;
+
+ /* setup chip type = IPAC ! */
+
+ sc->sc_ipac = 1;
+ sc->sc_bfifolen = IPAC_BFIFO_LEN;
+
+#if 0
+/*
+ * This for ELSA card in original driver.
+ */
+ /* enable hscx/isac irq's */
+ IPAC_WRITE(IPAC_MASK, (IPAC_MASK_INT1 | IPAC_MASK_INT0));
+
+ IPAC_WRITE(IPAC_ACFG, 0); /* outputs are open drain */
+ IPAC_WRITE(IPAC_AOE, /* aux 5..2 are inputs, 7, 6 outputs */
+ (IPAC_AOE_OE5 | IPAC_AOE_OE4 | IPAC_AOE_OE3 | IPAC_AOE_OE2));
+ IPAC_WRITE(IPAC_ATX, 0xff); /* set all output lines high */
+
+ bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, 0x4c, 0x41); /* enable card interrupt */
+#endif
+/*
+ * This has been taken from Linux driver.
+ * XXX Figure out bits to use defines as original driver did.
+ */
+ IPAC_WRITE (IPAC_CONF, 0x0);
+ IPAC_WRITE (IPAC_ACFG, 0xff);
+ IPAC_WRITE (IPAC_AOE, 0x0);
+ IPAC_WRITE (IPAC_MASK, 0xc0);
+ IPAC_WRITE (IPAC_PCFG, 0x12);
+}
+
+
+#endif
+
+#endif /* (NISIC > 0) && defined(ASUSCOM_IPAC) */
diff --git a/sys/i4b/layer1/i4b_avm_fritz_pci.c b/sys/i4b/layer1/i4b_avm_fritz_pci.c
new file mode 100644
index 000000000000..0b41c7bea129
--- /dev/null
+++ b/sys/i4b/layer1/i4b_avm_fritz_pci.c
@@ -0,0 +1,1732 @@
+/*
+ * Copyright (c) 1999 Gary Jennejohn. 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. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 4. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software and/or documentation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ * a lot of code was borrowed from i4b_bchan.c and i4b_hscx.c
+ *---------------------------------------------------------------------------
+ *
+ * Fritz!Card PCI specific routines for isic driver
+ * ------------------------------------------------
+ *
+ * $FreeBSD$
+ *
+ * last edit-date: [Tue Jun 1 14:08:01 1999]
+ *
+ *---------------------------------------------------------------------------*/
+
+#if defined(__FreeBSD__)
+#include "isic.h"
+#include "opt_i4b.h"
+#else
+#define NISIC 1
+#endif
+
+#if NISIC > 0 && defined(AVM_A1_PCI)
+
+#include <sys/param.h>
+#if defined(__FreeBSD__) && __FreeBSD__ >= 3
+#include <sys/ioccom.h>
+#else
+#include <sys/ioctl.h>
+#endif
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+
+#ifdef __FreeBSD__
+#include <machine/clock.h>
+#include <i386/isa/isa_device.h>
+#include <pci/pcivar.h> /* for pcici_t */
+#if __FreeBSD__ < 3
+#include <pci/pcireg.h>
+#include <pci/pcibus.h>
+#endif /* __FreeBSD__ < 3 */
+#else
+#include <machine/bus.h>
+#include <sys/device.h>
+#endif
+
+#include <sys/socket.h>
+#include <net/if.h>
+
+#ifdef __FreeBSD__
+#include <machine/i4b_debug.h>
+#include <machine/i4b_ioctl.h>
+#else
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+#include <i4b/i4b_debug.h>
+#include <i4b/i4b_ioctl.h>
+#endif
+
+#include <i4b/include/i4b_global.h>
+#include <i4b/include/i4b_l1l2.h>
+#include <i4b/include/i4b_mbuf.h>
+
+#include <i4b/layer1/i4b_l1.h>
+#include <i4b/layer1/i4b_isac.h>
+#include <i4b/layer1/i4b_hscx.h>
+
+#ifndef __FreeBSD__
+
+#include <i4b/layer1/pci_isic.h>
+
+/* PCI config map to use (only one in this driver) */
+#define FRITZPCI_PORT0_MAPOFF PCI_MAPREG_START+4
+
+#endif
+
+/* prototypes */
+static void avma1pp_disable(struct isic_softc *);
+
+#ifdef __FreeBSD__
+
+static void avma1pp_intr(struct isic_softc *);
+static void avma1pp_disable(struct isic_softc *);
+void avma1pp_map_int(pcici_t , void *, unsigned *);
+static void hscx_write_reg(int, u_int, u_int, struct isic_softc *);
+static u_char hscx_read_reg(int, u_int, struct isic_softc *);
+static u_int hscx_read_reg_int(int, u_int, struct isic_softc *);
+static void hscx_read_fifo(int, void *, size_t, struct isic_softc *);
+static void hscx_write_fifo(int, const void *, size_t, struct isic_softc *);
+static void avma1pp_hscx_int_handler(struct isic_softc *);
+static void avma1pp_hscx_intr(int, u_int, struct isic_softc *);
+static void avma1pp_init_linktab(struct isic_softc *);
+static void avma1pp_bchannel_setup(int, int, int, int);
+static void avma1pp_bchannel_start(int, int);
+static void avma1pp_hscx_init(struct isic_softc *, int, int);
+static void avma1pp_bchannel_stat(int, int, bchan_statistics_t *);
+static void avma1pp_set_linktab(int, int, drvr_link_t *);
+static isdn_link_t * avma1pp_ret_linktab(int, int);
+int isic_attach_avma1pp(int, u_int, u_int);
+extern void isicintr_sc(struct isic_softc *);
+
+#else
+
+static int avma1pp_intr(void*);
+static void avma1pp_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size);
+static void avma1pp_write_fifo(struct isic_softc *sc, int what, const void *buf, size_t size);
+static void avma1pp_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data);
+static u_int8_t avma1pp_read_reg(struct isic_softc *sc, int what, bus_size_t offs);
+static void hscx_write_fifo(int chan, const void *buf, size_t len, struct isic_softc *sc);
+static void hscx_read_fifo(int chan, void *buf, size_t len, struct isic_softc *sc);
+static void hscx_write_reg(int chan, u_int off, u_int val, struct isic_softc *sc);
+static u_char hscx_read_reg(int chan, u_int off, struct isic_softc *sc);
+static u_int hscx_read_reg_int(int chan, u_int off, struct isic_softc *sc);
+static void avma1pp_fifo(isic_Bchan_t *chan, struct isic_softc *sc);
+static void avma1pp_bchannel_stat(int unit, int h_chan, bchan_statistics_t *bsp);
+static void avma1pp_map_int(struct pci_isic_softc *sc, struct pci_attach_args *pa);
+static void avma1pp_bchannel_setup(int unit, int h_chan, int bprot, int activate);
+static void avma1pp_init_linktab(struct isic_softc *);
+#endif
+
+/*---------------------------------------------------------------------------*
+ * AVM PCI Fritz!Card special registers
+ *---------------------------------------------------------------------------*/
+
+/*
+ * register offsets from i/o base
+ */
+#define STAT0_OFFSET 0x02
+#define STAT1_OFFSET 0x03
+#define ADDR_REG_OFFSET 0x04
+/*#define MODREG_OFFSET 0x06
+#define VERREG_OFFSET 0x07*/
+
+/* these 2 are used to select an ISAC register set */
+#define ISAC_LO_REG_OFFSET 0x04
+#define ISAC_HI_REG_OFFSET 0x06
+
+/* offset higher than this goes to the HI register set */
+#define MAX_LO_REG_OFFSET 0x2f
+
+/* mask for the offset */
+#define ISAC_REGSET_MASK 0x0f
+
+/* the offset from the base to the ISAC registers */
+#define ISAC_REG_OFFSET 0x10
+
+/* the offset from the base to the ISAC FIFO */
+#define ISAC_FIFO 0x02
+
+/* not really the HSCX, but sort of */
+#define HSCX_FIFO 0x00
+#define HSCX_STAT 0x04
+
+/*
+ * AVM PCI Status Latch 0 read only bits
+ */
+#define ASL_IRQ_ISAC 0x01 /* ISAC interrupt, active low */
+#define ASL_IRQ_HSCX 0x02 /* HSX interrupt, active low */
+#define ASL_IRQ_TIMER 0x04 /* Timer interrupt, active low */
+#define ASL_IRQ_BCHAN ASL_IRQ_HSCX
+/* actually active LOW */
+#define ASL_IRQ_Pending (ASL_IRQ_ISAC | ASL_IRQ_HSCX | ASL_IRQ_TIMER)
+
+/*
+ * AVM Status Latch 0 write only bits
+ */
+#define ASL_RESET_ALL 0x01 /* reset siemens IC's, active 1 */
+#define ASL_TIMERDISABLE 0x02 /* active high */
+#define ASL_TIMERRESET 0x04 /* active high */
+#define ASL_ENABLE_INT 0x08 /* active high */
+#define ASL_TESTBIT 0x10 /* active high */
+
+/*
+ * AVM Status Latch 1 write only bits
+ */
+#define ASL1_INTSEL 0x0f /* active high */
+#define ASL1_ENABLE_IOM 0x80 /* active high */
+
+/*
+ * "HSCX" mode bits
+ */
+#define HSCX_MODE_ITF_FLG 0x01
+#define HSCX_MODE_TRANS 0x02
+#define HSCX_MODE_CCR_7 0x04
+#define HSCX_MODE_CCR_16 0x08
+#define HSCX_MODE_TESTLOOP 0x80
+
+/*
+ * "HSCX" status bits
+ */
+#define HSCX_STAT_RME 0x01
+#define HSCX_STAT_RDO 0x10
+#define HSCX_STAT_CRCVFRRAB 0x0E
+#define HSCX_STAT_CRCVFR 0x06
+#define HSCX_STAT_RML_MASK 0x3f00
+
+/*
+ * "HSCX" interrupt bits
+ */
+#define HSCX_INT_XPR 0x80
+#define HSCX_INT_XDU 0x40
+#define HSCX_INT_RPR 0x20
+#define HSCX_INT_MASK 0xE0
+
+/*
+ * "HSCX" command bits
+ */
+#define HSCX_CMD_XRS 0x80
+#define HSCX_CMD_XME 0x01
+#define HSCX_CMD_RRS 0x20
+#define HSCX_CMD_XML_MASK 0x3f00
+
+/*
+ * Commands and parameters are sent to the "HSCX" as a long, but the
+ * fields are handled as bytes.
+ *
+ * The long contains:
+ * (prot << 16)|(txl << 8)|cmd
+ *
+ * where:
+ * prot = protocol to use
+ * txl = transmit length
+ * cmd = the command to be executed
+ *
+ * The fields are defined as u_char in struct isic_softc.
+ *
+ * Macro to coalesce the byte fields into a u_int
+ */
+#define AVMA1PPSETCMDLONG(f) (f) = ((sc->avma1pp_cmd) | (sc->avma1pp_txl << 8) \
+ | (sc->avma1pp_prot << 16))
+
+#ifdef __FreeBSD__
+
+/* "fake" addresses for the non-existent HSCX */
+/* note: the unit number is in the lower byte for both the ISAC and "HSCX" */
+#define HSCX0FAKE 0xfa000 /* read: fake0 */
+#define HSCX1FAKE 0xfa100 /* read: fake1 */
+#define IS_HSCX_MASK 0xfff00
+
+#endif /* __FreeBSD__ */
+
+/*
+ * to prevent deactivating the "HSCX" when both channels are active we
+ * define an HSCX_ACTIVE flag which is or'd into the channel's state
+ * flag in avma1pp_bchannel_setup upon active and cleared upon deactivation.
+ * It is set high to allow room for new flags.
+ */
+#define HSCX_AVMA1PP_ACTIVE 0x1000
+
+/*---------------------------------------------------------------------------*
+ * AVM read fifo routines
+ *---------------------------------------------------------------------------*/
+
+#ifdef __FreeBSD__
+static void
+avma1pp_read_fifo(void *buf, const void *base, size_t len)
+{
+ int unit;
+ struct isic_softc *sc;
+
+ unit = (int)base & 0xff;
+ sc = &isic_sc[unit];
+
+ /* check whether the target is an HSCX */
+ if (((int)base & IS_HSCX_MASK) == HSCX0FAKE)
+ {
+ hscx_read_fifo(0, buf, len, sc);
+ return;
+ }
+ if (((int)base & IS_HSCX_MASK) == HSCX1FAKE)
+ {
+ hscx_read_fifo(1, buf, len, sc);
+ return;
+ }
+ /* tell the board to access the ISAC fifo */
+ outb(sc->sc_port + ADDR_REG_OFFSET, ISAC_FIFO);
+ insb(sc->sc_port + ISAC_REG_OFFSET, (u_char *)buf, len);
+}
+
+static void
+hscx_read_fifo(int chan, void *buf, size_t len, struct isic_softc *sc)
+{
+ u_int *ip;
+ size_t cnt;
+
+ outl(sc->sc_port + ADDR_REG_OFFSET, chan);
+ ip = (u_int *)buf;
+ cnt = 0;
+ /* what if len isn't a multiple of sizeof(int) and buf is */
+ /* too small ???? */
+ while (cnt < len)
+ {
+ *ip++ = inl(sc->sc_port + ISAC_REG_OFFSET);
+ cnt += 4;
+ }
+}
+
+#else
+
+static void
+avma1pp_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size)
+{
+ switch (what) {
+ case ISIC_WHAT_ISAC:
+ bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, ADDR_REG_OFFSET, ISAC_FIFO);
+ bus_space_read_multi_1(sc->sc_maps[0].t, sc->sc_maps[0].h, ISAC_REG_OFFSET, buf, size);
+ break;
+ case ISIC_WHAT_HSCXA:
+ hscx_read_fifo(0, buf, size, sc);
+ break;
+ case ISIC_WHAT_HSCXB:
+ hscx_read_fifo(1, buf, size, sc);
+ break;
+ }
+}
+
+static void
+hscx_read_fifo(int chan, void *buf, size_t len, struct isic_softc *sc)
+{
+ u_int32_t *ip;
+ size_t cnt;
+
+ bus_space_write_4(sc->sc_maps[0].t, sc->sc_maps[0].h, ADDR_REG_OFFSET, chan);
+ ip = (u_int32_t *)buf;
+ cnt = 0;
+ /* what if len isn't a multiple of sizeof(int) and buf is */
+ /* too small ???? */
+ while (cnt < len)
+ {
+ *ip++ = bus_space_read_4(sc->sc_maps[0].t, sc->sc_maps[0].h, ISAC_REG_OFFSET);
+ cnt += 4;
+ }
+}
+
+#endif
+
+/*---------------------------------------------------------------------------*
+ * AVM write fifo routines
+ *---------------------------------------------------------------------------*/
+#ifdef __FreeBSD__
+static void
+avma1pp_write_fifo(void *base, const void *buf, size_t len)
+{
+ int unit;
+ struct isic_softc *sc;
+
+ unit = (int)base & 0xff;
+ sc = &isic_sc[unit];
+
+ /* check whether the target is an HSCX */
+ if (((int)base & IS_HSCX_MASK) == HSCX0FAKE)
+ {
+ hscx_write_fifo(0, buf, len, sc);
+ return;
+ }
+ if (((int)base & IS_HSCX_MASK) == HSCX1FAKE)
+ {
+ hscx_write_fifo(1, buf, len, sc);
+ return;
+ }
+ /* tell the board to use the ISAC fifo */
+ outb(sc->sc_port + ADDR_REG_OFFSET, ISAC_FIFO);
+ outsb(sc->sc_port + ISAC_REG_OFFSET, (const u_char *)buf, len);
+}
+
+static void
+hscx_write_fifo(int chan, const void *buf, size_t len, struct isic_softc *sc)
+{
+ register const u_int *ip;
+ register size_t cnt;
+ isic_Bchan_t *Bchan = &sc->sc_chan[chan];
+
+ sc->avma1pp_cmd &= ~HSCX_CMD_XME;
+ sc->avma1pp_txl = 0;
+ if (Bchan->out_mbuf_cur == NULL)
+ {
+ if (Bchan->bprot != BPROT_NONE)
+ sc->avma1pp_cmd |= HSCX_CMD_XME;
+ }
+ if (len != sc->sc_bfifolen)
+ sc->avma1pp_txl = len;
+
+ cnt = 0; /* borrow cnt */
+ AVMA1PPSETCMDLONG(cnt);
+ hscx_write_reg(chan, HSCX_STAT, cnt, sc);
+
+ ip = (const u_int *)buf;
+ cnt = 0;
+ while (cnt < len)
+ {
+ outl(sc->sc_port + ISAC_REG_OFFSET, *ip++);
+ cnt += 4;
+ }
+}
+
+#else
+
+static void
+avma1pp_write_fifo(struct isic_softc *sc, int what, const void *buf, size_t size)
+{
+ switch (what) {
+ case ISIC_WHAT_ISAC:
+ bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, ADDR_REG_OFFSET, ISAC_FIFO);
+ bus_space_write_multi_1(sc->sc_maps[0].t, sc->sc_maps[0].h, ISAC_REG_OFFSET, (u_int8_t*)buf, size);
+ break;
+ case ISIC_WHAT_HSCXA:
+ hscx_write_fifo(0, buf, size, sc);
+ break;
+ case ISIC_WHAT_HSCXB:
+ hscx_write_fifo(1, buf, size, sc);
+ break;
+ }
+}
+
+static void
+hscx_write_fifo(int chan, const void *buf, size_t len, struct isic_softc *sc)
+{
+ u_int32_t *ip;
+ size_t cnt;
+ isic_Bchan_t *Bchan = &sc->sc_chan[chan];
+
+ sc->avma1pp_cmd &= ~HSCX_CMD_XME;
+ sc->avma1pp_txl = 0;
+ if (Bchan->out_mbuf_cur == NULL)
+ {
+ if (Bchan->bprot != BPROT_NONE)
+ sc->avma1pp_cmd |= HSCX_CMD_XME;
+ }
+ if (len != sc->sc_bfifolen)
+ sc->avma1pp_txl = len;
+
+ cnt = 0; /* borrow cnt */
+ AVMA1PPSETCMDLONG(cnt);
+ hscx_write_reg(chan, HSCX_STAT, cnt, sc);
+
+ ip = (u_int32_t *)buf;
+ cnt = 0;
+ while (cnt < len)
+ {
+ bus_space_write_4(sc->sc_maps[0].t, sc->sc_maps[0].h, ISAC_REG_OFFSET, *ip);
+ ip++;
+ cnt += 4;
+ }
+}
+#endif
+
+/*---------------------------------------------------------------------------*
+ * AVM write register routines
+ *---------------------------------------------------------------------------*/
+#ifdef __FreeBSD__
+static void
+avma1pp_write_reg(u_char *base, u_int offset, u_int v)
+{
+ int unit;
+ struct isic_softc *sc;
+ u_char reg_bank;
+
+ unit = (int)base & 0xff;
+ sc = &isic_sc[unit];
+
+ /* check whether the target is an HSCX */
+ if (((int)base & IS_HSCX_MASK) == HSCX0FAKE)
+ {
+ hscx_write_reg(0, offset, v, sc);
+ return;
+ }
+ if (((int)base & IS_HSCX_MASK) == HSCX1FAKE)
+ {
+ hscx_write_reg(1, offset, v, sc);
+ return;
+ }
+ /* must be the ISAC */
+ reg_bank = (offset > MAX_LO_REG_OFFSET) ? ISAC_HI_REG_OFFSET:ISAC_LO_REG_OFFSET;
+#ifdef AVMA1PCI_DEBUG
+ printf("write_reg bank %d off %d.. ", reg_bank, offset);
+#endif
+ /* set the register bank */
+ outb(sc->sc_port + ADDR_REG_OFFSET, reg_bank);
+ outb(sc->sc_port + ISAC_REG_OFFSET + (offset & ISAC_REGSET_MASK), v);
+}
+
+static void
+hscx_write_reg(int chan, u_int off, u_int val, struct isic_softc *sc)
+{
+ /* HACK */
+ if (off == H_MASK)
+ return;
+ /* point at the correct channel */
+ outl(sc->sc_port + ADDR_REG_OFFSET, chan);
+ outl(sc->sc_port + ISAC_REG_OFFSET + off, val);
+}
+
+#else
+
+static void
+avma1pp_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data)
+{
+ u_char reg_bank;
+ switch (what) {
+ case ISIC_WHAT_ISAC:
+ reg_bank = (offs > MAX_LO_REG_OFFSET) ? ISAC_HI_REG_OFFSET:ISAC_LO_REG_OFFSET;
+#ifdef AVMA1PCI_DEBUG
+ printf("write_reg bank %d off %ld.. ", (int)reg_bank, (long)offs);
+#endif
+ /* set the register bank */
+ bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, ADDR_REG_OFFSET, reg_bank);
+ bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, ISAC_REG_OFFSET + (offs & ISAC_REGSET_MASK), data);
+ break;
+ case ISIC_WHAT_HSCXA:
+ hscx_write_reg(0, offs, data, sc);
+ break;
+ case ISIC_WHAT_HSCXB:
+ hscx_write_reg(1, offs, data, sc);
+ break;
+ }
+}
+
+static void
+hscx_write_reg(int chan, u_int off, u_int val, struct isic_softc *sc)
+{
+ /* HACK */
+ if (off == H_MASK)
+ return;
+ /* point at the correct channel */
+ bus_space_write_4(sc->sc_maps[0].t, sc->sc_maps[0].h, ADDR_REG_OFFSET, chan);
+ bus_space_write_4(sc->sc_maps[0].t, sc->sc_maps[0].h, ISAC_REG_OFFSET + off, val);
+}
+
+#endif
+
+/*---------------------------------------------------------------------------*
+ * AVM read register routines
+ *---------------------------------------------------------------------------*/
+#ifdef __FreeBSD__
+
+static u_char
+avma1pp_read_reg(u_char *base, u_int offset)
+{
+ int unit;
+ struct isic_softc *sc;
+ u_char reg_bank;
+
+ unit = (int)base & 0xff;
+ sc = &isic_sc[unit];
+
+ /* check whether the target is an HSCX */
+ if (((int)base & IS_HSCX_MASK) == HSCX0FAKE)
+ return(hscx_read_reg(0, offset, sc));
+ if (((int)base & IS_HSCX_MASK) == HSCX1FAKE)
+ return(hscx_read_reg(1, offset, sc));
+ /* must be the ISAC */
+ reg_bank = (offset > MAX_LO_REG_OFFSET) ? ISAC_HI_REG_OFFSET:ISAC_LO_REG_OFFSET;
+#ifdef AVMA1PCI_DEBUG
+ printf("read_reg bank %d off %d.. ", reg_bank, offset);
+#endif
+ /* set the register bank */
+ outb(sc->sc_port + ADDR_REG_OFFSET, reg_bank);
+ return(inb(sc->sc_port + ISAC_REG_OFFSET +
+ (offset & ISAC_REGSET_MASK)));
+}
+#else
+static u_int8_t
+avma1pp_read_reg(struct isic_softc *sc, int what, bus_size_t offs)
+{
+ u_char reg_bank;
+ switch (what) {
+ case ISIC_WHAT_ISAC:
+ reg_bank = (offs > MAX_LO_REG_OFFSET) ? ISAC_HI_REG_OFFSET:ISAC_LO_REG_OFFSET;
+#ifdef AVMA1PCI_DEBUG
+ printf("read_reg bank %d off %ld.. ", (int)reg_bank, (long)offs);
+#endif
+ /* set the register bank */
+ bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, ADDR_REG_OFFSET, reg_bank);
+ return(bus_space_read_1(sc->sc_maps[0].t, sc->sc_maps[0].h, ISAC_REG_OFFSET +
+ (offs & ISAC_REGSET_MASK)));
+ case ISIC_WHAT_HSCXA:
+ return hscx_read_reg(0, offs, sc);
+ case ISIC_WHAT_HSCXB:
+ return hscx_read_reg(1, offs, sc);
+ }
+ return 0;
+}
+#endif
+
+static u_char
+hscx_read_reg(int chan, u_int off, struct isic_softc *sc)
+{
+ return(hscx_read_reg_int(chan, off, sc) & 0xff);
+}
+
+/*
+ * need to be able to return an int because the RBCH is in the 2nd
+ * byte.
+ */
+static u_int
+hscx_read_reg_int(int chan, u_int off, struct isic_softc *sc)
+{
+ /* HACK */
+ if (off == H_ISTA)
+ return(0);
+ /* point at the correct channel */
+#ifdef __FreeBSD__
+ outl(sc->sc_port + ADDR_REG_OFFSET, chan);
+ return(inl(sc->sc_port + ISAC_REG_OFFSET + off));
+#else
+ bus_space_write_4(sc->sc_maps[0].t, sc->sc_maps[0].h, ADDR_REG_OFFSET, chan);
+ return(bus_space_read_4(sc->sc_maps[0].t, sc->sc_maps[0].h, ISAC_REG_OFFSET + off));
+#endif
+}
+
+/*---------------------------------------------------------------------------*
+ * isic_attach_avma1pp - attach Fritz!Card PCI
+ *---------------------------------------------------------------------------*/
+#ifdef __FreeBSD__
+int
+isic_attach_avma1pp(int unit, u_int iobase1, u_int iobase2)
+{
+ struct isic_softc *sc = &isic_sc[unit];
+ u_int v;
+
+ /* check max unit range */
+
+ if(unit >= ISIC_MAXUNIT)
+ {
+ printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for AVM FRITZ/PCI!\n",
+ unit, unit);
+ return(0);
+ }
+ sc->sc_unit = unit;
+
+ /* setup iobase */
+
+ if((iobase1 <= 0) || (iobase1 > 0xffff))
+ {
+ printf("isic%d: Error, invalid iobase 0x%x specified for AVM FRITZ/PCI!\n",
+ unit, iobase1);
+ return(0);
+ }
+ sc->sc_port = iobase1;
+
+ /* the ISAC lives at offset 0x10, but we can't use that. */
+ /* instead, put the unit number into the lower byte - HACK */
+ sc->sc_isac = (caddr_t)((int)(iobase1 & ~0xff) + unit);
+
+ /* this thing doesn't have an HSCX, so fake the base addresses */
+ /* put the unit number into the lower byte - HACK */
+ HSCX_A_BASE = (caddr_t)(HSCX0FAKE + unit);
+ HSCX_B_BASE = (caddr_t)(HSCX1FAKE + unit);
+
+ /* setup access routines */
+
+ sc->clearirq = NULL;
+ sc->readreg = avma1pp_read_reg;
+ sc->writereg = avma1pp_write_reg;
+
+ sc->readfifo = avma1pp_read_fifo;
+ sc->writefifo = avma1pp_write_fifo;
+
+ /* setup card type */
+
+ sc->sc_cardtyp = CARD_TYPEP_AVMA1PCI;
+
+ /* setup IOM bus type */
+
+ sc->sc_bustyp = BUS_TYPE_IOM2;
+
+ /* set up some other miscellaneous things */
+ sc->sc_ipac = 0;
+ sc->sc_bfifolen = HSCX_FIFO_LEN;
+
+ /* reset the card */
+ /* the Linux driver does this to clear any pending ISAC interrupts */
+ v = 0;
+ v = ISAC_READ(I_STAR);
+#ifdef AVMA1PCI_DEBUG
+ printf("avma1pp_attach: I_STAR %x...", v);
+#endif
+ v = ISAC_READ(I_MODE);
+#ifdef AVMA1PCI_DEBUG
+ printf("avma1pp_attach: I_MODE %x...", v);
+#endif
+ v = ISAC_READ(I_ADF2);
+#ifdef AVMA1PCI_DEBUG
+ printf("avma1pp_attach: I_ADF2 %x...", v);
+#endif
+ v = ISAC_READ(I_ISTA);
+#ifdef AVMA1PCI_DEBUG
+ printf("avma1pp_attach: I_ISTA %x...", v);
+#endif
+ if (v & ISAC_ISTA_EXI)
+ {
+ v = ISAC_READ(I_EXIR);
+#ifdef AVMA1PCI_DEBUG
+ printf("avma1pp_attach: I_EXIR %x...", v);
+#endif
+ }
+ v = ISAC_READ(I_CIRR);
+#ifdef AVMA1PCI_DEBUG
+ printf("avma1pp_attach: I_CIRR %x...", v);
+#endif
+ ISAC_WRITE(I_MASK, 0xff);
+ /* the Linux driver does this to clear any pending HSCX interrupts */
+ v = hscx_read_reg_int(0, HSCX_STAT, sc);
+#ifdef AVMA1PCI_DEBUG
+ printf("avma1pp_attach: 0 HSCX_STAT %x...", v);
+#endif
+ v = hscx_read_reg_int(1, HSCX_STAT, sc);
+#ifdef AVMA1PCI_DEBUG
+ printf("avma1pp_attach: 1 HSCX_STAT %x\n", v);
+#endif
+
+ outb(sc->sc_port + STAT0_OFFSET, ASL_RESET_ALL|ASL_TIMERDISABLE);
+ DELAY(SEC_DELAY/100); /* 10 ms */
+ outb(sc->sc_port + STAT0_OFFSET, ASL_TIMERRESET|ASL_ENABLE_INT|ASL_TIMERDISABLE);
+ DELAY(SEC_DELAY/100); /* 10 ms */
+#ifdef AVMA1PCI_DEBUG
+ outb(sc->sc_port + STAT1_OFFSET, ASL1_ENABLE_IOM|sc->sc_irq);
+ DELAY(SEC_DELAY/100); /* 10 ms */
+ printf("after reset: S1 %#x\n", inb(sc->sc_port + STAT1_OFFSET));
+
+ v = inl(sc->sc_port);
+ printf("isic_attach_avma1pp: v %#x\n", v);
+#endif
+
+ /* from here to the end would normally be done in isic_pciattach */
+
+ printf("isic%d: ISAC %s (IOM-%c)\n", unit,
+ "2085 Version A1/A2 or 2086/2186 Version 1.1",
+ sc->sc_bustyp == BUS_TYPE_IOM1 ? '1' : '2');
+
+ /* init the ISAC */
+ isic_isac_init(sc);
+
+ /* init the "HSCX" */
+ avma1pp_bchannel_setup(sc->sc_unit, HSCX_CH_A, BPROT_NONE, 0);
+
+ avma1pp_bchannel_setup(sc->sc_unit, HSCX_CH_B, BPROT_NONE, 0);
+
+ /* can't use the normal B-Channel stuff */
+ avma1pp_init_linktab(sc);
+
+ /* set trace level */
+
+ sc->sc_trace = TRACE_OFF;
+
+ sc->sc_state = ISAC_IDLE;
+
+ sc->sc_ibuf = NULL;
+ sc->sc_ib = NULL;
+ sc->sc_ilen = 0;
+
+ sc->sc_obuf = NULL;
+ sc->sc_op = NULL;
+ sc->sc_ol = 0;
+ sc->sc_freeflag = 0;
+
+ sc->sc_obuf2 = NULL;
+ sc->sc_freeflag2 = 0;
+
+#if defined(__FreeBSD__) && __FreeBSD__ >=3
+ callout_handle_init(&sc->sc_T3_callout);
+ callout_handle_init(&sc->sc_T4_callout);
+#endif
+
+ /* init higher protocol layers */
+
+ MPH_Status_Ind(sc->sc_unit, STI_ATTACH, sc->sc_cardtyp);
+
+ return(1);
+}
+
+#else
+
+void
+isic_attach_fritzPci(struct pci_isic_softc *psc, struct pci_attach_args *pa)
+{
+ struct isic_softc *sc = &psc->sc_isic;
+ u_int v;
+
+ isic_sc[sc->sc_unit] = sc; /* XXX - hack! */
+
+ /* setup io mappings */
+ sc->sc_num_mappings = 1;
+ MALLOC_MAPS(sc);
+ sc->sc_maps[0].size = 0;
+ if (pci_mapreg_map(pa, FRITZPCI_PORT0_MAPOFF, PCI_MAPREG_TYPE_IO, 0,
+ &sc->sc_maps[0].t, &sc->sc_maps[0].h, NULL, NULL)) {
+ printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname);
+ return;
+ }
+
+ /* setup access routines */
+
+ sc->clearirq = NULL;
+ sc->readreg = avma1pp_read_reg;
+ sc->writereg = avma1pp_write_reg;
+
+ sc->readfifo = avma1pp_read_fifo;
+ sc->writefifo = avma1pp_write_fifo;
+
+
+ /* setup card type */
+
+ sc->sc_cardtyp = CARD_TYPEP_AVMA1PCI;
+
+ /* setup IOM bus type */
+
+ sc->sc_bustyp = BUS_TYPE_IOM2;
+
+ /* this is no IPAC based card */
+ sc->sc_ipac = 0;
+ sc->sc_bfifolen = HSCX_FIFO_LEN;
+
+ /* init the card */
+ /* the Linux driver does this to clear any pending ISAC interrupts */
+ /* see if it helps any - XXXX */
+ v = 0;
+ v = ISAC_READ(I_STAR);
+#ifdef AVMA1PCI_DEBUG
+ printf("avma1pp_attach: I_STAR %x...", v);
+#endif
+ v = ISAC_READ(I_MODE);
+#ifdef AVMA1PCI_DEBUG
+ printf("avma1pp_attach: I_MODE %x...", v);
+#endif
+ v = ISAC_READ(I_ADF2);
+#ifdef AVMA1PCI_DEBUG
+ printf("avma1pp_attach: I_ADF2 %x...", v);
+#endif
+ v = ISAC_READ(I_ISTA);
+#ifdef AVMA1PCI_DEBUG
+ printf("avma1pp_attach: I_ISTA %x...", v);
+#endif
+ if (v & ISAC_ISTA_EXI)
+ {
+ v = ISAC_READ(I_EXIR);
+#ifdef AVMA1PCI_DEBUG
+ printf("avma1pp_attach: I_EXIR %x...", v);
+#endif
+ }
+ v = ISAC_READ(I_CIRR);
+#ifdef AVMA1PCI_DEBUG
+ printf("avma1pp_attach: I_CIRR %x...", v);
+#endif
+ ISAC_WRITE(I_MASK, 0xff);
+ /* the Linux driver does this to clear any pending HSCX interrupts */
+ v = hscx_read_reg_int(0, HSCX_STAT, sc);
+#ifdef AVMA1PCI_DEBUG
+ printf("avma1pp_attach: 0 HSCX_STAT %x...", v);
+#endif
+ v = hscx_read_reg_int(1, HSCX_STAT, sc);
+#ifdef AVMA1PCI_DEBUG
+ printf("avma1pp_attach: 1 HSCX_STAT %x\n", v);
+#endif
+
+ bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, STAT0_OFFSET, ASL_RESET_ALL|ASL_TIMERDISABLE);
+ DELAY(SEC_DELAY/100); /* 10 ms */
+ bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, STAT0_OFFSET, ASL_TIMERRESET|ASL_ENABLE_INT|ASL_TIMERDISABLE);
+ DELAY(SEC_DELAY/100); /* 10 ms */
+#ifdef AVMA1PCI_DEBUG
+ bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, STAT1_OFFSET, ASL1_ENABLE_IOM|sc->sc_irq);
+ DELAY(SEC_DELAY/100); /* 10 ms */
+ v = bus_space_read_1(sc->sc_maps[0].t, sc->sc_maps[0].h, STAT1_OFFSET);
+ printf("after reset: S1 %#x\n", v);
+
+ v = bus_space_read_4(sc->sc_maps[0].t, sc->sc_maps[0].h, 0);
+ printf("isic_attach_avma1pp: v %#x\n", v);
+#endif
+
+ /* setup i4b infrastructure (have to roll our own here) */
+
+ /* sc->sc_isac_version = ((ISAC_READ(I_RBCH)) >> 5) & 0x03; */
+ printf("%s: ISAC %s (IOM-%c)\n", sc->sc_dev.dv_xname,
+ "2085 Version A1/A2 or 2086/2186 Version 1.1",
+ sc->sc_bustyp == BUS_TYPE_IOM1 ? '1' : '2');
+
+ /* init the ISAC */
+ isic_isac_init(sc);
+
+ /* init the "HSCX" */
+ avma1pp_bchannel_setup(sc->sc_unit, HSCX_CH_A, BPROT_NONE, 0);
+
+ avma1pp_bchannel_setup(sc->sc_unit, HSCX_CH_B, BPROT_NONE, 0);
+
+ /* can't use the normal B-Channel stuff */
+ avma1pp_init_linktab(sc);
+
+ /* set trace level */
+
+ sc->sc_trace = TRACE_OFF;
+
+ sc->sc_state = ISAC_IDLE;
+
+ sc->sc_ibuf = NULL;
+ sc->sc_ib = NULL;
+ sc->sc_ilen = 0;
+
+ sc->sc_obuf = NULL;
+ sc->sc_op = NULL;
+ sc->sc_ol = 0;
+ sc->sc_freeflag = 0;
+
+ sc->sc_obuf2 = NULL;
+ sc->sc_freeflag2 = 0;
+
+ /* init higher protocol layers */
+
+ MPH_Status_Ind(sc->sc_unit, STI_ATTACH, sc->sc_cardtyp);
+
+ /* setup interrupt mapping */
+ avma1pp_map_int(psc, pa);
+}
+
+#endif
+
+/*
+ * this is the real interrupt routine
+ */
+static void
+avma1pp_hscx_intr(int h_chan, u_int stat, struct isic_softc *sc)
+{
+ register isic_Bchan_t *chan = &sc->sc_chan[h_chan];
+ int activity = -1;
+ u_int param = 0;
+
+ DBGL1(L1_H_IRQ, "avma1pp_hscx_intr", ("%#x\n", stat));
+
+ if((stat & HSCX_INT_XDU) && (chan->bprot != BPROT_NONE))/* xmit data underrun */
+ {
+ chan->stat_XDU++;
+ DBGL1(L1_H_XFRERR, "avma1pp_hscx_intr", ("xmit data underrun\n"));
+ /* abort the transmission */
+ sc->avma1pp_txl = 0;
+ sc->avma1pp_cmd |= HSCX_CMD_XRS;
+ AVMA1PPSETCMDLONG(param);
+ hscx_write_reg(h_chan, HSCX_STAT, param, sc);
+ sc->avma1pp_cmd &= ~HSCX_CMD_XRS;
+ AVMA1PPSETCMDLONG(param);
+ hscx_write_reg(h_chan, HSCX_STAT, param, sc);
+
+ if (chan->out_mbuf_head != NULL) /* don't continue to transmit this buffer */
+ {
+ i4b_Bfreembuf(chan->out_mbuf_head);
+ chan->out_mbuf_cur = chan->out_mbuf_head = NULL;
+ }
+ }
+
+ /*
+ * The following is based on examination of the Linux driver.
+ *
+ * The logic here is different than with a "real" HSCX; all kinds
+ * of information (interrupt/status bits) are in stat.
+ * HSCX_INT_RPR indicates a receive interrupt
+ * HSCX_STAT_RDO indicates an overrun condition, abort -
+ * otherwise read the bytes ((stat & HSCX_STZT_RML_MASK) >> 8)
+ * HSCX_STAT_RME indicates end-of-frame and apparently any
+ * CRC/framing errors are only reported in this state.
+ * if ((stat & HSCX_STAT_CRCVFRRAB) != HSCX_STAT_CRCVFR)
+ * CRC/framing error
+ */
+
+ if(stat & HSCX_INT_RPR)
+ {
+ register int fifo_data_len;
+ int error = 0;
+ /* always have to read the FIFO, so use a scratch buffer */
+ u_char scrbuf[HSCX_FIFO_LEN];
+
+ if(stat & HSCX_STAT_RDO)
+ {
+ chan->stat_RDO++;
+ DBGL1(L1_H_XFRERR, "avma1pp_hscx_intr", ("receive data overflow\n"));
+ error++;
+ }
+
+ fifo_data_len = ((stat & HSCX_STAT_RML_MASK) >> 8);
+
+ if(fifo_data_len == 0)
+ fifo_data_len = sc->sc_bfifolen;
+
+ /* ALWAYS read data from HSCX fifo */
+
+ HSCX_RDFIFO(h_chan, scrbuf, fifo_data_len);
+ chan->rxcount += fifo_data_len;
+
+ /* all error conditions checked, now decide and take action */
+
+ if(error == 0)
+ {
+ if(chan->in_mbuf == NULL)
+ {
+ if((chan->in_mbuf = i4b_Bgetmbuf(BCH_MAX_DATALEN)) == NULL)
+ panic("L1 avma1pp_hscx_intr: RME, cannot allocate mbuf!\n");
+ chan->in_cbptr = chan->in_mbuf->m_data;
+ chan->in_len = 0;
+ }
+
+ if((chan->in_len + fifo_data_len) <= BCH_MAX_DATALEN)
+ {
+ /* OK to copy the data */
+ bcopy(scrbuf, chan->in_cbptr, fifo_data_len);
+ chan->in_cbptr += fifo_data_len;
+ chan->in_len += fifo_data_len;
+
+ /* setup mbuf data length */
+
+ chan->in_mbuf->m_len = chan->in_len;
+ chan->in_mbuf->m_pkthdr.len = chan->in_len;
+
+ if(sc->sc_trace & TRACE_B_RX)
+ {
+ i4b_trace_hdr_t hdr;
+ hdr.unit = sc->sc_unit;
+ hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2);
+ hdr.dir = FROM_NT;
+ hdr.count = ++sc->sc_trace_bcount;
+ MICROTIME(hdr.time);
+ MPH_Trace_Ind(&hdr, chan->in_mbuf->m_len, chan->in_mbuf->m_data);
+ }
+
+ if (stat & HSCX_STAT_RME)
+ {
+ if((stat & HSCX_STAT_CRCVFRRAB) == HSCX_STAT_CRCVFR)
+ {
+ (*chan->drvr_linktab->bch_rx_data_ready)(chan->drvr_linktab->unit);
+ activity = ACT_RX;
+
+ /* mark buffer ptr as unused */
+
+ chan->in_mbuf = NULL;
+ chan->in_cbptr = NULL;
+ chan->in_len = 0;
+ }
+ else
+ {
+ chan->stat_CRC++;
+ DBGL1(L1_H_XFRERR, "avma1pp_hscx_intr", ("CRC/RAB\n"));
+ if (chan->in_mbuf != NULL)
+ {
+ i4b_Bfreembuf(chan->in_mbuf);
+ chan->in_mbuf = NULL;
+ chan->in_cbptr = NULL;
+ chan->in_len = 0;
+ }
+ }
+ }
+ } /* END enough space in mbuf */
+ else
+ {
+ if(chan->bprot == BPROT_NONE)
+ {
+ /* setup mbuf data length */
+
+ chan->in_mbuf->m_len = chan->in_len;
+ chan->in_mbuf->m_pkthdr.len = chan->in_len;
+
+ if(sc->sc_trace & TRACE_B_RX)
+ {
+ i4b_trace_hdr_t hdr;
+ hdr.unit = sc->sc_unit;
+ hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2);
+ hdr.dir = FROM_NT;
+ hdr.count = ++sc->sc_trace_bcount;
+ MICROTIME(hdr.time);
+ MPH_Trace_Ind(&hdr, chan->in_mbuf->m_len, chan->in_mbuf->m_data);
+ }
+
+ /* move rx'd data to rx queue */
+
+ IF_ENQUEUE(&chan->rx_queue, chan->in_mbuf);
+
+ (*chan->drvr_linktab->bch_rx_data_ready)(chan->drvr_linktab->unit);
+
+ if(!(isic_hscx_silence(chan->in_mbuf->m_data, chan->in_mbuf->m_len)))
+ activity = ACT_RX;
+
+ /* alloc new buffer */
+
+ if((chan->in_mbuf = i4b_Bgetmbuf(BCH_MAX_DATALEN)) == NULL)
+ panic("L1 avma1pp_hscx_intr: RPF, cannot allocate new mbuf!\n");
+
+ /* setup new data ptr */
+
+ chan->in_cbptr = chan->in_mbuf->m_data;
+
+ /* OK to copy the data */
+ bcopy(scrbuf, chan->in_cbptr, fifo_data_len);
+
+ chan->in_cbptr += fifo_data_len;
+ chan->in_len = fifo_data_len;
+
+ chan->rxcount += fifo_data_len;
+ }
+ else
+ {
+ DBGL1(L1_H_XFRERR, "avma1pp_hscx_intr", ("RAWHDLC rx buffer overflow in RPF, in_len=%d\n", chan->in_len));
+ chan->in_cbptr = chan->in_mbuf->m_data;
+ chan->in_len = 0;
+ }
+ }
+ } /* if(error == 0) */
+ else
+ {
+ /* land here for RDO */
+ if (chan->in_mbuf != NULL)
+ {
+ i4b_Bfreembuf(chan->in_mbuf);
+ chan->in_mbuf = NULL;
+ chan->in_cbptr = NULL;
+ chan->in_len = 0;
+ }
+ sc->avma1pp_txl = 0;
+ sc->avma1pp_cmd |= HSCX_CMD_RRS;
+ AVMA1PPSETCMDLONG(param);
+ hscx_write_reg(h_chan, HSCX_STAT, param, sc);
+ sc->avma1pp_cmd &= ~HSCX_CMD_RRS;
+ AVMA1PPSETCMDLONG(param);
+ hscx_write_reg(h_chan, HSCX_STAT, param, sc);
+ }
+ }
+
+
+ /* transmit fifo empty, new data can be written to fifo */
+
+ if(stat & HSCX_INT_XPR)
+ {
+ /*
+ * for a description what is going on here, please have
+ * a look at isic_bchannel_start() in i4b_bchan.c !
+ */
+
+ DBGL1(L1_H_IRQ, "avma1pp_hscx_intr", ("unit %d, chan %d - XPR, Tx Fifo Empty!\n", sc->sc_unit, h_chan));
+
+ if(chan->out_mbuf_cur == NULL) /* last frame is transmitted */
+ {
+ IF_DEQUEUE(&chan->tx_queue, chan->out_mbuf_head);
+
+ if(chan->out_mbuf_head == NULL)
+ {
+ chan->state &= ~HSCX_TX_ACTIVE;
+ (*chan->drvr_linktab->bch_tx_queue_empty)(chan->drvr_linktab->unit);
+ }
+ else
+ {
+ chan->state |= HSCX_TX_ACTIVE;
+ chan->out_mbuf_cur = chan->out_mbuf_head;
+ chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data;
+ chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len;
+
+ if(sc->sc_trace & TRACE_B_TX)
+ {
+ i4b_trace_hdr_t hdr;
+ hdr.unit = sc->sc_unit;
+ hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2);
+ hdr.dir = FROM_TE;
+ hdr.count = ++sc->sc_trace_bcount;
+ MICROTIME(hdr.time);
+ MPH_Trace_Ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data);
+ }
+
+ if(chan->bprot == BPROT_NONE)
+ {
+ if(!(isic_hscx_silence(chan->out_mbuf_cur->m_data, chan->out_mbuf_cur->m_len)))
+ activity = ACT_TX;
+ }
+ else
+ {
+ activity = ACT_TX;
+ }
+ }
+ }
+
+ isic_hscx_fifo(chan, sc);
+ }
+
+ /* call timeout handling routine */
+
+ if(activity == ACT_RX || activity == ACT_TX)
+ (*chan->drvr_linktab->bch_activity)(chan->drvr_linktab->unit, activity);
+}
+
+/*
+ * this is the main routine which checks each channel and then calls
+ * the real interrupt routine as appropriate
+ */
+static void
+avma1pp_hscx_int_handler(struct isic_softc *sc)
+{
+ u_int stat;
+
+ /* has to be a u_int because the byte count is in the 2nd byte */
+ stat = hscx_read_reg_int(0, HSCX_STAT, sc);
+ if (stat & HSCX_INT_MASK)
+ avma1pp_hscx_intr(0, stat, sc);
+ stat = hscx_read_reg_int(1, HSCX_STAT, sc);
+ if (stat & HSCX_INT_MASK)
+ avma1pp_hscx_intr(1, stat, sc);
+}
+
+static void
+avma1pp_disable(struct isic_softc *sc)
+{
+#ifdef __FreeBSD__
+ outb(sc->sc_port + STAT0_OFFSET, ASL_RESET_ALL|ASL_TIMERDISABLE);
+#else
+ bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, STAT0_OFFSET, ASL_RESET_ALL|ASL_TIMERDISABLE);
+#endif
+}
+
+#ifdef __FreeBSD__
+static void
+avma1pp_intr(struct isic_softc *sc)
+{
+#define OURS /* no return value accumulated */
+#define ISICINTR(sc) isicintr_sc(sc)
+#else
+static int
+avma1pp_intr(void * parm)
+{
+ struct isic_softc *sc = parm;
+ int ret = 0;
+#define OURS ret = 1
+#define ISICINTR(sc) isicintr(sc)
+#endif
+ u_char stat;
+
+#ifdef __FreeBSD__
+ stat = inb(sc->sc_port + STAT0_OFFSET);
+#else
+ stat = bus_space_read_1(sc->sc_maps[0].t, sc->sc_maps[0].h, STAT0_OFFSET);
+#endif
+ DBGL1(L1_H_IRQ, "avma1pp_intr", ("stat %x\n", stat));
+ /* was there an interrupt from this card ? */
+ if ((stat & ASL_IRQ_Pending) == ASL_IRQ_Pending)
+#ifdef __FreeBSD__
+ return; /* no */
+#else
+ return 0; /* no */
+#endif
+ /* interrupts are low active */
+ if (!(stat & ASL_IRQ_TIMER))
+ DBGL1(L1_H_IRQ, "avma1pp_intr", ("timer interrupt ???\n"));
+ if (!(stat & ASL_IRQ_HSCX))
+ {
+ DBGL1(L1_H_IRQ, "avma1pp_intr", ("HSCX\n"));
+ avma1pp_hscx_int_handler(sc);
+ OURS;
+ }
+ if (!(stat & ASL_IRQ_ISAC))
+ {
+ DBGL1(L1_H_IRQ, "avma1pp_intr", ("ISAC\n"));
+ ISICINTR(sc);
+ OURS;
+ }
+#ifndef __FreeBSD__
+ return ret;
+#endif
+}
+
+#ifdef __FreeBSD__
+void
+avma1pp_map_int(pcici_t config_id, void *pisc, unsigned *net_imask)
+{
+ struct isic_softc *sc = (struct isic_softc *)pisc;
+
+#ifdef AVMA1PCI_DEBUG
+ /* may need the irq later */
+#if __FreeBSD__ < 3
+ /* I'd like to call getirq here, but it is static */
+ sc->sc_irq = PCI_INTERRUPT_LINE_EXTRACT(
+ pci_conf_read (config_id, PCI_INTERRUPT_REG));
+
+ if (sc->sc_irq == 0 || sc->sc_irq == 0xff)
+ printf ("avma1pp_map_int:int line register not set by bios\n");
+
+ if (sc->sc_irq >= PCI_MAX_IRQ)
+ printf ("avma1pp_map_int:irq %d out of bounds (must be < %d)\n",
+ sc->sc_irq, PCI_MAX_IRQ);
+#else
+ sc->sc_irq = config_id->intline;
+#endif
+#endif /* AVMA1PCI_DEBUG */
+
+ if(!(pci_map_int(config_id, (void *)avma1pp_intr, sc, net_imask)))
+ {
+ printf("Failed to map interrupt for AVM Fritz!Card PCI\n");
+ /* disable the card */
+ avma1pp_disable(sc);
+ }
+}
+#else
+static void
+avma1pp_map_int(struct pci_isic_softc *psc, struct pci_attach_args *pa)
+{
+ struct isic_softc *sc = &psc->sc_isic;
+ pci_chipset_tag_t pc = pa->pa_pc;
+ pci_intr_handle_t ih;
+ const char *intrstr;
+
+ /* Map and establish the interrupt. */
+ if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin,
+ pa->pa_intrline, &ih)) {
+ printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname);
+ avma1pp_disable(sc);
+ return;
+ }
+ intrstr = pci_intr_string(pc, ih);
+ psc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, avma1pp_intr, sc);
+ if (psc->sc_ih == NULL) {
+ printf("%s: couldn't establish interrupt",
+ sc->sc_dev.dv_xname);
+ if (intrstr != NULL)
+ printf(" at %s", intrstr);
+ printf("\n");
+ avma1pp_disable(sc);
+ return;
+ }
+ printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);
+}
+#endif
+
+static void
+avma1pp_hscx_init(struct isic_softc *sc, int h_chan, int activate)
+{
+ isic_Bchan_t *chan = &sc->sc_chan[h_chan];
+ u_int param = 0;
+
+ DBGL1(L1_BCHAN, "avma1pp_hscx_init", ("unit=%d, channel=%d, %s\n",
+ sc->sc_unit, h_chan, activate ? "activate" : "deactivate"));
+
+ if (activate == 0)
+ {
+ /* only deactivate if both channels are idle */
+ if (sc->sc_chan[HSCX_CH_A].state != HSCX_IDLE ||
+ sc->sc_chan[HSCX_CH_B].state != HSCX_IDLE)
+ {
+ return;
+ }
+ sc->avma1pp_cmd = HSCX_CMD_XRS|HSCX_CMD_RRS;
+ sc->avma1pp_prot = HSCX_MODE_TRANS;
+ AVMA1PPSETCMDLONG(param);
+ hscx_write_reg(h_chan, HSCX_STAT, param, sc);
+ return;
+ }
+ if(chan->bprot == BPROT_RHDLC)
+ {
+ DBGL1(L1_BCHAN, "avma1pp_hscx_init", ("BPROT_RHDLC\n"));
+
+ /* HDLC Frames, transparent mode 0 */
+ sc->avma1pp_cmd = HSCX_CMD_XRS|HSCX_CMD_RRS;
+ sc->avma1pp_prot = HSCX_MODE_ITF_FLG;
+ AVMA1PPSETCMDLONG(param);
+ hscx_write_reg(h_chan, HSCX_STAT, param, sc);
+ sc->avma1pp_cmd = HSCX_CMD_XRS;
+ AVMA1PPSETCMDLONG(param);
+ hscx_write_reg(h_chan, HSCX_STAT, param, sc);
+ sc->avma1pp_cmd = 0;
+ }
+ else
+ {
+ DBGL1(L1_BCHAN, "avma1pp_hscx_init", ("BPROT_NONE??\n"));
+
+ /* Raw Telephony, extended transparent mode 1 */
+ sc->avma1pp_cmd = HSCX_CMD_XRS|HSCX_CMD_RRS;
+ sc->avma1pp_prot = HSCX_MODE_TRANS;
+ AVMA1PPSETCMDLONG(param);
+ hscx_write_reg(h_chan, HSCX_STAT, param, sc);
+ sc->avma1pp_cmd = HSCX_CMD_XRS;
+ AVMA1PPSETCMDLONG(param);
+ hscx_write_reg(h_chan, HSCX_STAT, param, sc);
+ sc->avma1pp_cmd = 0;
+ }
+}
+
+static void
+avma1pp_bchannel_setup(int unit, int h_chan, int bprot, int activate)
+{
+#ifdef __FreeBSD__
+ struct isic_softc *sc = &isic_sc[unit];
+#else
+ struct isic_softc *sc = isic_find_sc(unit);
+#endif
+ isic_Bchan_t *chan = &sc->sc_chan[h_chan];
+
+ int s = SPLI4B();
+
+ if(activate == 0)
+ {
+ /* deactivation */
+ chan->state &= ~HSCX_AVMA1PP_ACTIVE;
+ avma1pp_hscx_init(sc, h_chan, activate);
+ }
+
+ DBGL1(L1_BCHAN, "avma1pp_bchannel_setup", ("unit=%d, channel=%d, %s\n",
+ sc->sc_unit, h_chan, activate ? "activate" : "deactivate"));
+
+ /* general part */
+
+ chan->unit = sc->sc_unit; /* unit number */
+ chan->channel = h_chan; /* B channel */
+ chan->bprot = bprot; /* B channel protocol */
+ chan->state = HSCX_IDLE; /* B channel state */
+
+ /* receiver part */
+
+ i4b_Bcleanifq(&chan->rx_queue); /* clean rx queue */
+
+ chan->rx_queue.ifq_maxlen = IFQ_MAXLEN;
+
+ chan->rxcount = 0; /* reset rx counter */
+
+ i4b_Bfreembuf(chan->in_mbuf); /* clean rx mbuf */
+
+ chan->in_mbuf = NULL; /* reset mbuf ptr */
+ chan->in_cbptr = NULL; /* reset mbuf curr ptr */
+ chan->in_len = 0; /* reset mbuf data len */
+
+ /* transmitter part */
+
+ i4b_Bcleanifq(&chan->tx_queue); /* clean tx queue */
+
+ chan->tx_queue.ifq_maxlen = IFQ_MAXLEN;
+
+ chan->txcount = 0; /* reset tx counter */
+
+ i4b_Bfreembuf(chan->out_mbuf_head); /* clean tx mbuf */
+
+ chan->out_mbuf_head = NULL; /* reset head mbuf ptr */
+ chan->out_mbuf_cur = NULL; /* reset current mbuf ptr */
+ chan->out_mbuf_cur_ptr = NULL; /* reset current mbuf data ptr */
+ chan->out_mbuf_cur_len = 0; /* reset current mbuf data cnt */
+
+ if(activate != 0)
+ {
+ /* activation */
+ avma1pp_hscx_init(sc, h_chan, activate);
+ chan->state |= HSCX_AVMA1PP_ACTIVE;
+ }
+
+ splx(s);
+}
+
+static void
+avma1pp_bchannel_start(int unit, int h_chan)
+{
+#ifdef __FreeBSD__
+ struct isic_softc *sc = &isic_sc[unit];
+#else
+ struct isic_softc *sc = isic_find_sc(unit);
+#endif
+ register isic_Bchan_t *chan = &sc->sc_chan[h_chan];
+ int s;
+ int activity = -1;
+
+ s = SPLI4B(); /* enter critical section */
+ if(chan->state & HSCX_TX_ACTIVE) /* already running ? */
+ {
+ splx(s);
+ return; /* yes, leave */
+ }
+
+ /* get next mbuf from queue */
+
+ IF_DEQUEUE(&chan->tx_queue, chan->out_mbuf_head);
+
+ if(chan->out_mbuf_head == NULL) /* queue empty ? */
+ {
+ splx(s); /* leave critical section */
+ return; /* yes, exit */
+ }
+
+ /* init current mbuf values */
+
+ chan->out_mbuf_cur = chan->out_mbuf_head;
+ chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len;
+ chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data;
+
+ /* activity indicator for timeout handling */
+
+ if(chan->bprot == BPROT_NONE)
+ {
+ if(!(isic_hscx_silence(chan->out_mbuf_cur->m_data, chan->out_mbuf_cur->m_len)))
+ activity = ACT_TX;
+ }
+ else
+ {
+ activity = ACT_TX;
+ }
+
+ chan->state |= HSCX_TX_ACTIVE; /* we start transmitting */
+
+ if(sc->sc_trace & TRACE_B_TX) /* if trace, send mbuf to trace dev */
+ {
+ i4b_trace_hdr_t hdr;
+ hdr.unit = unit;
+ hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2);
+ hdr.dir = FROM_TE;
+ hdr.count = ++sc->sc_trace_bcount;
+ MICROTIME(hdr.time);
+ MPH_Trace_Ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data);
+ }
+
+ isic_hscx_fifo(chan, sc);
+
+ /* call timeout handling routine */
+
+ if(activity == ACT_RX || activity == ACT_TX)
+ (*chan->drvr_linktab->bch_activity)(chan->drvr_linktab->unit, activity);
+
+ splx(s);
+}
+
+/*---------------------------------------------------------------------------*
+ * return the address of isic drivers linktab
+ *---------------------------------------------------------------------------*/
+static isdn_link_t *
+avma1pp_ret_linktab(int unit, int channel)
+{
+#ifdef __FreeBSD__
+ struct isic_softc *sc = &isic_sc[unit];
+#else
+ struct isic_softc *sc = isic_find_sc(unit);
+#endif
+ isic_Bchan_t *chan = &sc->sc_chan[channel];
+
+ return(&chan->isdn_linktab);
+}
+
+/*---------------------------------------------------------------------------*
+ * set the driver linktab in the b channel softc
+ *---------------------------------------------------------------------------*/
+static void
+avma1pp_set_linktab(int unit, int channel, drvr_link_t *dlt)
+{
+#ifdef __FreeBSD__
+ struct isic_softc *sc = &isic_sc[unit];
+#else
+ struct isic_softc *sc = isic_find_sc(unit);
+#endif
+ isic_Bchan_t *chan = &sc->sc_chan[channel];
+
+ chan->drvr_linktab = dlt;
+}
+
+
+/*---------------------------------------------------------------------------*
+ * initialize our local linktab
+ *---------------------------------------------------------------------------*/
+static void
+avma1pp_init_linktab(struct isic_softc *sc)
+{
+ isic_Bchan_t *chan = &sc->sc_chan[HSCX_CH_A];
+ isdn_link_t *lt = &chan->isdn_linktab;
+
+ /* make sure the hardware driver is known to layer 4 */
+ /* avoid overwriting if already set */
+ if (ctrl_types[CTRL_PASSIVE].set_linktab == NULL)
+ {
+ ctrl_types[CTRL_PASSIVE].set_linktab = avma1pp_set_linktab;
+ ctrl_types[CTRL_PASSIVE].get_linktab = avma1pp_ret_linktab;
+ }
+
+ /* local setup */
+ lt->unit = sc->sc_unit;
+ lt->channel = HSCX_CH_A;
+ lt->bch_config = avma1pp_bchannel_setup;
+ lt->bch_tx_start = avma1pp_bchannel_start;
+ lt->bch_stat = avma1pp_bchannel_stat;
+ lt->tx_queue = &chan->tx_queue;
+
+ /* used by non-HDLC data transfers, i.e. telephony drivers */
+ lt->rx_queue = &chan->rx_queue;
+
+ /* used by HDLC data transfers, i.e. ipr and isp drivers */
+ lt->rx_mbuf = &chan->in_mbuf;
+
+ chan = &sc->sc_chan[HSCX_CH_B];
+ lt = &chan->isdn_linktab;
+
+ lt->unit = sc->sc_unit;
+ lt->channel = HSCX_CH_B;
+ lt->bch_config = avma1pp_bchannel_setup;
+ lt->bch_tx_start = avma1pp_bchannel_start;
+ lt->bch_stat = avma1pp_bchannel_stat;
+ lt->tx_queue = &chan->tx_queue;
+
+ /* used by non-HDLC data transfers, i.e. telephony drivers */
+ lt->rx_queue = &chan->rx_queue;
+
+ /* used by HDLC data transfers, i.e. ipr and isp drivers */
+ lt->rx_mbuf = &chan->in_mbuf;
+}
+
+/*
+ * use this instead of isic_bchannel_stat in i4b_bchan.c because it's static
+ */
+static void
+avma1pp_bchannel_stat(int unit, int h_chan, bchan_statistics_t *bsp)
+{
+#ifdef __FreeBSD__
+ struct isic_softc *sc = &isic_sc[unit];
+#else
+ struct isic_softc *sc = isic_find_sc(unit);
+#endif
+ isic_Bchan_t *chan = &sc->sc_chan[h_chan];
+ int s;
+
+ s = SPLI4B();
+
+ bsp->outbytes = chan->txcount;
+ bsp->inbytes = chan->rxcount;
+
+ chan->txcount = 0;
+ chan->rxcount = 0;
+
+ splx(s);
+}
+
+/*---------------------------------------------------------------------------*
+ * fill HSCX fifo with data from the current mbuf
+ * Put this here until it can go into i4b_hscx.c
+ *---------------------------------------------------------------------------*/
+static int
+isic_hscx_fifo(isic_Bchan_t *chan, struct isic_softc *sc)
+{
+ int len;
+ int nextlen;
+ int i;
+ int cmd;
+ /* using a scratch buffer simplifies writing to the FIFO */
+ u_char scrbuf[HSCX_FIFO_LEN];
+
+ len = 0;
+
+ /*
+ * fill the HSCX tx fifo with data from the current mbuf. if
+ * current mbuf holds less data than HSCX fifo length, try to
+ * get the next mbuf from (a possible) mbuf chain. if there is
+ * not enough data in a single mbuf or in a chain, then this
+ * is the last mbuf and we tell the HSCX that it has to send
+ * CRC and closing flag
+ */
+
+ while(chan->out_mbuf_cur && len != sc->sc_bfifolen)
+ {
+ nextlen = min(chan->out_mbuf_cur_len, sc->sc_bfifolen - len);
+
+#ifdef NOTDEF
+ printf("i:mh=%p, mc=%p, mcp=%p, mcl=%d l=%d nl=%d # ",
+ chan->out_mbuf_head,
+ chan->out_mbuf_cur,
+ chan->out_mbuf_cur_ptr,
+ chan->out_mbuf_cur_len,
+ len,
+ nextlen);
+#endif
+
+ cmd |= HSCX_CMDR_XTF;
+ /* collect the data in the scratch buffer */
+ for (i = 0; i < nextlen; i++)
+ scrbuf[i + len] = chan->out_mbuf_cur_ptr[i];
+
+ len += nextlen;
+ chan->txcount += nextlen;
+
+ chan->out_mbuf_cur_ptr += nextlen;
+ chan->out_mbuf_cur_len -= nextlen;
+
+ if(chan->out_mbuf_cur_len == 0)
+ {
+ if((chan->out_mbuf_cur = chan->out_mbuf_cur->m_next) != NULL)
+ {
+ chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data;
+ chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len;
+
+ if(sc->sc_trace & TRACE_B_TX)
+ {
+ i4b_trace_hdr_t hdr;
+ hdr.unit = sc->sc_unit;
+ hdr.type = (chan->channel == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2);
+ hdr.dir = FROM_TE;
+ hdr.count = ++sc->sc_trace_bcount;
+ MICROTIME(hdr.time);
+ MPH_Trace_Ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data);
+ }
+ }
+ else
+ {
+ if (chan->bprot != BPROT_NONE)
+ cmd |= HSCX_CMDR_XME;
+ i4b_Bfreembuf(chan->out_mbuf_head);
+ chan->out_mbuf_head = NULL;
+ }
+ }
+ }
+ /* write what we have from the scratch buf to the HSCX fifo */
+ if (len != 0)
+ HSCX_WRFIFO(chan->channel, scrbuf, len);
+ return(cmd);
+}
+
+#endif /* NISIC > 0 && defined(AVM_A1_PCI) */
diff --git a/sys/i4b/layer1/i4b_avm_fritz_pnp.c b/sys/i4b/layer1/i4b_avm_fritz_pnp.c
new file mode 100644
index 000000000000..a411c8cb1320
--- /dev/null
+++ b/sys/i4b/layer1/i4b_avm_fritz_pnp.c
@@ -0,0 +1,1268 @@
+/*
+ * Copyright (c) 1999 Udo Schweigert. 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. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 4. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software and/or documentation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ * A lot of code was borrowed from i4b_bchan.c and i4b_hscx.c
+ * Based on AVM Fritz!PCI driver by Gary Jennejohn
+ *---------------------------------------------------------------------------
+ * In case of trouble please contact Udo Schweigert <ust@cert.siemens.de>
+ *---------------------------------------------------------------------------
+ *
+ * Fritz!Card PnP specific routines for isic driver
+ * ------------------------------------------------
+ *
+ * $FreeBSD$
+ *
+ * last edit-date: [Thu 10 Jun 08:50:28 CEST 1999]
+ *
+ *---------------------------------------------------------------------------*/
+
+#if defined(__FreeBSD__)
+#include "isic.h"
+#include "opt_i4b.h"
+
+#if NISIC > 0 && defined(AVM_PNP)
+
+#include <sys/param.h>
+#if defined(__FreeBSD__) && __FreeBSD__ >= 3
+#include <sys/ioccom.h>
+#else
+#include <sys/ioctl.h>
+#endif
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+
+#include <machine/clock.h>
+#include <i386/isa/isa_device.h>
+
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include <machine/i4b_debug.h>
+#include <machine/i4b_ioctl.h>
+
+#include <i4b/include/i4b_global.h>
+#include <i4b/include/i4b_l1l2.h>
+#include <i4b/include/i4b_mbuf.h>
+
+#include <i4b/layer1/i4b_l1.h>
+#include <i4b/layer1/i4b_isac.h>
+#include <i4b/layer1/i4b_hscx.h>
+
+static void hscx_write_reg(int, u_int, struct isic_softc *, int);
+static void hscx_write_reg_val(int, u_int, u_char, struct isic_softc *);
+static u_char hscx_read_reg(int, u_int, struct isic_softc *);
+static void hscx_read_fifo(int, void *, size_t, struct isic_softc *);
+static void hscx_write_fifo(int, const void *, size_t, struct isic_softc *);
+static void avm_pnp_hscx_int_handler(struct isic_softc *);
+static void avm_pnp_hscx_intr(int, int, int, struct isic_softc *);
+static void avm_pnp_init_linktab(struct isic_softc *);
+static void avm_pnp_bchannel_setup(int, int, int, int);
+static void avm_pnp_bchannel_start(int, int);
+static void avm_pnp_hscx_init(struct isic_softc *, int, int);
+static void avm_pnp_bchannel_stat(int, int, bchan_statistics_t *);
+static void avm_pnp_set_linktab(int, int, drvr_link_t *);
+static void avm_pnp_intr(int);
+static isdn_link_t * avm_pnp_ret_linktab(int, int);
+extern void isicintr_sc(struct isic_softc *);
+
+/*---------------------------------------------------------------------------*
+ * AVM PnP Fritz!Card special registers
+ *---------------------------------------------------------------------------*/
+
+/*
+ * register offsets from i/o base
+ */
+#define STAT0_OFFSET 0x02
+#define STAT1_OFFSET 0x03
+#define ADDR_REG_OFFSET 0x04
+
+/* these 2 are used to select an ISAC register set */
+#define ISAC_LO_REG_OFFSET 0x04
+#define ISAC_HI_REG_OFFSET 0x06
+
+/* offset higher than this goes to the HI register set */
+#define MAX_LO_REG_OFFSET 0x2f
+
+/* mask for the offset */
+#define ISAC_REGSET_MASK 0x0f
+
+/* the offset from the base to the ISAC registers */
+#define ISAC_REG_OFFSET 0x10
+
+/* the offset from the base to the ISAC FIFO */
+#define ISAC_FIFO 0x02
+
+/* not really the HSCX, but sort of */
+#define HSCX_FIFO 0x00
+#define HSCX_STAT 0x04
+
+/*
+ * AVM PnP Status Latch 0 read only bits
+ */
+#define ASL_IRQ_ISAC 0x01 /* ISAC interrupt, active low */
+#define ASL_IRQ_HSCX 0x02 /* HSX interrupt, active low */
+#define ASL_IRQ_TIMER 0x04 /* Timer interrupt, active low */
+#define ASL_IRQ_BCHAN ASL_IRQ_HSCX
+/* actually active LOW */
+#define ASL_IRQ_Pending 0x07
+
+/*
+ * AVM Status Latch 0 write only bits
+ */
+#define ASL_RESET_ALL 0x01 /* reset siemens IC's, active 1 */
+#define ASL_TIMERDISABLE 0x02 /* active high */
+#define ASL_TIMERRESET 0x04 /* active high */
+#define ASL_ENABLE_INT 0x08 /* active high */
+#define ASL_TESTBIT 0x10 /* active high */
+
+/*
+ * AVM Status Latch 1 write only bits
+ */
+#define ASL1_INTSEL 0x0f /* active high */
+#define ASL1_ENABLE_IOM 0x80 /* active high */
+
+/*
+ * "HSCX" mode bits
+ */
+#define HSCX_MODE_ITF_FLG 0x01
+#define HSCX_MODE_TRANS 0x02
+#define HSCX_MODE_CCR_7 0x04
+#define HSCX_MODE_CCR_16 0x08
+#define HSCX_MODE_TESTLOOP 0x80
+
+/*
+ * "HSCX" status bits
+ */
+#define HSCX_STAT_RME 0x01
+#define HSCX_STAT_RDO 0x10
+#define HSCX_STAT_CRCVFRRAB 0x0E
+#define HSCX_STAT_CRCVFR 0x06
+#define HSCX_STAT_RML_MASK 0x3f00
+
+/*
+ * "HSCX" interrupt bits
+ */
+#define HSCX_INT_XPR 0x80
+#define HSCX_INT_XDU 0x40
+#define HSCX_INT_RPR 0x20
+#define HSCX_INT_MASK 0xE0
+
+/*
+ * "HSCX" command bits
+ */
+#define HSCX_CMD_XRS 0x80
+#define HSCX_CMD_XME 0x01
+#define HSCX_CMD_RRS 0x20
+#define HSCX_CMD_XML_MASK 0x3f00
+
+/* "fake" addresses for the non-existent HSCX */
+/* note: the unit number is in the lower byte for both the ISAC and "HSCX" */
+#define HSCX0FAKE 0xfa000 /* read: fake0 */
+#define HSCX1FAKE 0xfa100 /* read: fake1 */
+#define IS_HSCX_MASK 0xfff00
+
+/*
+ * to prevent deactivating the "HSCX" when both channels are active we
+ * define an HSCX_ACTIVE flag which is or'd into the channel's state
+ * flag in avm_pnp_bchannel_setup upon active and cleared upon deactivation.
+ * It is set high to allow room for new flags.
+ */
+#define HSCX_AVMPNP_ACTIVE 0x1000
+
+/*---------------------------------------------------------------------------*
+ * AVM read fifo routines
+ *---------------------------------------------------------------------------*/
+
+static void
+avm_pnp_read_fifo(void *buf, const void *base, size_t len)
+{
+ int unit;
+ struct isic_softc *sc;
+
+ unit = (int)base & 0xff;
+ sc = &isic_sc[unit];
+
+ /* check whether the target is an HSCX */
+ if (((int)base & IS_HSCX_MASK) == HSCX0FAKE)
+ {
+ hscx_read_fifo(0, buf, len, sc);
+ return;
+ }
+ if (((int)base & IS_HSCX_MASK) == HSCX1FAKE)
+ {
+ hscx_read_fifo(1, buf, len, sc);
+ return;
+ }
+ /* tell the board to access the ISAC fifo */
+ outb(sc->sc_port + ADDR_REG_OFFSET, ISAC_FIFO);
+ insb(sc->sc_port + ISAC_REG_OFFSET, (u_char *)buf, len);
+}
+
+static void
+hscx_read_fifo(int chan, void *buf, size_t len, struct isic_softc *sc)
+{
+ u_char *ip;
+ size_t cnt;
+
+ outb(sc->sc_port + ADDR_REG_OFFSET, chan);
+ ip = (u_char *)buf;
+ cnt = 0;
+
+ while (cnt < len)
+ {
+ *ip++ = inb(sc->sc_port + ISAC_REG_OFFSET);
+ cnt++;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * AVM write fifo routines
+ *---------------------------------------------------------------------------*/
+static void
+avm_pnp_write_fifo(void *base, const void *buf, size_t len)
+{
+ int unit;
+ struct isic_softc *sc;
+
+ unit = (int)base & 0xff;
+ sc = &isic_sc[unit];
+
+ /* check whether the target is an HSCX */
+ if (((int)base & IS_HSCX_MASK) == HSCX0FAKE)
+ {
+ hscx_write_fifo(0, buf, len, sc);
+ return;
+ }
+ if (((int)base & IS_HSCX_MASK) == HSCX1FAKE)
+ {
+ hscx_write_fifo(1, buf, len, sc);
+ return;
+ }
+ /* tell the board to use the ISAC fifo */
+ outb(sc->sc_port + ADDR_REG_OFFSET, ISAC_FIFO);
+ outsb(sc->sc_port + ISAC_REG_OFFSET, (const u_char *)buf, len);
+}
+
+static void
+hscx_write_fifo(int chan, const void *buf, size_t len, struct isic_softc *sc)
+{
+ register const u_char *ip;
+ register size_t cnt;
+ isic_Bchan_t *Bchan = &sc->sc_chan[chan];
+
+ sc->avma1pp_cmd &= ~HSCX_CMD_XME;
+ sc->avma1pp_txl = 0;
+
+ if (Bchan->out_mbuf_cur == NULL && Bchan->bprot != BPROT_NONE)
+ sc->avma1pp_cmd |= HSCX_CMD_XME;
+
+ if (len != sc->sc_bfifolen)
+ sc->avma1pp_txl = len;
+
+ hscx_write_reg(chan, HSCX_STAT, sc, 3);
+
+ ip = (const u_char *)buf;
+ cnt = 0;
+ while (cnt < len)
+ {
+ outb(sc->sc_port + ISAC_REG_OFFSET, *ip++);
+ cnt++;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * AVM write register routines
+ *---------------------------------------------------------------------------*/
+static void
+avm_pnp_write_reg(u_char *base, u_int offset, u_int v)
+{
+ int unit;
+ struct isic_softc *sc;
+ u_char reg_bank;
+
+ unit = (int)base & 0xff;
+ sc = &isic_sc[unit];
+
+ /* check whether the target is an HSCX */
+ if (((int)base & IS_HSCX_MASK) == HSCX0FAKE)
+ {
+ hscx_write_reg_val(0, offset, v, sc);
+ return;
+ }
+ if (((int)base & IS_HSCX_MASK) == HSCX1FAKE)
+ {
+ hscx_write_reg_val(1, offset, v, sc);
+ return;
+ }
+ /* must be the ISAC */
+ reg_bank = (offset > MAX_LO_REG_OFFSET) ? ISAC_HI_REG_OFFSET:ISAC_LO_REG_OFFSET;
+ /* set the register bank */
+ outb(sc->sc_port + ADDR_REG_OFFSET, reg_bank);
+ outb(sc->sc_port + ISAC_REG_OFFSET + (offset & ISAC_REGSET_MASK), v);
+}
+
+static void
+hscx_write_reg(int chan, u_int off, struct isic_softc *sc, int which)
+{
+ /* HACK */
+ if (off == H_MASK)
+ return;
+ /* point at the correct channel */
+ outb(sc->sc_port + ADDR_REG_OFFSET, chan);
+ if (which & 4)
+ outb(sc->sc_port + ISAC_REG_OFFSET + off + 2, sc->avma1pp_prot);
+ if (which & 2)
+ outb(sc->sc_port + ISAC_REG_OFFSET + off + 1, sc->avma1pp_txl);
+ if (which & 1)
+ outb(sc->sc_port + ISAC_REG_OFFSET + off, sc->avma1pp_cmd);
+}
+
+static void
+hscx_write_reg_val(int chan, u_int off, u_char val, struct isic_softc *sc)
+{
+ /* HACK */
+ if (off == H_MASK)
+ return;
+ /* point at the correct channel */
+ outb(sc->sc_port + ADDR_REG_OFFSET, chan);
+ outb(sc->sc_port + ISAC_REG_OFFSET + off, val);
+}
+
+/*---------------------------------------------------------------------------*
+ * AVM read register routines
+ *---------------------------------------------------------------------------*/
+
+static u_char
+avm_pnp_read_reg(u_char *base, u_int offset)
+{
+ int unit;
+ struct isic_softc *sc;
+ u_char reg_bank;
+
+ unit = (int)base & 0xff;
+ sc = &isic_sc[unit];
+
+ /* check whether the target is an HSCX */
+ if (((int)base & IS_HSCX_MASK) == HSCX0FAKE)
+ return(hscx_read_reg(0, offset, sc));
+ if (((int)base & IS_HSCX_MASK) == HSCX1FAKE)
+ return(hscx_read_reg(1, offset, sc));
+ /* must be the ISAC */
+ reg_bank = (offset > MAX_LO_REG_OFFSET) ? ISAC_HI_REG_OFFSET:ISAC_LO_REG_OFFSET;
+ /* set the register bank */
+ outb(sc->sc_port + ADDR_REG_OFFSET, reg_bank);
+ return(inb(sc->sc_port + ISAC_REG_OFFSET +
+ (offset & ISAC_REGSET_MASK)));
+}
+
+static u_char
+hscx_read_reg(int chan, u_int off, struct isic_softc *sc)
+{
+ /* HACK */
+ if (off == H_ISTA)
+ return(0);
+ /* point at the correct channel */
+ outb(sc->sc_port + ADDR_REG_OFFSET, chan);
+ return(inb(sc->sc_port + ISAC_REG_OFFSET + off));
+}
+
+/*---------------------------------------------------------------------------*
+ * isic_probe_avm_pnp - probe Fritz!Card PnP
+ *---------------------------------------------------------------------------*/
+
+int
+isic_probe_avm_pnp(struct isa_device *dev, unsigned int iobase2)
+{
+ struct isic_softc *sc = &isic_sc[dev->id_unit];
+
+ /* check max unit range */
+
+ if(dev->id_unit >= ISIC_MAXUNIT)
+ {
+ printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for AVM Fritz! PnP\n",
+ dev->id_unit, dev->id_unit);
+ return(0);
+ }
+ sc->sc_unit = dev->id_unit;
+
+ /* check IRQ validity */
+
+ switch(ffs(dev->id_irq) - 1)
+ {
+ case 3:
+ case 4:
+ case 5:
+ case 7:
+ case 10:
+ case 11:
+ case 12:
+ case 15:
+ break;
+
+ default:
+ printf("isic%d: Error, invalid IRQ [%d] specified for AVM Fritz! PnP!\n",
+ dev->id_unit, ffs(dev->id_irq)-1);
+ return(0);
+ break;
+ }
+ sc->sc_irq = dev->id_irq;
+
+ dev->id_intr = (inthand2_t *) avm_pnp_intr;
+
+ /* check if memory addr specified */
+
+ if(dev->id_maddr)
+ {
+ printf("isic%d: Error, mem addr 0x%lx specified for AVM Fritz! PnP!\n",
+ dev->id_unit, (u_long)dev->id_maddr);
+ return(0);
+ }
+ dev->id_msize = 0;
+
+ /* check if we got an iobase */
+
+ if(!((dev->id_iobase >= 0x160) && (dev->id_iobase <= 0x360)))
+ {
+ printf("isic%d: Error, invalid iobase 0x%x specified for AVM Fritz! PnP!\n",
+ dev->id_unit, dev->id_iobase);
+ return(0);
+ }
+ sc->sc_port = dev->id_iobase;
+
+
+ /* setup access routines */
+
+ sc->clearirq = NULL;
+ sc->readreg = avm_pnp_read_reg;
+ sc->writereg = avm_pnp_write_reg;
+
+ sc->readfifo = avm_pnp_read_fifo;
+ sc->writefifo = avm_pnp_write_fifo;
+
+ /* setup card type */
+
+ sc->sc_cardtyp = CARD_TYPEP_AVM_PNP;
+
+ /* setup IOM bus type */
+
+ sc->sc_bustyp = BUS_TYPE_IOM2;
+
+ sc->sc_ipac = 0;
+ sc->sc_bfifolen = HSCX_FIFO_LEN;
+
+ /* the ISAC lives at offset 0x10, but we can't use that. */
+ /* instead, put the unit number into the lower byte - HACK */
+ ISAC_BASE = (caddr_t)((int)(dev->id_iobase & ~0xff) + dev->id_unit);
+
+ outb(sc->sc_port + STAT0_OFFSET, ASL_RESET_ALL|ASL_TIMERDISABLE);
+ ISAC_WRITE(I_MASK, 0x0);
+ outb(sc->sc_port + STAT0_OFFSET, ASL_TIMERRESET|ASL_ENABLE_INT|ASL_TIMERDISABLE);
+ ISAC_WRITE(I_MASK, 0x41);
+ return (1);
+}
+
+/*---------------------------------------------------------------------------*
+ * isic_attach_avm_pnp - attach Fritz!Card PnP
+ *---------------------------------------------------------------------------*/
+int
+isic_attach_avm_pnp(struct isa_device *dev, unsigned int iobase2)
+{
+ struct isic_softc *sc;
+ u_int v;
+ int unit;
+
+ unit = dev->id_unit;
+ sc = &isic_sc[unit];
+
+ /* this thing doesn't have an HSCX, so fake the base addresses */
+ /* put the unit number into the lower byte - HACK */
+ HSCX_A_BASE = (caddr_t)(HSCX0FAKE + unit);
+ HSCX_B_BASE = (caddr_t)(HSCX1FAKE + unit);
+
+
+ /* reset the card */
+
+ /* the Linux driver does this to clear any pending ISAC interrupts */
+ v = 0;
+ v = ISAC_READ(I_STAR);
+ v = ISAC_READ(I_MODE);
+ v = ISAC_READ(I_ADF2);
+ v = ISAC_READ(I_ISTA);
+ if (v & ISAC_ISTA_EXI)
+ {
+ v = ISAC_READ(I_EXIR);
+ }
+ v = ISAC_READ(I_CIRR);
+ ISAC_WRITE(I_MASK, 0xff);
+
+ /* the Linux driver does this to clear any pending HSCX interrupts */
+ v = hscx_read_reg(0, HSCX_STAT, sc);
+ v = hscx_read_reg(0, HSCX_STAT+1, sc);
+ v = hscx_read_reg(0, HSCX_STAT+2, sc);
+ v = hscx_read_reg(0, HSCX_STAT+3, sc);
+ v = hscx_read_reg(1, HSCX_STAT, sc);
+ v = hscx_read_reg(1, HSCX_STAT+1, sc);
+ v = hscx_read_reg(1, HSCX_STAT+2, sc);
+ v = hscx_read_reg(1, HSCX_STAT+3, sc);
+
+ outb(sc->sc_port + STAT0_OFFSET, ASL_RESET_ALL|ASL_TIMERDISABLE);
+ DELAY(SEC_DELAY/100); /* 10 ms */
+ outb(sc->sc_port + STAT0_OFFSET, ASL_TIMERRESET|ASL_ENABLE_INT|ASL_TIMERDISABLE);
+ DELAY(SEC_DELAY/100); /* 10 ms */
+ outb(sc->sc_port + STAT1_OFFSET, ASL1_ENABLE_IOM+(ffs(sc->sc_irq)-1));
+ DELAY(SEC_DELAY/100); /* 10 ms */
+
+ printf("isic%d: ISAC %s (IOM-%c)\n", unit,
+ "2085 Version A1/A2 or 2086/2186 Version 1.1",
+ sc->sc_bustyp == BUS_TYPE_IOM1 ? '1' : '2');
+
+ /* init the ISAC */
+ isic_isac_init(sc);
+
+ /* init the "HSCX" */
+ avm_pnp_bchannel_setup(sc->sc_unit, HSCX_CH_A, BPROT_NONE, 0);
+
+ avm_pnp_bchannel_setup(sc->sc_unit, HSCX_CH_B, BPROT_NONE, 0);
+
+ /* can't use the normal B-Channel stuff */
+ avm_pnp_init_linktab(sc);
+
+ /* set trace level */
+
+ sc->sc_trace = TRACE_OFF;
+
+ sc->sc_state = ISAC_IDLE;
+
+ sc->sc_ibuf = NULL;
+ sc->sc_ib = NULL;
+ sc->sc_ilen = 0;
+
+ sc->sc_obuf = NULL;
+ sc->sc_op = NULL;
+ sc->sc_ol = 0;
+ sc->sc_freeflag = 0;
+
+ sc->sc_obuf2 = NULL;
+ sc->sc_freeflag2 = 0;
+
+#if defined(__FreeBSD__) && __FreeBSD__ >=3
+ callout_handle_init(&sc->sc_T3_callout);
+ callout_handle_init(&sc->sc_T4_callout);
+#endif
+
+ /* init higher protocol layers */
+
+ MPH_Status_Ind(sc->sc_unit, STI_ATTACH, sc->sc_cardtyp);
+
+ return(0);
+}
+
+/*
+ * this is the real interrupt routine
+ */
+static void
+avm_pnp_hscx_intr(int h_chan, int stat, int cnt, struct isic_softc *sc)
+{
+ register isic_Bchan_t *chan = &sc->sc_chan[h_chan];
+ int activity = -1;
+
+ DBGL1(L1_H_IRQ, "avm_pnp_hscx_intr", ("%#x\n", stat));
+
+ if((stat & HSCX_INT_XDU) && (chan->bprot != BPROT_NONE))/* xmit data underrun */
+ {
+ chan->stat_XDU++;
+ DBGL1(L1_H_XFRERR, "avm_pnp_hscx_intr", ("xmit data underrun\n"));
+ /* abort the transmission */
+ sc->avma1pp_txl = 0;
+ sc->avma1pp_cmd |= HSCX_CMD_XRS;
+ hscx_write_reg(h_chan, HSCX_STAT, sc, 1);
+ sc->avma1pp_cmd &= ~HSCX_CMD_XRS;
+ hscx_write_reg(h_chan, HSCX_STAT, sc, 1);
+
+ if (chan->out_mbuf_head != NULL) /* don't continue to transmit this buffer */
+ {
+ i4b_Bfreembuf(chan->out_mbuf_head);
+ chan->out_mbuf_cur = chan->out_mbuf_head = NULL;
+ }
+ }
+
+ /*
+ * The following is based on examination of the Linux driver.
+ *
+ * The logic here is different than with a "real" HSCX; all kinds
+ * of information (interrupt/status bits) are in stat.
+ * HSCX_INT_RPR indicates a receive interrupt
+ * HSCX_STAT_RDO indicates an overrun condition, abort -
+ * otherwise read the bytes ((stat & HSCX_STZT_RML_MASK) >> 8)
+ * HSCX_STAT_RME indicates end-of-frame and apparently any
+ * CRC/framing errors are only reported in this state.
+ * if ((stat & HSCX_STAT_CRCVFRRAB) != HSCX_STAT_CRCVFR)
+ * CRC/framing error
+ */
+
+ if(stat & HSCX_INT_RPR)
+ {
+ register int fifo_data_len;
+ int error = 0;
+ /* always have to read the FIFO, so use a scratch buffer */
+ u_char scrbuf[HSCX_FIFO_LEN];
+
+ if(stat & HSCX_STAT_RDO)
+ {
+ chan->stat_RDO++;
+ DBGL1(L1_H_XFRERR, "avm_pnp_hscx_intr", ("receive data overflow\n"));
+ error++;
+ }
+
+ fifo_data_len = cnt;
+
+ if(fifo_data_len == 0)
+ fifo_data_len = sc->sc_bfifolen;
+
+ /* ALWAYS read data from HSCX fifo */
+
+ HSCX_RDFIFO(h_chan, scrbuf, fifo_data_len);
+ chan->rxcount += fifo_data_len;
+
+ /* all error conditions checked, now decide and take action */
+
+ if(error == 0)
+ {
+ if(chan->in_mbuf == NULL)
+ {
+ if((chan->in_mbuf = i4b_Bgetmbuf(BCH_MAX_DATALEN)) == NULL)
+ panic("L1 avm_pnp_hscx_intr: RME, cannot allocate mbuf!\n");
+ chan->in_cbptr = chan->in_mbuf->m_data;
+ chan->in_len = 0;
+ }
+
+ if((chan->in_len + fifo_data_len) <= BCH_MAX_DATALEN)
+ {
+ /* OK to copy the data */
+ bcopy(scrbuf, chan->in_cbptr, fifo_data_len);
+ chan->in_cbptr += fifo_data_len;
+ chan->in_len += fifo_data_len;
+
+ /* setup mbuf data length */
+
+ chan->in_mbuf->m_len = chan->in_len;
+ chan->in_mbuf->m_pkthdr.len = chan->in_len;
+
+
+ if(sc->sc_trace & TRACE_B_RX)
+ {
+ i4b_trace_hdr_t hdr;
+ hdr.unit = sc->sc_unit;
+ hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2);
+ hdr.dir = FROM_NT;
+ hdr.count = ++sc->sc_trace_bcount;
+ MICROTIME(hdr.time);
+ MPH_Trace_Ind(&hdr, chan->in_mbuf->m_len, chan->in_mbuf->m_data);
+ }
+
+ if (stat & HSCX_STAT_RME)
+ {
+ if((stat & HSCX_STAT_CRCVFRRAB) == HSCX_STAT_CRCVFR)
+ {
+ (*chan->drvr_linktab->bch_rx_data_ready)(chan->drvr_linktab->unit);
+ activity = ACT_RX;
+
+ /* mark buffer ptr as unused */
+
+ chan->in_mbuf = NULL;
+ chan->in_cbptr = NULL;
+ chan->in_len = 0;
+ }
+ else
+ {
+ chan->stat_CRC++;
+ DBGL1(L1_H_XFRERR, "avm_pnp_hscx_intr", ("CRC/RAB\n"));
+ if (chan->in_mbuf != NULL)
+ {
+ i4b_Bfreembuf(chan->in_mbuf);
+ chan->in_mbuf = NULL;
+ chan->in_cbptr = NULL;
+ chan->in_len = 0;
+ }
+ }
+ }
+ } /* END enough space in mbuf */
+ else
+ {
+ if(chan->bprot == BPROT_NONE)
+ {
+ /* setup mbuf data length */
+
+ chan->in_mbuf->m_len = chan->in_len;
+ chan->in_mbuf->m_pkthdr.len = chan->in_len;
+
+ if(sc->sc_trace & TRACE_B_RX)
+ {
+ i4b_trace_hdr_t hdr;
+ hdr.unit = sc->sc_unit;
+ hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2);
+ hdr.dir = FROM_NT;
+ hdr.count = ++sc->sc_trace_bcount;
+ MICROTIME(hdr.time);
+ MPH_Trace_Ind(&hdr, chan->in_mbuf->m_len, chan->in_mbuf->m_data);
+ }
+
+ /* move rx'd data to rx queue */
+
+ IF_ENQUEUE(&chan->rx_queue, chan->in_mbuf);
+
+ (*chan->drvr_linktab->bch_rx_data_ready)(chan->drvr_linktab->unit);
+
+ if(!(isic_hscx_silence(chan->in_mbuf->m_data, chan->in_mbuf->m_len)))
+ activity = ACT_RX;
+
+ /* alloc new buffer */
+
+ if((chan->in_mbuf = i4b_Bgetmbuf(BCH_MAX_DATALEN)) == NULL)
+ panic("L1 avm_pnp_hscx_intr: RPF, cannot allocate new mbuf!\n");
+
+ /* setup new data ptr */
+
+ chan->in_cbptr = chan->in_mbuf->m_data;
+
+ /* OK to copy the data */
+ bcopy(scrbuf, chan->in_cbptr, fifo_data_len);
+
+ chan->in_cbptr += fifo_data_len;
+ chan->in_len = fifo_data_len;
+
+ chan->rxcount += fifo_data_len;
+ }
+ else
+ {
+ DBGL1(L1_H_XFRERR, "avm_pnp_hscx_intr", ("RAWHDLC rx buffer overflow in RPF, in_len=%d\n", chan->in_len));
+ chan->in_cbptr = chan->in_mbuf->m_data;
+ chan->in_len = 0;
+ }
+ }
+ } /* if(error == 0) */
+ else
+ {
+ /* land here for RDO */
+ if (chan->in_mbuf != NULL)
+ {
+ i4b_Bfreembuf(chan->in_mbuf);
+ chan->in_mbuf = NULL;
+ chan->in_cbptr = NULL;
+ chan->in_len = 0;
+ }
+ sc->avma1pp_txl = 0;
+ sc->avma1pp_cmd |= HSCX_CMD_RRS;
+ hscx_write_reg(h_chan, HSCX_STAT, sc, 1);
+ sc->avma1pp_cmd &= ~HSCX_CMD_RRS;
+ hscx_write_reg(h_chan, HSCX_STAT, sc, 1);
+ }
+ }
+
+
+ /* transmit fifo empty, new data can be written to fifo */
+
+ if(stat & HSCX_INT_XPR)
+ {
+ /*
+ * for a description what is going on here, please have
+ * a look at isic_bchannel_start() in i4b_bchan.c !
+ */
+
+ DBGL1(L1_H_IRQ, "avm_pnp_hscx_intr", ("unit %d, chan %d - XPR, Tx Fifo Empty!\n", sc->sc_unit, h_chan));
+
+ if(chan->out_mbuf_cur == NULL || chan->out_mbuf_head == NULL) /* last frame is transmitted */
+ {
+ IF_DEQUEUE(&chan->tx_queue, chan->out_mbuf_head);
+
+ if(chan->out_mbuf_head == NULL)
+ {
+ chan->state &= ~HSCX_TX_ACTIVE;
+ (*chan->drvr_linktab->bch_tx_queue_empty)(chan->drvr_linktab->unit);
+ }
+ else
+ {
+ chan->state |= HSCX_TX_ACTIVE;
+ chan->out_mbuf_cur = chan->out_mbuf_head;
+ chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data;
+ chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len;
+
+ if(sc->sc_trace & TRACE_B_TX)
+ {
+ i4b_trace_hdr_t hdr;
+ hdr.unit = sc->sc_unit;
+ hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2);
+ hdr.dir = FROM_TE;
+ hdr.count = ++sc->sc_trace_bcount;
+ MICROTIME(hdr.time);
+ MPH_Trace_Ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data);
+ }
+ if(chan->bprot == BPROT_NONE)
+ {
+ if(!(isic_hscx_silence(chan->out_mbuf_cur->m_data, chan->out_mbuf_cur->m_len)))
+ activity = ACT_TX;
+ }
+ else
+ {
+ activity = ACT_TX;
+ }
+ }
+ }
+
+ isic_hscx_fifo(chan, sc);
+ }
+
+ /* call timeout handling routine */
+
+ if(activity == ACT_RX || activity == ACT_TX)
+ (*chan->drvr_linktab->bch_activity)(chan->drvr_linktab->unit, activity);
+}
+
+/*
+ * this is the main routine which checks each channel and then calls
+ * the real interrupt routine as appropriate
+ */
+static void
+avm_pnp_hscx_int_handler(struct isic_softc *sc)
+{
+ u_char stat = 0;
+ u_char cnt = 0;
+
+ stat = hscx_read_reg(0, HSCX_STAT, sc);
+ if (stat & HSCX_INT_RPR)
+ cnt = hscx_read_reg(0, HSCX_STAT+1, sc);
+ if (stat & HSCX_INT_MASK)
+ avm_pnp_hscx_intr(0, stat, cnt, sc);
+
+ cnt = 0;
+ stat = hscx_read_reg(1, HSCX_STAT, sc);
+ if (stat & HSCX_INT_RPR)
+ cnt = hscx_read_reg(1, HSCX_STAT+1, sc);
+ if (stat & HSCX_INT_MASK)
+ avm_pnp_hscx_intr(1, stat, cnt, sc);
+}
+
+static void
+avm_pnp_hscx_init(struct isic_softc *sc, int h_chan, int activate)
+{
+ isic_Bchan_t *chan = &sc->sc_chan[h_chan];
+
+ DBGL1(L1_BCHAN, "avm_pnp_hscx_init", ("unit=%d, channel=%d, %s\n",
+ sc->sc_unit, h_chan, activate ? "activate" : "deactivate"));
+
+ if (activate == 0)
+ {
+ /* only deactivate if both channels are idle */
+ if (sc->sc_chan[HSCX_CH_A].state != HSCX_IDLE ||
+ sc->sc_chan[HSCX_CH_B].state != HSCX_IDLE)
+ {
+ return;
+ }
+ sc->avma1pp_cmd = HSCX_CMD_XRS|HSCX_CMD_RRS;
+ sc->avma1pp_prot = HSCX_MODE_TRANS;
+ hscx_write_reg(h_chan, HSCX_STAT, sc, 5);
+ return;
+ }
+ if(chan->bprot == BPROT_RHDLC)
+ {
+ DBGL1(L1_BCHAN, "avm_pnp_hscx_init", ("BPROT_RHDLC\n"));
+
+ /* HDLC Frames, transparent mode 0 */
+ sc->avma1pp_cmd = HSCX_CMD_XRS|HSCX_CMD_RRS;
+ sc->avma1pp_prot = HSCX_MODE_ITF_FLG;
+ hscx_write_reg(h_chan, HSCX_STAT, sc, 5);
+ sc->avma1pp_cmd = HSCX_CMD_XRS;
+ hscx_write_reg(h_chan, HSCX_STAT, sc, 1);
+ sc->avma1pp_cmd = 0;
+ }
+ else
+ {
+ DBGL1(L1_BCHAN, "avm_pnp_hscx_init", ("BPROT_NONE??\n"));
+
+ /* Raw Telephony, extended transparent mode 1 */
+ sc->avma1pp_cmd = HSCX_CMD_XRS|HSCX_CMD_RRS;
+ sc->avma1pp_prot = HSCX_MODE_TRANS;
+ hscx_write_reg(h_chan, HSCX_STAT, sc, 5);
+ sc->avma1pp_cmd = HSCX_CMD_XRS;
+ hscx_write_reg(h_chan, HSCX_STAT, sc, 1);
+ sc->avma1pp_cmd = 0;
+ }
+}
+
+static void
+avm_pnp_bchannel_setup(int unit, int h_chan, int bprot, int activate)
+{
+ struct isic_softc *sc = &isic_sc[unit];
+ isic_Bchan_t *chan = &sc->sc_chan[h_chan];
+
+ int s = SPLI4B();
+
+ if(activate == 0)
+ {
+ /* deactivation */
+ chan->state &= ~HSCX_AVMPNP_ACTIVE;
+ avm_pnp_hscx_init(sc, h_chan, activate);
+ }
+
+ DBGL1(L1_BCHAN, "avm_pnp_bchannel_setup", ("unit=%d, channel=%d, %s\n",
+ sc->sc_unit, h_chan, activate ? "activate" : "deactivate"));
+
+ /* general part */
+
+ chan->unit = sc->sc_unit; /* unit number */
+ chan->channel = h_chan; /* B channel */
+ chan->bprot = bprot; /* B channel protocol */
+ chan->state = HSCX_IDLE; /* B channel state */
+
+ /* receiver part */
+
+ i4b_Bcleanifq(&chan->rx_queue); /* clean rx queue */
+
+ chan->rx_queue.ifq_maxlen = IFQ_MAXLEN;
+
+ chan->rxcount = 0; /* reset rx counter */
+
+ i4b_Bfreembuf(chan->in_mbuf); /* clean rx mbuf */
+
+ chan->in_mbuf = NULL; /* reset mbuf ptr */
+ chan->in_cbptr = NULL; /* reset mbuf curr ptr */
+ chan->in_len = 0; /* reset mbuf data len */
+
+ /* transmitter part */
+
+ i4b_Bcleanifq(&chan->tx_queue); /* clean tx queue */
+
+ chan->tx_queue.ifq_maxlen = IFQ_MAXLEN;
+
+ chan->txcount = 0; /* reset tx counter */
+
+ i4b_Bfreembuf(chan->out_mbuf_head); /* clean tx mbuf */
+
+ chan->out_mbuf_head = NULL; /* reset head mbuf ptr */
+ chan->out_mbuf_cur = NULL; /* reset current mbuf ptr */
+ chan->out_mbuf_cur_ptr = NULL; /* reset current mbuf data ptr */
+ chan->out_mbuf_cur_len = 0; /* reset current mbuf data cnt */
+
+ if(activate != 0)
+ {
+ /* activation */
+ avm_pnp_hscx_init(sc, h_chan, activate);
+ chan->state |= HSCX_AVMPNP_ACTIVE;
+ }
+
+ splx(s);
+}
+
+static void
+avm_pnp_bchannel_start(int unit, int h_chan)
+{
+ struct isic_softc *sc = &isic_sc[unit];
+ register isic_Bchan_t *chan = &sc->sc_chan[h_chan];
+ int s;
+ int activity = -1;
+
+ s = SPLI4B(); /* enter critical section */
+ if(chan->state & HSCX_TX_ACTIVE) /* already running ? */
+ {
+ splx(s);
+ return; /* yes, leave */
+ }
+
+ /* get next mbuf from queue */
+
+ IF_DEQUEUE(&chan->tx_queue, chan->out_mbuf_head);
+
+ if(chan->out_mbuf_head == NULL) /* queue empty ? */
+ {
+ splx(s); /* leave critical section */
+ return; /* yes, exit */
+ }
+
+ /* init current mbuf values */
+
+ chan->out_mbuf_cur = chan->out_mbuf_head;
+ chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len;
+ chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data;
+
+ /* activity indicator for timeout handling */
+
+ if(chan->bprot == BPROT_NONE)
+ {
+ if(!(isic_hscx_silence(chan->out_mbuf_cur->m_data, chan->out_mbuf_cur->m_len)))
+ activity = ACT_TX;
+ }
+ else
+ {
+ activity = ACT_TX;
+ }
+
+ chan->state |= HSCX_TX_ACTIVE; /* we start transmitting */
+
+ if(sc->sc_trace & TRACE_B_TX) /* if trace, send mbuf to trace dev */
+ {
+ i4b_trace_hdr_t hdr;
+ hdr.unit = unit;
+ hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2);
+ hdr.dir = FROM_TE;
+ hdr.count = ++sc->sc_trace_bcount;
+ MICROTIME(hdr.time);
+ MPH_Trace_Ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data);
+ }
+
+ isic_hscx_fifo(chan, sc);
+
+ /* call timeout handling routine */
+
+ if(activity == ACT_RX || activity == ACT_TX)
+ (*chan->drvr_linktab->bch_activity)(chan->drvr_linktab->unit, activity);
+
+ splx(s);
+}
+
+/*---------------------------------------------------------------------------*
+ * return the address of isic drivers linktab
+ *---------------------------------------------------------------------------*/
+static isdn_link_t *
+avm_pnp_ret_linktab(int unit, int channel)
+{
+ struct isic_softc *sc = &isic_sc[unit];
+ isic_Bchan_t *chan = &sc->sc_chan[channel];
+
+ return(&chan->isdn_linktab);
+}
+
+/*---------------------------------------------------------------------------*
+ * set the driver linktab in the b channel softc
+ *---------------------------------------------------------------------------*/
+static void
+avm_pnp_set_linktab(int unit, int channel, drvr_link_t *dlt)
+{
+ struct isic_softc *sc = &isic_sc[unit];
+ isic_Bchan_t *chan = &sc->sc_chan[channel];
+
+ chan->drvr_linktab = dlt;
+}
+
+
+/*---------------------------------------------------------------------------*
+ * initialize our local linktab
+ *---------------------------------------------------------------------------*/
+static void
+avm_pnp_init_linktab(struct isic_softc *sc)
+{
+ isic_Bchan_t *chan = &sc->sc_chan[HSCX_CH_A];
+ isdn_link_t *lt = &chan->isdn_linktab;
+
+ /* make sure the hardware driver is known to layer 4 */
+ /* avoid overwriting if already set */
+ if (ctrl_types[CTRL_PASSIVE].set_linktab == NULL)
+ {
+ ctrl_types[CTRL_PASSIVE].set_linktab = avm_pnp_set_linktab;
+ ctrl_types[CTRL_PASSIVE].get_linktab = avm_pnp_ret_linktab;
+ }
+
+ /* local setup */
+ lt->unit = sc->sc_unit;
+ lt->channel = HSCX_CH_A;
+ lt->bch_config = avm_pnp_bchannel_setup;
+ lt->bch_tx_start = avm_pnp_bchannel_start;
+ lt->bch_stat = avm_pnp_bchannel_stat;
+ lt->tx_queue = &chan->tx_queue;
+
+ /* used by non-HDLC data transfers, i.e. telephony drivers */
+ lt->rx_queue = &chan->rx_queue;
+
+ /* used by HDLC data transfers, i.e. ipr and isp drivers */
+ lt->rx_mbuf = &chan->in_mbuf;
+
+ chan = &sc->sc_chan[HSCX_CH_B];
+ lt = &chan->isdn_linktab;
+
+ lt->unit = sc->sc_unit;
+ lt->channel = HSCX_CH_B;
+ lt->bch_config = avm_pnp_bchannel_setup;
+ lt->bch_tx_start = avm_pnp_bchannel_start;
+ lt->bch_stat = avm_pnp_bchannel_stat;
+ lt->tx_queue = &chan->tx_queue;
+
+ /* used by non-HDLC data transfers, i.e. telephony drivers */
+ lt->rx_queue = &chan->rx_queue;
+
+ /* used by HDLC data transfers, i.e. ipr and isp drivers */
+ lt->rx_mbuf = &chan->in_mbuf;
+}
+
+/*
+ * use this instead of isic_bchannel_stat in i4b_bchan.c because it's static
+ */
+static void
+avm_pnp_bchannel_stat(int unit, int h_chan, bchan_statistics_t *bsp)
+{
+ struct isic_softc *sc = &isic_sc[unit];
+ isic_Bchan_t *chan = &sc->sc_chan[h_chan];
+ int s;
+
+ s = SPLI4B();
+
+ bsp->outbytes = chan->txcount;
+ bsp->inbytes = chan->rxcount;
+
+ chan->txcount = 0;
+ chan->rxcount = 0;
+
+ splx(s);
+}
+
+/*---------------------------------------------------------------------------*
+ * fill HSCX fifo with data from the current mbuf
+ * Put this here until it can go into i4b_hscx.c
+ *---------------------------------------------------------------------------*/
+static int
+isic_hscx_fifo(isic_Bchan_t *chan, struct isic_softc *sc)
+{
+ int len;
+ int nextlen;
+ int i;
+ /* using a scratch buffer simplifies writing to the FIFO */
+ u_char scrbuf[HSCX_FIFO_LEN];
+
+ len = 0;
+
+ /*
+ * fill the HSCX tx fifo with data from the current mbuf. if
+ * current mbuf holds less data than HSCX fifo length, try to
+ * get the next mbuf from (a possible) mbuf chain. if there is
+ * not enough data in a single mbuf or in a chain, then this
+ * is the last mbuf and we tell the HSCX that it has to send
+ * CRC and closing flag
+ */
+
+ while(chan->out_mbuf_cur && len != sc->sc_bfifolen)
+ {
+ nextlen = min(chan->out_mbuf_cur_len, sc->sc_bfifolen - len);
+
+#ifdef NOTDEF
+ printf("i:mh=%p, mc=%p, mcp=%p, mcl=%d l=%d nl=%d # ",
+ chan->out_mbuf_head,
+ chan->out_mbuf_cur,
+ chan->out_mbuf_cur_ptr,
+ chan->out_mbuf_cur_len,
+ len,
+ nextlen);
+#endif
+
+ /* collect the data in the scratch buffer */
+ for (i = 0; i < nextlen; i++)
+ scrbuf[i + len] = chan->out_mbuf_cur_ptr[i];
+
+ len += nextlen;
+ chan->txcount += nextlen;
+
+ chan->out_mbuf_cur_ptr += nextlen;
+ chan->out_mbuf_cur_len -= nextlen;
+
+ if(chan->out_mbuf_cur_len == 0)
+ {
+ if((chan->out_mbuf_cur = chan->out_mbuf_cur->m_next) != NULL)
+ {
+ chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data;
+ chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len;
+
+ if(sc->sc_trace & TRACE_B_TX)
+ {
+ i4b_trace_hdr_t hdr;
+ hdr.unit = sc->sc_unit;
+ hdr.type = (chan->channel == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2);
+ hdr.dir = FROM_TE;
+ hdr.count = ++sc->sc_trace_bcount;
+ MICROTIME(hdr.time);
+ MPH_Trace_Ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data);
+ }
+ }
+ else
+ {
+ i4b_Bfreembuf(chan->out_mbuf_head);
+ chan->out_mbuf_head = NULL;
+ }
+ }
+ }
+ /* write what we have from the scratch buf to the HSCX fifo */
+ if (len != 0)
+ HSCX_WRFIFO(chan->channel, scrbuf, len);
+
+ return(0);
+}
+
+void
+avm_pnp_intr(int unit)
+{
+ struct isic_softc *sc;
+ u_char stat;
+ register u_char isac_irq_stat;
+ int was_isac = 0;
+
+ sc = &isic_sc[unit];
+
+ for(;;) {
+ stat = inb(sc->sc_port + STAT0_OFFSET);
+
+ DBGL1(L1_H_IRQ, "avm_pnp_intr", ("stat %x\n", stat));
+
+ /* was there an interrupt from this card ? */
+ if ((stat & ASL_IRQ_Pending) == ASL_IRQ_Pending)
+ break; /* no */
+
+ /* interrupts are low active */
+ if (!(stat & ASL_IRQ_TIMER))
+ DBGL1(L1_H_IRQ, "avm_pnp_intr", ("timer interrupt ???\n"));
+
+ if (!(stat & ASL_IRQ_ISAC))
+ {
+ DBGL1(L1_H_IRQ, "avm_pnp_intr", ("ISAC\n"));
+ isac_irq_stat = ISAC_READ(I_ISTA);
+ isic_isac_irq(sc, isac_irq_stat);
+ was_isac = 1;
+ }
+
+ if (!(stat & ASL_IRQ_HSCX))
+ {
+ DBGL1(L1_H_IRQ, "avm_pnp_intr", ("HSCX\n"));
+ avm_pnp_hscx_int_handler(sc);
+ }
+ }
+ if (was_isac) {
+ ISAC_WRITE(0x20, 0xFF);
+ ISAC_WRITE(0x20, 0x0);
+ }
+}
+#endif /* NISIC > 0 && defined(AVM_PNP) */
+#endif /* FreeBSD */
diff --git a/sys/i4b/layer1/i4b_siemens_isurf.c b/sys/i4b/layer1/i4b_siemens_isurf.c
new file mode 100644
index 000000000000..ed48a66d53e6
--- /dev/null
+++ b/sys/i4b/layer1/i4b_siemens_isurf.c
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 1999 Udo Schweigert. 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. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 4. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software and/or documentation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ * Based on ELSA Quickstep 1000pro PCI driver (i4b_elsa_qs1p.c)
+ *---------------------------------------------------------------------------
+ * In case of trouble please contact Udo Schweigert <ust@cert.siemens.de>
+ *---------------------------------------------------------------------------
+ *
+ * Siemens I-Surf 2.0 PnP specific routines for isic driver
+ * --------------------------------------------------------
+ *
+ * $FreeBSD$
+ *
+ * last edit-date: [Mon 14 Jun 16:46:27 CEST 1999]
+ *
+ *---------------------------------------------------------------------------*/
+
+#if defined(__FreeBSD__)
+#include "isic.h"
+#include "opt_i4b.h"
+
+#if NISIC > 0 && defined(SIEMENS_ISURF2)
+
+#include <sys/param.h>
+#if defined(__FreeBSD__) && __FreeBSD__ >= 3
+#include <sys/ioccom.h>
+#else
+#include <sys/ioctl.h>
+#endif
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+
+#include <machine/clock.h>
+#include <i386/isa/isa_device.h>
+
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include <machine/i4b_debug.h>
+#include <machine/i4b_ioctl.h>
+
+#include <i4b/include/i4b_global.h>
+#include <i4b/include/i4b_l1l2.h>
+#include <i4b/include/i4b_mbuf.h>
+
+#include <i4b/layer1/i4b_l1.h>
+#include <i4b/layer1/i4b_ipac.h>
+#include <i4b/layer1/i4b_isac.h>
+#include <i4b/layer1/i4b_hscx.h>
+
+/* masks for register encoded in base addr */
+
+#define SIE_ISURF_BASE_MASK 0x0ffff
+#define SIE_ISURF_OFF_MASK 0xf0000
+
+/* register id's to be encoded in base addr */
+
+#define SIE_ISURF_IDISAC 0x00000
+#define SIE_ISURF_IDHSCXA 0x10000
+#define SIE_ISURF_IDHSCXB 0x20000
+#define SIE_ISURF_IDIPAC 0x40000
+
+/* offsets from base address */
+
+#define SIE_ISURF_OFF_ALE 0x00
+#define SIE_ISURF_OFF_RW 0x01
+
+/*---------------------------------------------------------------------------*
+ * Siemens I-Surf 2.0 PnP ISAC get fifo routine
+ *---------------------------------------------------------------------------*/
+
+static void
+siemens_isurf_read_fifo(void *buf, const void *base, size_t len)
+{
+ if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDHSCXB)
+ {
+ outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, IPAC_HSCXB_OFF);
+ insb((((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW), (u_char *)buf, (u_int)len);
+ }
+ else if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDHSCXA)
+ {
+ outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, IPAC_HSCXA_OFF);
+ insb((((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW), (u_char *)buf, (u_int)len);
+ }
+ else /* if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDISAC) */
+ {
+ outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, IPAC_ISAC_OFF);
+ insb((((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW), (u_char *)buf, (u_int)len);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * Siemens I-Surf 2.0 PnP ISAC put fifo routine
+ *---------------------------------------------------------------------------*/
+
+static void
+siemens_isurf_write_fifo(void *base, const void *buf, size_t len)
+{
+ if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDHSCXB)
+ {
+ outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, IPAC_HSCXB_OFF);
+ outsb((((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW), (const u_char *)buf, (u_int)len);
+ }
+ else if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDHSCXA)
+ {
+ outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, IPAC_HSCXA_OFF);
+ outsb((((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW), (const u_char *)buf, (u_int)len);
+ }
+ else /* if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDISAC) */
+ {
+ outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, IPAC_ISAC_OFF);
+ outsb((((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW), (const u_char *)buf, (u_int)len);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * Siemens I-Surf 2.0 PnP ISAC put register routine
+ *---------------------------------------------------------------------------*/
+
+static void
+siemens_isurf_write_reg(u_char *base, u_int offset, u_int v)
+{
+ if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDHSCXB)
+ {
+ outb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, (u_char)(offset+IPAC_HSCXB_OFF));
+ outb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW, (u_char)v);
+ }
+ else if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDHSCXA)
+ {
+ outb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, (u_char)(offset+IPAC_HSCXA_OFF));
+ outb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW, (u_char)v);
+ }
+ else if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDISAC)
+ {
+ outb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, (u_char)(offset+IPAC_ISAC_OFF));
+ outb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW, (u_char)v);
+ }
+ else /* IPAC */
+ {
+ outb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, (u_char)(offset+IPAC_IPAC_OFF));
+ outb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW, (u_char)v);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * Siemens I-Surf 2.0 PnP ISAC get register routine
+ *---------------------------------------------------------------------------*/
+
+static u_char
+siemens_isurf_read_reg(u_char *base, u_int offset)
+{
+ if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDHSCXB)
+ {
+ outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, (u_char)(offset+IPAC_HSCXB_OFF));
+ return(inb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW));
+ }
+ else if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDHSCXA)
+ {
+ outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, (u_char)(offset+IPAC_HSCXA_OFF));
+ return(inb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW));
+ }
+ else if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDISAC)
+ {
+ outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, (u_char)(offset+IPAC_ISAC_OFF));
+ return(inb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW));
+ }
+ else /* IPAC */
+ {
+ outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, (u_char)(offset+IPAC_IPAC_OFF));
+ return(inb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW));
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * isic_probe_siemens_isurf - probe for Siemens I-Surf 2.0 PnP
+ *---------------------------------------------------------------------------*/
+
+int
+isic_probe_siemens_isurf(struct isa_device *dev, unsigned int iobase2)
+{
+ struct isic_softc *sc = &isic_sc[dev->id_unit];
+
+ /* check max unit range */
+
+ if(dev->id_unit >= ISIC_MAXUNIT)
+ {
+ printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for Siemens I-Surf 2.0 PnP\n",
+ dev->id_unit, dev->id_unit);
+ return(0);
+ }
+ sc->sc_unit = dev->id_unit;
+
+ /* check IRQ validity */
+
+ switch(ffs(dev->id_irq) - 1)
+ {
+ case 3:
+ case 4:
+ case 5:
+ case 7:
+ case 10:
+ case 11:
+ case 12:
+ case 15:
+ break;
+
+ default:
+ printf("isic%d: Error, invalid IRQ [%d] specified for Siemens I-Surf 2.0 PnP!\n",
+ dev->id_unit, ffs(dev->id_irq)-1);
+ return(0);
+ break;
+ }
+ sc->sc_irq = dev->id_irq;
+
+ /* check if memory addr specified */
+
+ if(dev->id_maddr)
+ {
+ printf("isic%d: Error, mem addr 0x%lx specified for Siemens I-Surf 2.0 PnP!\n",
+ dev->id_unit, (u_long)dev->id_maddr);
+ return(0);
+ }
+ dev->id_msize = 0;
+
+ /* check if we got an iobase */
+
+ if(!((dev->id_iobase >= 0x100) && (dev->id_iobase <= 0xff0)))
+ {
+ printf("isic%d: Error, invalid iobase 0x%x specified for Siemens I-Surf 2.0 PnP!\n",
+ dev->id_unit, dev->id_iobase);
+ return(0);
+ }
+ sc->sc_port = dev->id_iobase;
+
+
+ /* setup access routines */
+
+ sc->clearirq = NULL;
+ sc->readreg = siemens_isurf_read_reg;
+ sc->writereg = siemens_isurf_write_reg;
+
+ sc->readfifo = siemens_isurf_read_fifo;
+ sc->writefifo = siemens_isurf_write_fifo;
+
+ /* setup card type */
+
+ sc->sc_cardtyp = CARD_TYPEP_SIE_ISURF2;
+
+ /* setup IOM bus type */
+
+ sc->sc_bustyp = BUS_TYPE_IOM2;
+
+ /* setup chip type = IPAC ! */
+
+ sc->sc_ipac = 1;
+ sc->sc_bfifolen = IPAC_BFIFO_LEN;
+
+
+ return (1);
+}
+
+/*---------------------------------------------------------------------------*
+ * isic_attach_siemens_isurf - attach for Siemens I-Surf 2.0 PnP
+ *---------------------------------------------------------------------------*/
+int
+isic_attach_siemens_isurf(struct isa_device *dev, unsigned int iobase2)
+{
+ struct isic_softc *sc = &isic_sc[dev->id_unit];
+
+ /* setup ISAC and HSCX base addr */
+
+ ISAC_BASE = (caddr_t) ((u_int)sc->sc_port | SIE_ISURF_IDISAC);
+ HSCX_A_BASE = (caddr_t) ((u_int)sc->sc_port | SIE_ISURF_IDHSCXA);
+ HSCX_B_BASE = (caddr_t) ((u_int)sc->sc_port | SIE_ISURF_IDHSCXB);
+ IPAC_BASE = (caddr_t) ((u_int)sc->sc_port | SIE_ISURF_IDIPAC);
+
+ /* enable hscx/isac irq's */
+ IPAC_WRITE(IPAC_MASK, (IPAC_MASK_INT1 | IPAC_MASK_INT0));
+
+ IPAC_WRITE(IPAC_ACFG, 0); /* outputs are open drain */
+ IPAC_WRITE(IPAC_AOE, /* aux 5..2 are inputs, 7, 6 outputs */
+ (IPAC_AOE_OE5 | IPAC_AOE_OE4 | IPAC_AOE_OE3 | IPAC_AOE_OE2));
+ IPAC_WRITE(IPAC_ATX, 0xff); /* set all output lines high */
+
+ return(1);
+}
+#endif /* NISIC > 0 && defined(SIEMENS_ISURF2) */
+#endif /* FreeBSD */
diff --git a/sys/i4b/layer1/pci_isic.h b/sys/i4b/layer1/pci_isic.h
new file mode 100644
index 000000000000..a19025c8aaf0
--- /dev/null
+++ b/sys/i4b/layer1/pci_isic.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1999 Martin Husemann. 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. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 4. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software and/or documentation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * pci_isic.h - pci bus frontend for i4b_isic driver
+ * -------------------------------------------------
+ *
+ * $FreeBSD$
+ *
+ * last edit-date: [Wed Mar 10 07:22:08 1999]
+ *
+ * -mh original implementation
+ *
+ *---------------------------------------------------------------------------*/
+
+struct pci_isic_softc {
+ struct isic_softc sc_isic; /* parent class */
+
+ /* PCI-specific goo */
+ void *sc_ih; /* interrupt handler */
+};
+
+extern void isic_attach_Eqs1pp __P((struct pci_isic_softc *psc, struct pci_attach_args *pa));
+extern void isic_attach_fritzPci __P((struct pci_isic_softc *psc, struct pci_attach_args *pa));
+
diff --git a/sys/pci/alpm.c b/sys/pci/alpm.c
new file mode 100644
index 000000000000..ff4c5d3fb435
--- /dev/null
+++ b/sys/pci/alpm.c
@@ -0,0 +1,666 @@
+/*-
+ * Copyright (c) 1998, 1999 Nicolas Souchu
+ * 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+
+/*
+ * Power Management support for the Acer M15x3 chipsets
+ */
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/buf.h>
+#include <sys/uio.h>
+#include <sys/malloc.h>
+
+#include <machine/clock.h>
+
+#include <machine/bus_pio.h>
+#include <machine/bus_memio.h>
+#include <machine/bus.h>
+
+#include <pci/pcivar.h>
+#include <pci/pcireg.h>
+
+#include <dev/iicbus/iiconf.h>
+#include <dev/smbus/smbconf.h>
+#include "smbus_if.h"
+
+#include "alpm.h"
+
+#define ALPM_DEBUG(x) if (alpm_debug) (x)
+
+#ifdef DEBUG
+static int alpm_debug = 1;
+#else
+static int alpm_debug = 0;
+#endif
+
+#define ACER_M1543_PMU_ID 0x710110b9
+
+/* Uncomment this line to force another I/O base address for SMB */
+/* #define ALPM_SMBIO_BASE_ADDR 0x3a80 */
+
+/* I/O registers offsets - the base address is programmed via the
+ * SMBBA PCI configuration register
+ */
+#define SMBSTS 0x0 /* SMBus host/slave status register */
+#define SMBCMD 0x1 /* SMBus host/slave command register */
+#define SMBSTART 0x2 /* start to generate programmed cycle */
+#define SMBHADDR 0x3 /* host address register */
+#define SMBHDATA 0x4 /* data A register for host controller */
+#define SMBHDATB 0x5 /* data B register for host controller */
+#define SMBHBLOCK 0x6 /* block register for host controller */
+#define SMBHCMD 0x7 /* command register for host controller */
+
+/* SMBSTS masks */
+#define TERMINATE 0x80
+#define BUS_COLLI 0x40
+#define DEVICE_ERR 0x20
+#define SMI_I_STS 0x10
+#define HST_BSY 0x08
+#define IDL_STS 0x04
+#define HSTSLV_STS 0x02
+#define HSTSLV_BSY 0x01
+
+/* SMBCMD masks */
+#define SMB_BLK_CLR 0x80
+#define T_OUT_CMD 0x08
+#define ABORT_HOST 0x04
+
+/* SMBus commands */
+#define SMBQUICK 0x00
+#define SMBSRBYTE 0x10 /* send/receive byte */
+#define SMBWRBYTE 0x20 /* write/read byte */
+#define SMBWRWORD 0x30 /* write/read word */
+#define SMBWRBLOCK 0x40 /* write/read block */
+
+/* PCI configuration registers and masks
+ */
+#define COM 0x4
+#define COM_ENABLE_IO 0x1
+
+#define SMBBA 0x14
+
+#define ATPC 0x5b
+#define ATPC_SMBCTRL 0x04
+
+#define SMBHSI 0xe0
+#define SMBHSI_SLAVE 0x2
+#define SMBHSI_HOST 0x1
+
+#define SMBHCBC 0xe2
+#define SMBHCBC_CLOCK 0x70
+
+#define SMBCLOCK_149K 0x0
+#define SMBCLOCK_74K 0x20
+#define SMBCLOCK_37K 0x40
+#define SMBCLOCK_223K 0x80
+#define SMBCLOCK_111K 0xa0
+#define SMBCLOCK_55K 0xc0
+
+struct alpm_data {
+ int base;
+ bus_space_tag_t smbst;
+ bus_space_handle_t smbsh;
+ pcici_t tag;
+};
+struct alpm_data alpmdata[NALPM];
+
+struct alsmb_softc {
+ int base;
+ device_t smbus;
+ struct alpm_data *alpm;
+};
+
+#define ALPM_SMBINB(alsmb,register) \
+ (bus_space_read_1(alsmb->alpm->smbst, alsmb->alpm->smbsh, register))
+#define ALPM_SMBOUTB(alsmb,register,value) \
+ (bus_space_write_1(alsmb->alpm->smbst, alsmb->alpm->smbsh, register, value))
+
+static int alsmb_probe(device_t);
+static int alsmb_attach(device_t);
+static int alsmb_smb_callback(device_t, int, caddr_t *);
+static int alsmb_smb_quick(device_t dev, u_char slave, int how);
+static int alsmb_smb_sendb(device_t dev, u_char slave, char byte);
+static int alsmb_smb_recvb(device_t dev, u_char slave, char *byte);
+static int alsmb_smb_writeb(device_t dev, u_char slave, char cmd, char byte);
+static int alsmb_smb_readb(device_t dev, u_char slave, char cmd, char *byte);
+static int alsmb_smb_writew(device_t dev, u_char slave, char cmd, short word);
+static int alsmb_smb_readw(device_t dev, u_char slave, char cmd, short *word);
+static int alsmb_smb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf);
+static int alsmb_smb_bread(device_t dev, u_char slave, char cmd, u_char count, char *byte);
+
+static devclass_t alsmb_devclass;
+
+static device_method_t alsmb_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, alsmb_probe),
+ DEVMETHOD(device_attach, alsmb_attach),
+
+ /* bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+
+ /* smbus interface */
+ DEVMETHOD(smbus_callback, alsmb_smb_callback),
+ DEVMETHOD(smbus_quick, alsmb_smb_quick),
+ DEVMETHOD(smbus_sendb, alsmb_smb_sendb),
+ DEVMETHOD(smbus_recvb, alsmb_smb_recvb),
+ DEVMETHOD(smbus_writeb, alsmb_smb_writeb),
+ DEVMETHOD(smbus_readb, alsmb_smb_readb),
+ DEVMETHOD(smbus_writew, alsmb_smb_writew),
+ DEVMETHOD(smbus_readw, alsmb_smb_readw),
+ DEVMETHOD(smbus_bwrite, alsmb_smb_bwrite),
+ DEVMETHOD(smbus_bread, alsmb_smb_bread),
+
+ { 0, 0 }
+};
+
+static driver_t alsmb_driver = {
+ "alsmb",
+ alsmb_methods,
+ sizeof(struct alsmb_softc),
+};
+
+static const char* alpm_pci_probe(pcici_t tag, pcidi_t type);
+static void alpm_pci_attach(pcici_t tag, int unit);
+
+static u_long alpm_count;
+
+static struct pci_device alpm_device = {
+ "alpm",
+ alpm_pci_probe,
+ alpm_pci_attach,
+ &alpm_count
+};
+
+COMPAT_PCI_DRIVER (alpm, alpm_device);
+
+static const char*
+alpm_pci_probe(pcici_t tag, pcidi_t type)
+{
+ if (type == ACER_M1543_PMU_ID)
+ return ("AcerLabs M15x3 Power Management Unit");
+
+ return ((char *)0);
+}
+
+static void
+alpm_pci_attach(pcici_t tag, int unit)
+{
+ struct alpm_data *alpm;
+ u_long l;
+
+ if (unit >= NALPM) {
+ printf("alpm%d: attach: only %d units configured.\n",
+ unit, NALPM);
+ return;
+ }
+ alpm = &alpmdata[unit];
+
+ alpm->tag = tag;
+
+ /* Unlock SMBIO base register access */
+ l = pci_cfgread(tag, ATPC, 1);
+ pci_cfgwrite(tag, ATPC, l & ~ATPC_SMBCTRL, 1);
+
+ if (bootverbose) {
+ l = pci_cfgread(tag, SMBHSI, 1);
+ printf("alsmb%d: %s/%s", unit,
+ (l & SMBHSI_HOST) ? "host":"nohost",
+ (l & SMBHSI_SLAVE) ? "slave":"noslave");
+
+ l = pci_cfgread(tag, SMBHCBC, 1);
+ switch (l & SMBHCBC_CLOCK) {
+ case SMBCLOCK_149K:
+ printf(" 149K");
+ break;
+ case SMBCLOCK_74K:
+ printf(" 74K");
+ break;
+ case SMBCLOCK_37K:
+ printf(" 37K");
+ break;
+ case SMBCLOCK_223K:
+ printf(" 223K");
+ break;
+ case SMBCLOCK_111K:
+ printf(" 111K");
+ break;
+ case SMBCLOCK_55K:
+ printf(" 55K");
+ break;
+ }
+ }
+
+ alpm->smbst = I386_BUS_SPACE_IO;
+
+#ifdef ALPM_SMBIO_BASE_ADDR
+ /* disable I/O */
+ l = pci_cfgread(tag, COM, 2);
+ pci_cfgwrite(tag, COM, l & ~COM_ENABLE_IO, 2);
+
+ /* set the I/O base address */
+ pci_cfgwrite(tag, SMBBA, ALPM_SMBIO_BASE_ADDR | 0x1, 4);
+
+ /* enable I/O */
+ pci_cfgwrite(tag, COM, l | COM_ENABLE_IO, 2);
+
+ alpm->smbsh = ALPM_SMBIO_BASE_ADDR;
+#else
+ alpm->smbsh = pci_cfgread(tag, SMBBA, 4) & ~0x1;
+#endif
+ if (bootverbose)
+ printf(" at 0x%x\n", alpm->smbsh);
+
+ /* XXX add the I2C interface to the root_bus until pcibus is ready */
+ device_add_child(root_bus, "alsmb", unit, NULL);
+
+ return;
+}
+
+/*
+ * Not a real probe, we know the device exists since the device has
+ * been added after the successfull pci probe.
+ */
+static int
+alsmb_probe(device_t dev)
+{
+ struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev);
+
+ sc->alpm = &alpmdata[device_get_unit(dev)];
+
+ device_set_desc(dev, "Aladdin IV/V/Pro2 SMBus controller");
+
+ return (0);
+}
+
+static int
+alsmb_attach(device_t dev)
+{
+ struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev);
+
+ /* allocate a new smbus device */
+ sc->smbus = smbus_alloc_bus(dev);
+
+ /* probe and attach the smbus */
+ device_probe_and_attach(sc->smbus);
+
+ return (0);
+}
+
+static int
+alsmb_smb_callback(device_t dev, int index, caddr_t *data)
+{
+ int error = 0;
+
+ switch (index) {
+ case SMB_REQUEST_BUS:
+ case SMB_RELEASE_BUS:
+ /* ok, bus allocation accepted */
+ break;
+ default:
+ error = EINVAL;
+ }
+
+ return (error);
+}
+
+static int
+alsmb_clear(struct alsmb_softc *sc)
+{
+ ALPM_SMBOUTB(sc, SMBSTS, 0xff);
+ DELAY(10);
+
+ return (0);
+}
+
+#if 0
+static int
+alsmb_abort(struct alsmb_softc *sc)
+{
+ ALPM_SMBOUTB(sc, SMBCMD, T_OUT_CMD | ABORT_HOST);
+
+ return (0);
+}
+#endif
+
+static int
+alsmb_idle(struct alsmb_softc *sc)
+{
+ u_char sts;
+
+ sts = ALPM_SMBINB(sc, SMBSTS);
+
+ ALPM_DEBUG(printf("alpm: idle? STS=0x%x\n", sts));
+
+ return (sts & IDL_STS);
+}
+
+/*
+ * Poll the SMBus controller
+ */
+static int
+alsmb_wait(struct alsmb_softc *sc)
+{
+ int count = 10000;
+ u_char sts;
+ int error;
+
+ /* wait for command to complete and SMBus controller is idle */
+ while(count--) {
+ DELAY(10);
+ sts = ALPM_SMBINB(sc, SMBSTS);
+ if (sts & SMI_I_STS)
+ break;
+ }
+
+ ALPM_DEBUG(printf("alpm: STS=0x%x\n", sts));
+
+ error = SMB_ENOERR;
+
+ if (!count)
+ error |= SMB_ETIMEOUT;
+
+ if (sts & TERMINATE)
+ error |= SMB_EABORT;
+
+ if (sts & BUS_COLLI)
+ error |= SMB_ENOACK;
+
+ if (sts & DEVICE_ERR)
+ error |= SMB_EBUSERR;
+
+ if (error != SMB_ENOERR)
+ alsmb_clear(sc);
+
+ return (error);
+}
+
+static int
+alsmb_smb_quick(device_t dev, u_char slave, int how)
+{
+ struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev);
+ int error;
+
+ alsmb_clear(sc);
+ if (!alsmb_idle(sc))
+ return (EBUSY);
+
+ switch (how) {
+ case SMB_QWRITE:
+ ALPM_DEBUG(printf("alpm: QWRITE to 0x%x", slave));
+ ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB);
+ break;
+ case SMB_QREAD:
+ ALPM_DEBUG(printf("alpm: QREAD to 0x%x", slave));
+ ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB);
+ break;
+ default:
+ panic("%s: unknown QUICK command (%x)!", __FUNCTION__,
+ how);
+ }
+ ALPM_SMBOUTB(sc, SMBCMD, SMBQUICK);
+ ALPM_SMBOUTB(sc, SMBSTART, 0xff);
+
+ error = alsmb_wait(sc);
+
+ ALPM_DEBUG(printf(", error=0x%x\n", error));
+
+ return (error);
+}
+
+static int
+alsmb_smb_sendb(device_t dev, u_char slave, char byte)
+{
+ struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev);
+ int error;
+
+ alsmb_clear(sc);
+ if (!alsmb_idle(sc))
+ return (SMB_EBUSY);
+
+ ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB);
+ ALPM_SMBOUTB(sc, SMBCMD, SMBSRBYTE);
+ ALPM_SMBOUTB(sc, SMBHDATA, byte);
+ ALPM_SMBOUTB(sc, SMBSTART, 0xff);
+
+ error = alsmb_wait(sc);
+
+ ALPM_DEBUG(printf("alpm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error));
+
+ return (error);
+}
+
+static int
+alsmb_smb_recvb(device_t dev, u_char slave, char *byte)
+{
+ struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev);
+ int error;
+
+ alsmb_clear(sc);
+ if (!alsmb_idle(sc))
+ return (SMB_EBUSY);
+
+ ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB);
+ ALPM_SMBOUTB(sc, SMBCMD, SMBSRBYTE);
+ ALPM_SMBOUTB(sc, SMBSTART, 0xff);
+
+ if ((error = alsmb_wait(sc)) == SMB_ENOERR)
+ *byte = ALPM_SMBINB(sc, SMBHDATA);
+
+ ALPM_DEBUG(printf("alpm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error));
+
+ return (error);
+}
+
+static int
+alsmb_smb_writeb(device_t dev, u_char slave, char cmd, char byte)
+{
+ struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev);
+ int error;
+
+ alsmb_clear(sc);
+ if (!alsmb_idle(sc))
+ return (SMB_EBUSY);
+
+ ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB);
+ ALPM_SMBOUTB(sc, SMBCMD, SMBWRBYTE);
+ ALPM_SMBOUTB(sc, SMBHDATA, byte);
+ ALPM_SMBOUTB(sc, SMBHCMD, cmd);
+ ALPM_SMBOUTB(sc, SMBSTART, 0xff);
+
+ error = alsmb_wait(sc);
+
+ ALPM_DEBUG(printf("alpm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error));
+
+ return (error);
+}
+
+static int
+alsmb_smb_readb(device_t dev, u_char slave, char cmd, char *byte)
+{
+ struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev);
+ int error;
+
+ alsmb_clear(sc);
+ if (!alsmb_idle(sc))
+ return (SMB_EBUSY);
+
+ ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB);
+ ALPM_SMBOUTB(sc, SMBCMD, SMBWRBYTE);
+ ALPM_SMBOUTB(sc, SMBHCMD, cmd);
+ ALPM_SMBOUTB(sc, SMBSTART, 0xff);
+
+ if ((error = alsmb_wait(sc)) == SMB_ENOERR)
+ *byte = ALPM_SMBINB(sc, SMBHDATA);
+
+ ALPM_DEBUG(printf("alpm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error));
+
+ return (error);
+}
+
+static int
+alsmb_smb_writew(device_t dev, u_char slave, char cmd, short word)
+{
+ struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev);
+ int error;
+
+ alsmb_clear(sc);
+ if (!alsmb_idle(sc))
+ return (SMB_EBUSY);
+
+ ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB);
+ ALPM_SMBOUTB(sc, SMBCMD, SMBWRWORD);
+ ALPM_SMBOUTB(sc, SMBHDATA, word & 0x00ff);
+ ALPM_SMBOUTB(sc, SMBHDATB, (word & 0xff00) >> 8);
+ ALPM_SMBOUTB(sc, SMBHCMD, cmd);
+ ALPM_SMBOUTB(sc, SMBSTART, 0xff);
+
+ error = alsmb_wait(sc);
+
+ ALPM_DEBUG(printf("alpm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error));
+
+ return (error);
+}
+
+static int
+alsmb_smb_readw(device_t dev, u_char slave, char cmd, short *word)
+{
+ struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev);
+ int error;
+ u_char high, low;
+
+ alsmb_clear(sc);
+ if (!alsmb_idle(sc))
+ return (SMB_EBUSY);
+
+ ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB);
+ ALPM_SMBOUTB(sc, SMBCMD, SMBWRWORD);
+ ALPM_SMBOUTB(sc, SMBHCMD, cmd);
+ ALPM_SMBOUTB(sc, SMBSTART, 0xff);
+
+ if ((error = alsmb_wait(sc)) == SMB_ENOERR) {
+ low = ALPM_SMBINB(sc, SMBHDATA);
+ high = ALPM_SMBINB(sc, SMBHDATB);
+
+ *word = ((high & 0xff) << 8) | (low & 0xff);
+ }
+
+ ALPM_DEBUG(printf("alpm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error));
+
+ return (error);
+}
+
+static int
+alsmb_smb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
+{
+ struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev);
+ u_char remain, len, i;
+ int error = SMB_ENOERR;
+
+ alsmb_clear(sc);
+ if(!alsmb_idle(sc))
+ return (SMB_EBUSY);
+
+ remain = count;
+ while (remain) {
+ len = min(remain, 32);
+
+ ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB);
+
+ /* set the cmd and reset the
+ * 32-byte long internal buffer */
+ ALPM_SMBOUTB(sc, SMBCMD, SMBWRBLOCK | SMB_BLK_CLR);
+
+ ALPM_SMBOUTB(sc, SMBHDATA, len);
+
+ /* fill the 32-byte internal buffer */
+ for (i=0; i<len; i++) {
+ ALPM_SMBOUTB(sc, SMBHBLOCK, buf[count-remain+i]);
+ DELAY(2);
+ }
+ ALPM_SMBOUTB(sc, SMBHCMD, cmd);
+ ALPM_SMBOUTB(sc, SMBSTART, 0xff);
+
+ if ((error = alsmb_wait(sc)) != SMB_ENOERR)
+ goto error;
+
+ remain -= len;
+ }
+
+error:
+ ALPM_DEBUG(printf("alpm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
+
+ return (error);
+}
+
+static int
+alsmb_smb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
+{
+ struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev);
+ u_char remain, len, i;
+ int error = SMB_ENOERR;
+
+ alsmb_clear(sc);
+ if (!alsmb_idle(sc))
+ return (SMB_EBUSY);
+
+ remain = count;
+ while (remain) {
+ ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB);
+
+ /* set the cmd and reset the
+ * 32-byte long internal buffer */
+ ALPM_SMBOUTB(sc, SMBCMD, SMBWRBLOCK | SMB_BLK_CLR);
+
+ ALPM_SMBOUTB(sc, SMBHCMD, cmd);
+ ALPM_SMBOUTB(sc, SMBSTART, 0xff);
+
+ if ((error = alsmb_wait(sc)) != SMB_ENOERR)
+ goto error;
+
+ len = ALPM_SMBINB(sc, SMBHDATA);
+
+ /* read the 32-byte internal buffer */
+ for (i=0; i<len; i++) {
+ buf[count-remain+i] = ALPM_SMBINB(sc, SMBHBLOCK);
+ DELAY(2);
+ }
+
+ remain -= len;
+ }
+error:
+ ALPM_DEBUG(printf("alpm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
+
+ return (error);
+}
+
+DRIVER_MODULE(alsmb, root, alsmb_driver, alsmb_devclass, 0, 0);
diff --git a/sys/pci/intpmreg.h b/sys/pci/intpmreg.h
new file mode 100644
index 000000000000..73816e7748d5
--- /dev/null
+++ b/sys/pci/intpmreg.h
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 1998, 1999 Takanori Watanabe
+ * 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*Register Difinition for Intel Chipset with ACPI Support*/
+#define PCI_BASE_ADDR_SMB 0x90 /*Where to MAP IO*/
+#define PCI_BASE_ADDR_PM 0x40
+#define PCI_HST_CFG_SMB 0xd2 /*Host Configuration*/
+#define PCI_INTR_SMB_SMI 0
+#define PCI_INTR_SMB_IRQ9 8
+#define PCI_INTR_SMB_ENABLE 1
+#define PCI_SLV_CMD_SMB 0xd3 /*SLAVE COMMAND*/
+#define PCI_SLV_SDW_SMB_1 0xd4 /*SLAVE SHADOW PORT 1*/
+#define PCI_SLV_SDW_SMB_2 0xd5 /*SLAVE SHADOW PORT 2*/
+#define PCI_REVID_SMB 0xd6
+#define LSB 0x1
+#define PIIX4_SMBHSTSTS 0x00
+#define PIIX4_SMBHSTSTAT_BUSY (1<<0)
+#define PIIX4_SMBHSTSTAT_INTR (1<<1)
+#define PIIX4_SMBHSTSTAT_ERR (1<<2)
+#define PIIX4_SMBHSTSTAT_BUSC (1<<3)
+#define PIIX4_SMBHSTSTAT_FAIL (1<<4)
+#define PIIX4_SMBSLVSTS 0x01
+#define PIIX4_SMBSLVSTS_ALART (1<<5)
+#define PIIX4_SMBSLVSTS_SDW2 (1<<4)
+#define PIIX4_SMBSLVSTS_SDW1 (1<<3)
+#define PIIX4_SMBSLVSTS_SLV (1<<2)
+#define PIIX4_SMBSLVSTS_BUSY (1<<0)
+#define PIIX4_SMBHSTCNT 0x02
+#define PIIX4_SMBHSTCNT_START (1<<6)
+#define PIIX4_SMBHSTCNT_PROT_QUICK 0
+#define PIIX4_SMBHSTCNT_PROT_BYTE (1<<2)
+#define PIIX4_SMBHSTCNT_PROT_BDATA (2<<2)
+#define PIIX4_SMBHSTCNT_PROT_WDATA (3<<2)
+#define PIIX4_SMBHSTCNT_PROT_BLOCK (5<<2)
+#define SMBBLOCKTRANS_MAX 32
+#define PIIX4_SMBHSTCNT_KILL (1<<1)
+#define PIIX4_SMBHSTCNT_INTREN (1)
+#define PIIX4_SMBHSTCMD 0x03
+#define PIIX4_SMBHSTADD 0x04
+#define PIIX4_SMBHSTDAT0 0x05
+#define PIIX4_SMBHSTDAT1 0x06
+#define PIIX4_SMBBLKDAT 0x07
+#define PIIX4_SMBSLVCNT 0x08
+#define PIIX4_SMBSLVCNT_ALTEN (1<<3)
+#define PIIX4_SMBSLVCNT_SD2EN (1<<2)
+#define PIIX4_SMBSLVCNT_SD1EN (1<<1)
+#define PIIX4_SMBSLVCNT_SLVEN (1)
+#define PIIX4_SMBSLVCMD 0x09
+#define PIIX4_SMBSLVEVT 0x0a
+#define PIIX4_SMBSLVDAT 0x0c
+/*This is SMBus alart response address*/
+#define SMBALTRESP 0x18
diff --git a/sys/pci/xmaciireg.h b/sys/pci/xmaciireg.h
new file mode 100644
index 000000000000..f649e93a044e
--- /dev/null
+++ b/sys/pci/xmaciireg.h
@@ -0,0 +1,393 @@
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Registers and data structures for the XaQti Corporation XMAC II
+ * Gigabit Ethernet MAC. Datasheet is available from http://www.xaqti.com.
+ * The XMAC can be programmed for 16-bit or 32-bit register access modes.
+ * The SysKonnect gigabit ethernet adapters use 16-bit mode, so that's
+ * how the registers are laid out here.
+ */
+
+#define XM_DEVICEID 0x00E0AE20
+#define XM_XAQTI_OUI 0x00E0AE
+
+#define XM_XMAC_REV(x) (((x) & 0x000000E0) >> 5)
+
+#define XM_XMAC_REV_B2 0x0
+#define XM_XMAC_REV_C1 0x1
+
+#define XM_MMUCMD 0x0000
+#define XM_POFF 0x0008
+#define XM_BURST 0x000C
+#define XM_VLAN_TAGLEV1 0x0010
+#define XM_VLAN_TAGLEV2 0x0014
+#define XM_TXCMD 0x0020
+#define XM_TX_RETRYLIMIT 0x0024
+#define XM_TX_SLOTTIME 0x0028
+#define XM_TX_IPG 0x003C
+#define XM_RXCMD 0x0030
+#define XM_PHY_ADDR 0x0034
+#define XM_PHY_DATA 0x0038
+#define XM_GPIO 0x0040
+#define XM_IMR 0x0044
+#define XM_ISR 0x0048
+#define XM_HWCFG 0x004C
+#define XM_TX_LOWAT 0x0060
+#define XM_TX_HIWAT 0x0062
+#define XM_TX_REQTHRESH_LO 0x0064
+#define XM_TX_REQTHRESH_HI 0x0066
+#define XM_TX_REQTHRESH XM_TX_REQTHRESH_LO
+#define XM_PAUSEDST0 0x0068
+#define XM_PAUSEDST1 0x006A
+#define XM_PAUSEDST2 0x006C
+#define XM_CTLPARM_LO 0x0070
+#define XM_CTLPARM_HI 0x0072
+#define XM_CTLPARM XM_CTLPARM_LO
+#define XM_OPCODE_PAUSE_TIMER 0x0074
+#define XM_TXSTAT_LIFO 0x0078
+
+/*
+ * Perfect filter registers. The XMAC has a table of 16 perfect
+ * filter entries, spaced 8 bytes apart. This is in addition to
+ * the station address registers, which appear below.
+ */
+#define XM_RXFILT_BASE 0x0080
+#define XM_RXFILT_END 0x0107
+#define XM_RXFILT_MAX 16
+#define XM_RXFILT_ENTRY(ent) (XM_RXFILT_BASE + ((ent * 8)))
+
+/* Primary station address. */
+#define XM_PAR0 0x0108
+#define XM_PAR1 0x010A
+#define XM_PAR2 0x010C
+
+/* 64-bit multicast hash table registers */
+#define XM_MAR0 0x0110
+#define XM_MAR1 0x0112
+#define XM_MAR2 0x0114
+#define XM_MAR3 0x0116
+#define XM_RX_LOWAT 0x0118
+#define XM_RX_HIWAT 0x011A
+#define XM_RX_REQTHRESH_LO 0x011C
+#define XM_RX_REQTHRESH_HI 0x011E
+#define XM_RX_REQTHRESH XM_RX_REQTHRESH_LO
+#define XM_DEVID_LO 0x0120
+#define XM_DEVID_HI 0x0122
+#define XM_DEVID XM_DEVID_LO
+#define XM_MODE_LO 0x0124
+#define XM_MODE_HI 0x0126
+#define XM_MODE XM_MODE_LO
+#define XM_LASTSRC0 0x0128
+#define XM_LASTSRC1 0x012A
+#define XM_LASTSRC2 0x012C
+#define XM_TSTAMP_READ 0x0130
+#define XM_TSTAMP_LOAD 0x0134
+#define XM_STATS_CMD 0x0200
+#define XM_RXCNT_EVENT_LO 0x0204
+#define XM_RXCNT_EVENT_HI 0x0206
+#define XM_RXCNT_EVENT XM_RXCNT_EVENT_LO
+#define XM_TXCNT_EVENT_LO 0x0208
+#define XM_TXCNT_EVENT_HI 0x020A
+#define XM_TXCNT_EVENT XM_TXCNT_EVENT_LO
+#define XM_RXCNT_EVMASK_LO 0x020C
+#define XM_RXCNT_EVMASK_HI 0x020E
+#define XM_RXCNT_EVMASK XM_RXCNT_EVMASK_LO
+#define XM_TXCNT_EVMASK_LO 0x0210
+#define XM_TXCNT_EVMASK_HI 0x0212
+#define XM_TXCNT_EVMASK XM_TXCNT_EVMASK_LO
+
+/* Statistics command register */
+#define XM_STATCMD_CLR_TX 0x0001
+#define XM_STATCMD_CLR_RX 0x0002
+#define XM_STATCMD_COPY_TX 0x0004
+#define XM_STATCMD_COPY_RX 0x0008
+#define XM_STATCMD_SNAP_TX 0x0010
+#define XM_STATCMD_SNAP_RX 0x0020
+
+/* TX statistics registers */
+#define XM_TXSTATS_PKTSOK 0x280
+#define XM_TXSTATS_BYTESOK_HI 0x284
+#define XM_TXSTATS_BYTESOK_LO 0x288
+#define XM_TXSTATS_BCASTSOK 0x28C
+#define XM_TXSTATS_MCASTSOK 0x290
+#define XM_TXSTATS_UCASTSOK 0x294
+#define XM_TXSTATS_GIANTS 0x298
+#define XM_TXSTATS_BURSTCNT 0x29C
+#define XM_TXSTATS_PAUSEPKTS 0x2A0
+#define XM_TXSTATS_MACCTLPKTS 0x2A4
+#define XM_TXSTATS_SINGLECOLS 0x2A8
+#define XM_TXSTATS_MULTICOLS 0x2AC
+#define XM_TXSTATS_EXCESSCOLS 0x2B0
+#define XM_TXSTATS_LATECOLS 0x2B4
+#define XM_TXSTATS_DEFER 0x2B8
+#define XM_TXSTATS_EXCESSDEFER 0x2BC
+#define XM_TXSTATS_UNDERRUN 0x2C0
+#define XM_TXSTATS_CARRIERSENSE 0x2C4
+#define XM_TXSTATS_UTILIZATION 0x2C8
+#define XM_TXSTATS_64 0x2D0
+#define XM_TXSTATS_65_127 0x2D4
+#define XM_TXSTATS_128_255 0x2D8
+#define XM_TXSTATS_256_511 0x2DC
+#define XM_TXSTATS_512_1023 0x2E0
+#define XM_TXSTATS_1024_MAX 0x2E4
+
+/* RX statistics registers */
+#define XM_RXSTATS_PKTSOK 0x300
+#define XM_RXSTATS_BYTESOK_HI 0x304
+#define XM_RXSTATS_BYTESOK_LO 0x308
+#define XM_RXSTATS_BCASTSOK 0x30C
+#define XM_RXSTATS_MCASTSOK 0x310
+#define XM_RXSTATS_UCASTSOK 0x314
+#define XM_RXSTATS_PAUSEPKTS 0x318
+#define XM_RXSTATS_MACCTLPKTS 0x31C
+#define XM_RXSTATS_BADPAUSEPKTS 0x320
+#define XM_RXSTATS_BADMACCTLPKTS 0x324
+#define XM_RXSTATS_BURSTCNT 0x328
+#define XM_RXSTATS_MISSEDPKTS 0x32C
+#define XM_RXSTATS_FRAMEERRS 0x330
+#define XM_RXSTATS_OVERRUN 0x334
+#define XM_RXSTATS_JABBER 0x338
+#define XM_RXSTATS_CARRLOSS 0x33C
+#define XM_RXSTATS_INRNGLENERR 0x340
+#define XM_RXSTATS_SYMERR 0x344
+#define XM_RXSTATS_SHORTEVENT 0x348
+#define XM_RXSTATS_RUNTS 0x34C
+#define XM_RXSTATS_GIANTS 0x350
+#define XM_RXSTATS_CRCERRS 0x354
+#define XM_RXSTATS_CEXTERRS 0x35C
+#define XM_RXSTATS_UTILIZATION 0x360
+#define XM_RXSTATS_64 0x368
+#define XM_RXSTATS_65_127 0x36C
+#define XM_RXSTATS_128_255 0x370
+#define XM_RXSTATS_256_511 0x374
+#define XM_RXSTATS_512_1023 0x378
+#define XM_RXSTATS_1024_MAX 0x37C
+
+#define XM_MMUCMD_TX_ENB 0x0001
+#define XM_MMUCMD_RX_ENB 0x0002
+#define XM_MMUCMD_GMIILOOP 0x0004
+#define XM_MMUCMD_RATECTL 0x0008
+#define XM_MMUCMD_GMIIFDX 0x0010
+#define XM_MMUCMD_NO_MGMT_PRMB 0x0020
+#define XM_MMUCMD_SIMCOL 0x0040
+#define XM_MMUCMD_FORCETX 0x0080
+#define XM_MMUCMD_LOOPENB 0x0200
+#define XM_MMUCMD_IGNPAUSE 0x0400
+#define XM_MMUCMD_PHYBUSY 0x0800
+#define XM_MMUCMD_PHYDATARDY 0x1000
+
+#define XM_TXCMD_AUTOPAD 0x0001
+#define XM_TXCMD_NOCRC 0x0002
+#define XM_TXCMD_NOPREAMBLE 0x0004
+#define XM_TXCMD_NOGIGAMODE 0x0008
+#define XM_TXCMD_SAMPLELINE 0x0010
+#define XM_TXCMD_ENCBYPASS 0x0020
+#define XM_TXCMD_XMITBK2BK 0x0040
+#define XM_TXCMD_FAIRSHARE 0x0080
+
+#define XM_RXCMD_DISABLE_CEXT 0x0001
+#define XM_RXCMD_STRIPPAD 0x0002
+#define XM_RXCMD_SAMPLELINE 0x0004
+#define XM_RXCMD_SELFRX 0x0008
+#define XM_RXCMD_STRIPFCS 0x0010
+#define XM_RXCMD_TRANSPARENT 0x0020
+#define XM_RXCMD_IPGCAPTURE 0x0040
+#define XM_RXCMD_BIGPKTOK 0x0080
+#define XM_RXCMD_LENERROK 0x0100
+
+#define XM_IMR_RX_EOF 0x0001
+#define XM_IMR_TX_EOF 0x0002
+#define XM_IMR_TX_UNDERRUN 0x0004
+#define XM_IMR_RX_OVERRUN 0x0008
+#define XM_IMR_TX_STATS_OFLOW 0x0010
+#define XM_IMR_RX_STATS_OFLOW 0x0020
+#define XM_IMR_TSTAMP_OFLOW 0x0040
+#define XM_IMR_AUTONEG_DONE 0x0080
+#define XM_IMR_NEXTPAGE_RDY 0x0100
+#define XM_IMR_PAGE_RECEIVED 0x0200
+#define XM_IMR_LP_REQCFG 0x0400
+#define XM_IMR_GP0_SET 0x0800
+#define XM_IMR_FORCEINTR 0x1000
+#define XM_IMR_TX_ABORT 0x2000
+#define XM_IMR_LINKEVENT 0x4000
+
+#define XM_INTRS \
+ (~(XM_IMR_LINKEVENT|XM_IMR_AUTONEG_DONE|XM_IMR_TX_UNDERRUN))
+
+#define XM_ISR_RX_EOF 0x0001
+#define XM_ISR_TX_EOF 0x0002
+#define XM_ISR_TX_UNDERRUN 0x0004
+#define XM_ISR_RX_OVERRUN 0x0008
+#define XM_ISR_TX_STATS_OFLOW 0x0010
+#define XM_ISR_RX_STATS_OFLOW 0x0020
+#define XM_ISR_TSTAMP_OFLOW 0x0040
+#define XM_ISR_AUTONEG_DONE 0x0080
+#define XM_ISR_NEXTPAGE_RDY 0x0100
+#define XM_ISR_PAGE_RECEIVED 0x0200
+#define XM_ISR_LP_REQCFG 0x0400
+#define XM_ISR_GP0_SET 0x0800
+#define XM_ISR_FORCEINTR 0x1000
+#define XM_ISR_TX_ABORT 0x2000
+#define XM_ISR_LINKEVENT 0x4000
+
+#define XM_MODE_FLUSH_RXFIFO 0x00000001
+#define XM_MODE_FLUSH_TXFIFO 0x00000002
+#define XM_MODE_BIGENDIAN 0x00000004
+#define XM_MODE_RX_PROMISC 0x00000008
+#define XM_MODE_RX_NOBROAD 0x00000010
+#define XM_MODE_RX_NOMULTI 0x00000020
+#define XM_MODE_RX_NOUNI 0x00000040
+#define XM_MODE_RX_BADFRAMES 0x00000080
+#define XM_MODE_RX_CRCERRS 0x00000100
+#define XM_MODE_RX_GIANTS 0x00000200
+#define XM_MODE_RX_INRANGELEN 0x00000400
+#define XM_MODE_RX_RUNTS 0x00000800
+#define XM_MODE_RX_MACCTL 0x00001000
+#define XM_MODE_RX_USE_PERFECT 0x00002000
+#define XM_MODE_RX_USE_STATION 0x00004000
+#define XM_MODE_RX_USE_HASH 0x00008000
+#define XM_MODE_RX_ADDRPAIR 0x00010000
+#define XM_MODE_PAUSEONHI 0x00020000
+#define XM_MODE_PAUSEONLO 0x00040000
+#define XM_MODE_TIMESTAMP 0x00080000
+#define XM_MODE_SENDPAUSE 0x00100000
+#define XM_MODE_SENDCONTINUOUS 0x00200000
+#define XM_MODE_LE_STATUSWORD 0x00400000
+#define XM_MODE_AUTOFIFOPAUSE 0x00800000
+#define XM_MODE_EXPAUSEGEN 0x02000000
+#define XM_MODE_RX_INVERSE 0x04000000
+
+#define XM_RXSTAT_MACCTL 0x00000001
+#define XM_RXSTAT_ERRFRAME 0x00000002
+#define XM_RXSTAT_CRCERR 0x00000004
+#define XM_RXSTAT_GIANT 0x00000008
+#define XM_RXSTAT_RUNT 0x00000010
+#define XM_RXSTAT_FRAMEERR 0x00000020
+#define XM_RXSTAT_INRANGEERR 0x00000040
+#define XM_RXSTAT_CARRIERERR 0x00000080
+#define XM_RXSTAT_COLLERR 0x00000100
+#define XM_RXSTAT_802_3 0x00000200
+#define XM_RXSTAT_CARREXTERR 0x00000400
+#define XM_RXSTAT_BURSTMODE 0x00000800
+#define XM_RXSTAT_UNICAST 0x00002000
+#define XM_RXSTAT_MULTICAST 0x00004000
+#define XM_RXSTAT_BROADCAST 0x00008000
+#define XM_RXSTAT_VLAN_LEV1 0x00010000
+#define XM_RXSTAT_VLAN_LEV2 0x00020000
+#define XM_RXSTAT_LEN 0xFFFC0000
+
+/*
+ * XMAC PHY registers, indirectly accessed through
+ * XM_PHY_ADDR and XM_PHY_REG.
+ */
+
+#define XM_PHY_BMCR 0x0000 /* control */
+#define XM_PHY_BMSR 0x0001 /* status */
+#define XM_PHY_VENID 0x0002 /* vendor id */
+#define XM_PHY_DEVID 0x0003 /* device id */
+#define XM_PHY_ANAR 0x0004 /* autoneg advertisenemt */
+#define XM_PHY_LPAR 0x0005 /* link partner ability */
+#define XM_PHY_ANEXP 0x0006 /* autoneg expansion */
+#define XM_PHY_NEXTP 0x0007 /* nextpage */
+#define XM_PHY_LPNEXTP 0x0008 /* link partner's nextpage */
+#define XM_PHY_EXTSTS 0x000F /* extented status */
+#define XM_PHY_RESAB 0x0010 /* resolved ability */
+
+#define XM_BMCR_DUPLEX 0x0100
+#define XM_BMCR_RENEGOTIATE 0x0200
+#define XM_BMCR_AUTONEGENBL 0x1000
+#define XM_BMCR_LOOPBACK 0x4000
+#define XM_BMCR_RESET 0x8000
+
+#define XM_BMSR_EXTCAP 0x0001
+#define XM_BMSR_LINKSTAT 0x0004
+#define XM_BMSR_AUTONEGABLE 0x0008
+#define XM_BMSR_REMFAULT 0x0010
+#define XM_BMSR_AUTONEGDONE 0x0020
+#define XM_BMSR_EXTSTAT 0x0100
+
+#define XM_VENID_XAQTI 0xD14C
+#define XM_DEVID_XMAC 0x0002
+
+#define XM_ANAR_FULLDUPLEX 0x0020
+#define XM_ANAR_HALFDUPLEX 0x0040
+#define XM_ANAR_PAUSEBITS 0x0180
+#define XM_ANAR_REMFAULTBITS 0x1800
+#define XM_ANAR_ACK 0x4000
+#define XM_ANAR_NEXTPAGE 0x8000
+
+#define XM_LPAR_FULLDUPLEX 0x0020
+#define XM_LPAR_HALFDUPLEX 0x0040
+#define XM_LPAR_PAUSEBITS 0x0180
+#define XM_LPAR_REMFAULTBITS 0x1800
+#define XM_LPAR_ACK 0x4000
+#define XM_LPAR_NEXTPAGE 0x8000
+
+#define XM_PAUSE_NOPAUSE 0x0000
+#define XM_PAUSE_SYMPAUSE 0x0080
+#define XM_PAUSE_ASYMPAUSE 0x0100
+#define XM_PAUSE_BOTH 0x0180
+
+#define XM_REMFAULT_LINKOK 0x0000
+#define XM_REMFAULT_LINKFAIL 0x0800
+#define XM_REMFAULT_OFFLINE 0x1000
+#define XM_REMFAULT_ANEGERR 0x1800
+
+#define XM_ANEXP_GOTPAGE 0x0002
+#define XM_ANEXP_NEXTPAGE_SELF 0x0004
+#define XM_ANEXP_NEXTPAGE_LP 0x0008
+
+#define XM_NEXTP_MESSAGE 0x07FF
+#define XM_NEXTP_TOGGLE 0x0800
+#define XM_NEXTP_ACK2 0x1000
+#define XM_NEXTP_MPAGE 0x2000
+#define XM_NEXTP_ACK1 0x4000
+#define XM_NEXTP_NPAGE 0x8000
+
+#define XM_LPNEXTP_MESSAGE 0x07FF
+#define XM_LPNEXTP_TOGGLE 0x0800
+#define XM_LPNEXTP_ACK2 0x1000
+#define XM_LPNEXTP_MPAGE 0x2000
+#define XM_LPNEXTP_ACK1 0x4000
+#define XM_LPNEXTP_NPAGE 0x8000
+
+#define XM_EXTSTS_HALFDUPLEX 0x4000
+#define XM_EXTSTS_FULLDUPLEX 0x8000
+
+#define XM_RESAB_PAUSEMISMATCH 0x0008
+#define XM_RESAB_ABLMISMATCH 0x0010
+#define XM_RESAB_FDMODESEL 0x0020
+#define XM_RESAB_HDMODESEL 0x0040
+#define XM_RESAB_PAUSEBITS 0x0180
diff --git a/sys/sys/memrange.h b/sys/sys/memrange.h
new file mode 100644
index 000000000000..363a5f09904c
--- /dev/null
+++ b/sys/sys/memrange.h
@@ -0,0 +1,67 @@
+/*
+ * Memory range attribute operations, peformed on /dev/mem
+ */
+
+/* Memory range attributes */
+#define MDF_UNCACHEABLE (1<<0) /* region not cached */
+#define MDF_WRITECOMBINE (1<<1) /* region supports "write combine" action */
+#define MDF_WRITETHROUGH (1<<2) /* write-through cached */
+#define MDF_WRITEBACK (1<<3) /* write-back cached */
+#define MDF_WRITEPROTECT (1<<4) /* read-only region */
+#define MDF_ATTRMASK (0x00ffffff)
+
+#define MDF_FIXBASE (1<<24) /* fixed base */
+#define MDF_FIXLEN (1<<25) /* fixed length */
+#define MDF_FIRMWARE (1<<26) /* set by firmware (XXX not useful?) */
+#define MDF_ACTIVE (1<<27) /* currently active */
+#define MDF_BOGUS (1<<28) /* we don't like it */
+#define MDF_FIXACTIVE (1<<29) /* can't be turned off */
+#define MDF_BUSY (1<<30) /* range is in use */
+
+struct mem_range_desc
+{
+ u_int64_t mr_base;
+ u_int64_t mr_len;
+ int mr_flags;
+ char mr_owner[8];
+};
+
+struct mem_range_op
+{
+ struct mem_range_desc *mo_desc;
+ int mo_arg[2];
+#define MEMRANGE_SET_UPDATE 0
+#define MEMRANGE_SET_REMOVE 1
+ /* XXX want a flag that says "set and undo when I exit" */
+};
+
+#define MEMRANGE_GET _IOWR('m', 50, struct mem_range_op)
+#define MEMRANGE_SET _IOW('m', 51, struct mem_range_op)
+
+#ifdef KERNEL
+
+MALLOC_DECLARE(M_MEMDESC);
+
+struct mem_range_softc;
+struct mem_range_ops
+{
+ void (*init)(struct mem_range_softc *sc);
+ int (*set)(struct mem_range_softc *sc, struct mem_range_desc *mrd, int *arg);
+ void (*initAP)(struct mem_range_softc *sc);
+};
+
+struct mem_range_softc
+{
+ struct mem_range_ops *mr_op;
+ int mr_cap;
+ int mr_ndesc;
+ struct mem_range_desc *mr_desc;
+};
+
+extern struct mem_range_softc mem_range_softc;
+
+extern int mem_range_attr_get(struct mem_range_desc *mrd, int *arg);
+extern int mem_range_attr_set(struct mem_range_desc *mrd, int *arg);
+extern void mem_range_AP_init(void);
+#endif
+
diff --git a/usr.sbin/i4b/dtmfdecode/Makefile b/usr.sbin/i4b/dtmfdecode/Makefile
new file mode 100644
index 000000000000..792b2ef39301
--- /dev/null
+++ b/usr.sbin/i4b/dtmfdecode/Makefile
@@ -0,0 +1,15 @@
+#---------------------------------------------------------------------------
+#
+# $FreeBSD$
+#
+# last edit-date: [Thu May 20 12:04:05 1999]
+#
+#---------------------------------------------------------------------------
+
+PROG = dtmfdecode
+SRC = dtmfdecode.c
+#LDADD += -lm
+CFLAGS += -Wall -g -DDEBUG
+MAN1 = dtmfdecode.1
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/i4b/dtmfdecode/dtmfdecode.1 b/usr.sbin/i4b/dtmfdecode/dtmfdecode.1
new file mode 100644
index 000000000000..42cd5beb7419
--- /dev/null
+++ b/usr.sbin/i4b/dtmfdecode/dtmfdecode.1
@@ -0,0 +1,64 @@
+.\"
+.\" Copyright (c) 1999 Hellmuth Michaelis. 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.\" last edit-date: [Mon Apr 26 13:42:15 1999]
+.\"
+.\"
+.Dd February, 15 1999
+.Dt DTMFDECODE 1
+.Os
+.Sh NAME
+.Nm dtmfdecode
+.Nd decodes DTMF tones from A-law audio data
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+.Nm dtmfdecode
+is part of the isdn4bsd package and is used to detect DTMF tones in the
+audio stream.
+.Pp
+It reads audio G.711 A-Law coded data from stdin and outputs the detected
+numbers values as ASCII charcters to stdout.
+.Pp
+The detector is implemented as 8 narrow band-pass filters realized with
+an integer double-cross recursive algorithm. Various ad-hoc methods are
+employed to provide hysteresis and anti-bounce for the detected signals.
+.Sh EXAMPLES
+The command:
+.Bd -literal -offset indent
+dtmfdecode < beep.al
+.Ed
+.Pp
+will print a "1" to stdout.
+.Sh STANDARDS
+ITU Recommendations G.711
+.Sh AUTHORS
+The
+.Nm
+utility was written by
+.An Poul-Henning Kamp Aq phk@FreeBSD.org .
+This man page was written by
+.An Hellmuth Michaelis Aq hm@FreeBSD.org .
diff --git a/usr.sbin/i4b/dtmfdecode/dtmfdecode.c b/usr.sbin/i4b/dtmfdecode/dtmfdecode.c
new file mode 100644
index 000000000000..f96bacd42b10
--- /dev/null
+++ b/usr.sbin/i4b/dtmfdecode/dtmfdecode.c
@@ -0,0 +1,150 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ *
+ * $FreeBSD$
+ *
+ * Extract DTMF signalling from ISDN4BSD A-law coded audio data
+ *
+ * A-Law to linear conversion from the sox package.
+ *
+ */
+
+#include <stdio.h>
+#include <math.h>
+
+/* Integer math scaling factor */
+#define FSC (1<<12)
+
+/* Alaw parameters */
+#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */
+#define QUANT_MASK (0xf) /* Quantization field mask. */
+#define SEG_SHIFT (4) /* Left shift for segment number. */
+#define SEG_MASK (0x70) /* Segment field mask. */
+
+static int
+alaw2linear(a_val)
+ unsigned char a_val;
+{
+ int t;
+ int seg;
+
+ a_val ^= 0x55;
+
+ t = (a_val & QUANT_MASK) << 4;
+ seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT;
+ switch (seg) {
+ case 0:
+ t += 8;
+ break;
+ case 1:
+ t += 0x108;
+ break;
+ default:
+ t += 0x108;
+ t <<= seg - 1;
+ }
+ return ((a_val & SIGN_BIT) ? t : -t);
+}
+
+#ifdef USE_COS
+/* The frequencies we're trying to detect */
+static int dtmf[8] = {697, 770, 852, 941, 1209, 1336, 1477, 1633};
+#else
+/* precalculated: p1[kk] = (-cos(2 * 3.141592 * dtmf[kk] / 8000.0) * FSC) */
+static int p1[8] = {-3497, -3369, -3212, -3027, -2384, -2040, -1635, -1164};
+#endif
+
+/* This is the Q of the filter (pole radius) */
+#define POLRAD .99
+
+#define P2 ((int)(POLRAD*POLRAD*FSC))
+
+int
+main(int argc, char **argv)
+{
+ int i, kk, t, nn, s, so, ia;
+ int x, c, d, f, h[8], k[8], n, y[8];
+#ifdef USE_COS
+ int p1[8];
+#endif
+ int alaw[256];
+ char key[256];
+
+ for (kk = 0; kk < 8; kk++) {
+ y[kk] = h[kk] = k[kk] = 0;
+#ifdef USE_COS
+ p1[kk] = (-cos(2 * 3.141592 * dtmf[kk] / 8000.0) * FSC);
+#endif
+ }
+
+ for (i = 0; i < 256; i++) {
+ key[i] = '?';
+ alaw[i] = alaw2linear(i) / (32768/FSC);
+ }
+
+ /* We encode the tones in 8 bits, translate those to symbol */
+ key[0x00] = '\0';
+
+ key[0x11] = '1'; key[0x12] = '4'; key[0x14] = '7'; key[0x18] = '*';
+ key[0x21] = '2'; key[0x22] = '5'; key[0x24] = '8'; key[0x28] = '0';
+ key[0x41] = '3'; key[0x42] = '6'; key[0x44] = '9'; key[0x48] = '#';
+ key[0x81] = 'A'; key[0x82] = 'B'; key[0x84] = 'C'; key[0x88] = 'D';
+
+ nn = 0;
+ ia = 0;
+ so = 0;
+ t = 0;
+ while ((i = getchar()) != EOF)
+ {
+ t++;
+
+ /* Convert to our format */
+ x = alaw[i];
+
+ /* Input amplitude */
+ if (x > 0)
+ ia += (x - ia) / 128;
+ else
+ ia += (-x - ia) / 128;
+
+ /* For each tone */
+ s = 0;
+ for(kk = 0; kk < 8; kk++) {
+
+ /* Turn the crank */
+ c = (P2 * (x - k[kk])) / FSC;
+ d = x + c;
+ f = (p1[kk] * (d - h[kk])) / FSC;
+ n = x - k[kk] - c;
+ k[kk] = h[kk] + f;
+ h[kk] = f + d;
+
+ /* Detect and Average */
+ if (n > 0)
+ y[kk] += (n - y[kk]) / 64;
+ else
+ y[kk] += (-n - y[kk]) / 64;
+
+ /* Threshold */
+ if (y[kk] > FSC/10 && y[kk] > ia)
+ s |= 1 << kk;
+ }
+
+ /* Hysteresis and noise supressor */
+ if (s != so) {
+/* printf("x %d %x -> %x\n",t,so, s); */
+ nn = 0;
+ so = s;
+ } else if (nn++ == 520 && key[s]) {
+ putchar(key[s]);
+/* printf(" %d %x\n",t,s); */
+ }
+ }
+ putchar('\n');
+ return (0);
+}
diff --git a/usr.sbin/i4b/g711conv/Makefile b/usr.sbin/i4b/g711conv/Makefile
new file mode 100644
index 000000000000..f96de268deea
--- /dev/null
+++ b/usr.sbin/i4b/g711conv/Makefile
@@ -0,0 +1,14 @@
+#---------------------------------------------------------------------------
+#
+# $FreeBSD$
+#
+# last edit-date: [Thu May 20 11:58:43 1999]
+#
+#---------------------------------------------------------------------------
+
+PROG = g711conv
+SRC = g711conv.c
+CFLAGS += -Wall -g
+MAN1 = g711conv.1
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/i4b/g711conv/g711conv.1 b/usr.sbin/i4b/g711conv/g711conv.1
new file mode 100644
index 000000000000..4d9102458cad
--- /dev/null
+++ b/usr.sbin/i4b/g711conv/g711conv.1
@@ -0,0 +1,96 @@
+.\"
+.\" Copyright (c) 1999 Hellmuth Michaelis. 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.\" last edit-date: [Mon Mar 15 16:17:23 1999]
+.\"
+.Dd March 15, 1999
+.Dt G711CONV 1
+.Os
+.Sh NAME
+.Nm g711conv
+.Nd conversions according to G.711
+.Sh SYNOPSIS
+.Nm
+.Op Fl a
+.Op Fl u
+.Op Fl P
+.Op Fl A
+.Op Fl R
+.Sh DESCRIPTION
+.Nm g711conv
+is part of the isdn4bsd package and is used to convert between the A-Law and
+u-law formats as specified in ITU G.711. It is based on a freely available
+and freely usable reference implementation done by Sun Microsystems, Inc.
+.Pp
+The following options are available:
+.Bl -tag -width Ds
+.It Fl a
+Convert A-law to u-law
+.It Fl u
+Convert u-law to A-law
+.It Fl r
+Reverse bits before conversion
+.It Fl R
+Reverse bits after conversion
+.It Fl P
+Print the resulting conversion tables (as C-source) to stdout instead of
+doing the actual conversion.
+.El
+.Pp
+
+.Sh STANDARDS
+A-Law and u-Law conversions are specified in ITU Recommendation G.711.
+.Pp
+The reference implementation done by Sun Microsystems, Inc. is available
+from http://www.itu.int/itudoc/itu-t/rec/g/g700-799/refimpl.txt
+.Pp
+
+.Sh EXAMPLES
+The command:
+.Bd -literal -offset indent
+g711conv -P -a
+.Ed
+.Pp
+prints out the A-law to u-law conversion table as C-source to stdout.
+.Pp
+The command:
+.Bd -literal -offset indent
+cat max_headroom.ul | g711conv -u -R > /dev/i4btel0
+.Ed
+.Pp
+converts the u-law coded voice of Max Headroom to A-law, reverses the
+bits of the result and moves that to an active isdn4bsd telephone connection.
+.Pp
+
+.Sh AUTHORS
+The
+.Nm
+utility and this manpage were written by
+.An Hellmuth Michaelis Aq hm@kts.org
+based on the G.711 conversion reference code written by Sun Microsystems,
+Inc. and code contributed to isdn4bsd by
+.An Stefan Bethke .
+
diff --git a/usr.sbin/i4b/g711conv/g711conv.c b/usr.sbin/i4b/g711conv/g711conv.c
new file mode 100644
index 000000000000..f6a442ead0d3
--- /dev/null
+++ b/usr.sbin/i4b/g711conv/g711conv.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 1999 Hellmuth Michaelis. 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * ---
+ *
+ * The A-law to u-law and u-law to A-law conversion routines and tables
+ * were taken from the G.711 reference implementation from Sun and freely
+ * available as http://www.itu.int/itudoc/itu-t/rec/g/g700-799/refimpl.txt.
+ *
+ * Therefore for that part of the code, the following restrictions apply:
+ *
+ *
+ * This source code is a product of Sun Microsystems, Inc. and is provided
+ * for unrestricted use. Users may copy or modify this source code without
+ * charge.
+ *
+ * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
+ * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun source code is provided with no support and without any obligation on
+ * the part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ *
+ * ---
+ *
+ * The bitreverse table was contributed by Stefan Bethke.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * A-law / u-law conversions as specified in G.711
+ * -----------------------------------------------
+ *
+ * last edit-date: [Mon Apr 26 14:00:31 1999]
+ *
+ * $FreeBSD$
+ *
+ *---------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <machine/i4b_ioctl.h>
+
+/* copy from CCITT G.711 specifications */
+
+/* u- to A-law conversions */
+
+unsigned char _u2a[128] = {
+ 1, 1, 2, 2, 3, 3, 4, 4,
+ 5, 5, 6, 6, 7, 7, 8, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 27, 29, 31, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44,
+ 46, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62,
+ 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79,
+ 81, 82, 83, 84, 85, 86, 87, 88,
+ 89, 90, 91, 92, 93, 94, 95, 96,
+ 97, 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110, 111, 112,
+ 113, 114, 115, 116, 117, 118, 119, 120,
+ 121, 122, 123, 124, 125, 126, 127, 128
+};
+
+/* A- to u-law conversions */
+
+unsigned char _a2u[128] = {
+ 1, 3, 5, 7, 9, 11, 13, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 32, 33, 33, 34, 34, 35, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 48, 49, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57,
+ 58, 59, 60, 61, 62, 63, 64, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 78, 79, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103,
+ 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127
+};
+
+/* reverse bits (7->0, 6->1, 5->2 etc) for tx to / rx from ISDN */
+
+unsigned char bitreverse[256] = {
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+};
+
+/* A-law to u-law conversion */
+
+unsigned char alaw2ulaw(unsigned char aval)
+{
+ aval &= 0xff;
+ return ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) :
+ (0x7F ^ _a2u[aval ^ 0x55]));
+}
+
+/* u-law to A-law conversion */
+
+unsigned char ulaw2alaw(unsigned char uval)
+{
+ uval &= 0xff;
+ return ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) :
+ (0x55 ^ (_u2a[0x7F ^ uval] - 1)));
+}
+
+void
+usage(void)
+{
+ fprintf(stderr, "\n");
+ fprintf(stderr, "g711conv - do conversions according to ITU G.711, (version %d.%d.%d)\n",VERSION, REL, STEP);
+ fprintf(stderr, "usage: g711conv -a -r -R -u -P\n");
+ fprintf(stderr, " -a A-law to u-law conversion\n");
+ fprintf(stderr, " -r reverse bits before conversion\n");
+ fprintf(stderr, " -R reverse bits after conversion\n");
+ fprintf(stderr, " -u u-law to A-law conversion\n");
+ fprintf(stderr, " -P print conversion table as C source\n");
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+ int i;
+ int c;
+ int opt_a = 0;
+ int opt_u = 0;
+ int opt_r = 0;
+ int opt_P = 0;
+ int opt_R = 0;
+ unsigned char uc;
+
+ while ((c = getopt(argc, argv, "aurPR?")) != -1)
+ {
+ switch(c)
+ {
+ case 'a':
+ opt_a = 1;
+ break;
+
+ case 'u':
+ opt_u = 1;
+ break;
+
+ case 'r':
+ opt_r = 1;
+ break;
+
+ case 'R':
+ opt_R = 1;
+ break;
+
+ case 'P':
+ opt_P = 1;
+ break;
+
+ case '?':
+ default:
+ usage();
+ break;
+ }
+ }
+
+ if((opt_a + opt_u) > 1)
+ usage();
+
+ if(opt_P)
+ {
+ printf("\n/* ");
+
+ if((opt_a + opt_u) == 0)
+ printf("No Conversion");
+
+ if(opt_a)
+ printf("A-law to u-law conversion");
+
+ if(opt_u)
+ printf("u-law to A-law conversion");
+
+ if(opt_r)
+ printf(", reverse bits BEFORE conversion");
+
+ if(opt_R)
+ printf(", reverse bits AFTER conversion");
+
+ if(opt_a)
+ {
+ printf(" */\n\nunsigned char a2u_tab[256] = {");
+ }
+ else if(opt_u)
+ {
+ printf(" */\n\nunsigned char u2a_tab[256] = {");
+ }
+ else
+ {
+ printf(" */\n\nunsigned char table[256] = {");
+ }
+
+ for(i=0; i < 256; i++)
+ {
+ uc = i;
+
+ if(!(i % 8))
+ printf("\n/* %02x */\t", i);
+
+ if(opt_r)
+ uc = bitreverse[uc];
+
+ if(opt_u)
+ uc = ulaw2alaw(uc);
+
+ if(opt_a)
+ uc = alaw2ulaw(uc);
+
+ if(opt_R)
+ uc = bitreverse[uc];
+
+ if(i == 255)
+ printf("0x%02x", uc);
+ else
+ printf("0x%02x, ", uc);
+ }
+ printf("\n};\n");
+ }
+ else
+ {
+ unsigned char ib[1];
+
+ while(fread(ib, 1, 1, stdin) == 1)
+ {
+ if(opt_r)
+ ib[0] = bitreverse[ib[0]];
+
+ if(opt_u)
+ ib[0] = ulaw2alaw(ib[0]);
+
+ if(opt_a)
+ ib[0] = alaw2ulaw(ib[0]);
+
+ if(opt_R)
+ ib[0] = bitreverse[ib[0]];
+
+ fwrite(ib, 1, 1, stdout);
+ }
+ }
+ return(0);
+}
+
+/* EOF */
diff --git a/usr.sbin/inetd/builtins.c b/usr.sbin/inetd/builtins.c
new file mode 100644
index 000000000000..d5fa0bb5e485
--- /dev/null
+++ b/usr.sbin/inetd/builtins.c
@@ -0,0 +1,682 @@
+/*-
+ * Copyright (c) 1983, 1991, 1993, 1994
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#include <sys/filio.h>
+#include <sys/ioccom.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/ucred.h>
+#include <sys/uio.h>
+#include <sys/utsname.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "inetd.h"
+
+extern int debug;
+extern struct servtab *servtab;
+
+char ring[128];
+char *endring;
+
+int check_loop __P((struct sockaddr_in *, struct servtab *sep));
+void inetd_setproctitle __P((char *, int));
+
+struct biltin biltins[] = {
+ /* Echo received data */
+ { "echo", SOCK_STREAM, 1, -1, echo_stream },
+ { "echo", SOCK_DGRAM, 0, 1, echo_dg },
+
+ /* Internet /dev/null */
+ { "discard", SOCK_STREAM, 1, -1, discard_stream },
+ { "discard", SOCK_DGRAM, 0, 1, discard_dg },
+
+ /* Return 32 bit time since 1970 */
+ { "time", SOCK_STREAM, 0, -1, machtime_stream },
+ { "time", SOCK_DGRAM, 0, 1, machtime_dg },
+
+ /* Return human-readable time */
+ { "daytime", SOCK_STREAM, 0, -1, daytime_stream },
+ { "daytime", SOCK_DGRAM, 0, 1, daytime_dg },
+
+ /* Familiar character generator */
+ { "chargen", SOCK_STREAM, 1, -1, chargen_stream },
+ { "chargen", SOCK_DGRAM, 0, 1, chargen_dg },
+
+ { "tcpmux", SOCK_STREAM, 1, -1, (void (*)())tcpmux },
+
+ { "auth", SOCK_STREAM, 1, -1, ident_stream },
+
+ { NULL }
+};
+
+/*
+ * RFC864 Character Generator Protocol. Generates character data without
+ * any regard for input.
+ */
+
+void
+initring()
+{
+ int i;
+
+ endring = ring;
+
+ for (i = 0; i <= 128; ++i)
+ if (isprint(i))
+ *endring++ = i;
+}
+
+/* ARGSUSED */
+void
+chargen_dg(s, sep) /* Character generator */
+ int s;
+ struct servtab *sep;
+{
+ struct sockaddr_in sin;
+ static char *rs;
+ int len, size;
+ char text[LINESIZ+2];
+
+ if (endring == 0) {
+ initring();
+ rs = ring;
+ }
+
+ size = sizeof(sin);
+ if (recvfrom(s, text, sizeof(text), 0,
+ (struct sockaddr *)&sin, &size) < 0)
+ return;
+
+ if (check_loop(&sin, sep))
+ return;
+
+ if ((len = endring - rs) >= LINESIZ)
+ memmove(text, rs, LINESIZ);
+ else {
+ memmove(text, rs, len);
+ memmove(text + len, ring, LINESIZ - len);
+ }
+ if (++rs == endring)
+ rs = ring;
+ text[LINESIZ] = '\r';
+ text[LINESIZ + 1] = '\n';
+ (void) sendto(s, text, sizeof(text), 0,
+ (struct sockaddr *)&sin, sizeof(sin));
+}
+
+/* ARGSUSED */
+void
+chargen_stream(s, sep) /* Character generator */
+ int s;
+ struct servtab *sep;
+{
+ int len;
+ char *rs, text[LINESIZ+2];
+
+ inetd_setproctitle(sep->se_service, s);
+
+ if (!endring) {
+ initring();
+ rs = ring;
+ }
+
+ text[LINESIZ] = '\r';
+ text[LINESIZ + 1] = '\n';
+ for (rs = ring;;) {
+ if ((len = endring - rs) >= LINESIZ)
+ memmove(text, rs, LINESIZ);
+ else {
+ memmove(text, rs, len);
+ memmove(text + len, ring, LINESIZ - len);
+ }
+ if (++rs == endring)
+ rs = ring;
+ if (write(s, text, sizeof(text)) != sizeof(text))
+ break;
+ }
+ exit(0);
+}
+
+/*
+ * RFC867 Daytime Protocol. Sends the current date and time as an ascii
+ * character string without any regard for input.
+ */
+
+/* ARGSUSED */
+void
+daytime_dg(s, sep) /* Return human-readable time of day */
+ int s;
+ struct servtab *sep;
+{
+ char buffer[256];
+ time_t clock;
+ struct sockaddr_in sin;
+ int size;
+
+ clock = time((time_t *) 0);
+
+ size = sizeof(sin);
+ if (recvfrom(s, buffer, sizeof(buffer), 0,
+ (struct sockaddr *)&sin, &size) < 0)
+ return;
+
+ if (check_loop(&sin, sep))
+ return;
+
+ (void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
+ (void) sendto(s, buffer, strlen(buffer), 0,
+ (struct sockaddr *)&sin, sizeof(sin));
+}
+
+/* ARGSUSED */
+void
+daytime_stream(s, sep) /* Return human-readable time of day */
+ int s;
+ struct servtab *sep;
+{
+ char buffer[256];
+ time_t clock;
+
+ clock = time((time_t *) 0);
+
+ (void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
+ (void) write(s, buffer, strlen(buffer));
+}
+
+/*
+ * RFC863 Discard Protocol. Any data received is thrown away and no response
+ * is sent.
+ */
+
+/* ARGSUSED */
+void
+discard_dg(s, sep) /* Discard service -- ignore data */
+ int s;
+ struct servtab *sep;
+{
+ char buffer[BUFSIZE];
+
+ (void) read(s, buffer, sizeof(buffer));
+}
+
+/* ARGSUSED */
+void
+discard_stream(s, sep) /* Discard service -- ignore data */
+ int s;
+ struct servtab *sep;
+{
+ int ret;
+ char buffer[BUFSIZE];
+
+ inetd_setproctitle(sep->se_service, s);
+ while (1) {
+ while ((ret = read(s, buffer, sizeof(buffer))) > 0)
+ ;
+ if (ret == 0 || errno != EINTR)
+ break;
+ }
+ exit(0);
+}
+
+/*
+ * RFC862 Echo Protocol. Any data received is sent back to the sender as
+ * received.
+ */
+
+/* ARGSUSED */
+void
+echo_dg(s, sep) /* Echo service -- echo data back */
+ int s;
+ struct servtab *sep;
+{
+ char buffer[BUFSIZE];
+ int i, size;
+ struct sockaddr_in sin;
+
+ size = sizeof(sin);
+ if ((i = recvfrom(s, buffer, sizeof(buffer), 0,
+ (struct sockaddr *)&sin, &size)) < 0)
+ return;
+
+ if (check_loop(&sin, sep))
+ return;
+
+ (void) sendto(s, buffer, i, 0, (struct sockaddr *)&sin,
+ sizeof(sin));
+}
+
+/* ARGSUSED */
+void
+echo_stream(s, sep) /* Echo service -- echo data back */
+ int s;
+ struct servtab *sep;
+{
+ char buffer[BUFSIZE];
+ int i;
+
+ inetd_setproctitle(sep->se_service, s);
+ while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
+ write(s, buffer, i) > 0)
+ ;
+ exit(0);
+}
+
+/*
+ * RFC1413 Identification Protocol. Given a TCP port number pair, return a
+ * character string which identifies the owner of that connection on the
+ * server's system. Extended to allow for ~/.fakeid support and ~/.noident
+ * support.
+ */
+
+/* ARGSUSED */
+void
+iderror(lport, fport, s, er) /* Generic ident_stream error-sending func */
+ int lport, fport, s, er;
+{
+ char *p;
+
+ asprintf(&p, "%d , %d : ERROR : %s\r\n", lport, fport,
+ er == -1 ? "HIDDEN-USER" : er ? strerror(er) : "UNKNOWN-ERROR");
+ if (p == NULL) {
+ syslog(LOG_ERR, "asprintf: %m");
+ exit(EX_OSERR);
+ }
+ write(s, p, strlen(p));
+ free(p);
+
+ exit(0);
+}
+
+/* ARGSUSED */
+void
+ident_stream(s, sep) /* Ident service (AKA "auth") */
+ int s;
+ struct servtab *sep;
+{
+ struct utsname un;
+ struct stat sb;
+ struct sockaddr_in sin[2];
+ struct ucred uc;
+ struct timeval tv = {
+ 10,
+ 0
+ };
+ struct passwd *pw;
+ fd_set fdset;
+ char buf[BUFSIZE], *cp = NULL, *p, **av, *osname = NULL;
+ int len, c, fflag = 0, nflag = 0, rflag = 0, argc = 0;
+ u_short lport, fport;
+
+ inetd_setproctitle(sep->se_service, s);
+ /*
+ * Reset getopt() since we are a fork() but not an exec() from
+ * a parent which used getopt() already.
+ */
+ optind = 1;
+ optreset = 1;
+ /*
+ * Take the internal argument vector and count it out to make an
+ * argument count for getopt. This can be used for any internal
+ * service to read arguments and use getopt() easily.
+ */
+ for (av = sep->se_argv; *av; av++)
+ argc++;
+ if (argc) {
+ int sec, usec;
+
+ while ((c = getopt(argc, sep->se_argv, "fno:rt:")) != -1)
+ switch (c) {
+ case 'f':
+ fflag = 1;
+ break;
+ case 'n':
+ nflag = 1;
+ break;
+ case 'o':
+ osname = optarg;
+ break;
+ case 'r':
+ rflag = 1;
+ break;
+ case 't':
+ switch (sscanf(optarg, "%d.%d", &sec, &usec)) {
+ case 2:
+ tv.tv_usec = usec;
+ case 1:
+ tv.tv_sec = sec;
+ break;
+ default:
+ if (debug)
+ warnx("bad -t argument");
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ if (osname == NULL) {
+ if (uname(&un) == -1)
+ iderror(0, 0, s, errno);
+ osname = un.sysname;
+ }
+ len = sizeof(sin[0]);
+ if (getsockname(s, (struct sockaddr *)&sin[0], &len) == -1)
+ iderror(0, 0, s, errno);
+ len = sizeof(sin[1]);
+ if (getpeername(s, (struct sockaddr *)&sin[1], &len) == -1)
+ iderror(0, 0, s, errno);
+ /*
+ * We're going to prepare for and execute reception of a
+ * packet of data from the user. The data is in the format
+ * "local_port , foreign_port\r\n" (with local being the
+ * server's port and foreign being the client's.)
+ */
+ FD_ZERO(&fdset);
+ FD_SET(s, &fdset);
+ if (select(s + 1, &fdset, NULL, NULL, &tv) == -1)
+ iderror(0, 0, s, errno);
+ if (ioctl(s, FIONREAD, &len) == -1)
+ iderror(0, 0, s, errno);
+ if (len >= sizeof(buf))
+ len = sizeof(buf) - 1;
+ len = read(s, buf, len);
+ if (len == -1)
+ iderror(0, 0, s, errno);
+ buf[len] = '\0';
+ if (sscanf(buf, "%hu , %hu", &lport, &fport) != 2)
+ iderror(0, 0, s, 0);
+ if (!rflag) /* Send HIDDEN-USER immediately if not "real" */
+ iderror(lport, fport, s, -1);
+ /*
+ * We take the input and construct an array of two sockaddr_ins
+ * which contain the local address information and foreign
+ * address information, respectively, used to look up the
+ * credentials for the socket (which are returned by the
+ * sysctl "net.inet.tcp.getcred" when we call it.) The
+ * arrays have been filled in above via get{peer,sock}name(),
+ * so right here we are only setting the ports.
+ */
+ sin[0].sin_port = htons(lport);
+ sin[1].sin_port = htons(fport);
+ len = sizeof(uc);
+ if (sysctlbyname("net.inet.tcp.getcred", &uc, &len, sin,
+ sizeof(sin)) == -1)
+ iderror(lport, fport, s, errno);
+ pw = getpwuid(uc.cr_uid); /* Look up the pw to get the username */
+ if (pw == NULL)
+ iderror(lport, fport, s, errno);
+ /*
+ * If enabled, we check for a file named ".noident" in the user's
+ * home directory. If found, we return HIDDEN-USER.
+ */
+ if (nflag) {
+ if (asprintf(&p, "%s/.noident", pw->pw_dir) == -1)
+ iderror(lport, fport, s, errno);
+ if (lstat(p, &sb) == 0) {
+ free(p);
+ iderror(lport, fport, s, -1);
+ }
+ free(p);
+ }
+ /*
+ * Here, if enabled, we read a user's ".fakeid" file in their
+ * home directory. It consists of a line containing the name
+ * they want.
+ */
+ if (fflag) {
+ FILE *fakeid = NULL;
+
+ if (asprintf(&p, "%s/.fakeid", pw->pw_dir) == -1)
+ iderror(lport, fport, s, errno);
+ /*
+ * Here we set ourself to effectively be the user, so we don't
+ * open any files we have no permission to open, especially
+ * symbolic links to sensitive root-owned files or devices.
+ */
+ seteuid(pw->pw_uid);
+ setegid(pw->pw_gid);
+ /*
+ * If we were to lstat() here, it would do no good, since it
+ * would introduce a race condition and could be defeated.
+ * Therefore, we open the file we have permissions to open
+ * and if it's not a regular file, we close it and end up
+ * returning the user's real username.
+ */
+ fakeid = fopen(p, "r");
+ free(p);
+ if (fakeid != NULL &&
+ fstat(fileno(fakeid), &sb) != -1 && S_ISREG(sb.st_mode)) {
+ buf[sizeof(buf) - 1] = '\0';
+ if (fgets(buf, sizeof(buf), fakeid) == NULL) {
+ cp = pw->pw_name;
+ fclose(fakeid);
+ goto printit;
+ }
+ fclose(fakeid);
+ /*
+ * Usually, the file will have the desired identity
+ * in the form "identity\n", so we use strtok() to
+ * end the string (which fgets() doesn't do.)
+ */
+ strtok(buf, "\r\n");
+ /* User names of >16 characters are invalid */
+ if (strlen(buf) > 16)
+ buf[16] = '\0';
+ cp = buf;
+ /* Allow for beginning white space... */
+ while (isspace(*cp))
+ cp++;
+ /* ...and ending white space. */
+ strtok(cp, " \t");
+ /*
+ * If the name is a zero-length string or matches
+ * the name of another user, it's invalid, so
+ * we will return their real identity instead.
+ */
+
+ if (!*cp || getpwnam(cp))
+ cp = getpwuid(uc.cr_uid)->pw_name;
+ } else
+ cp = pw->pw_name;
+ } else
+ cp = pw->pw_name;
+printit:
+ /* Finally, we make and send the reply. */
+ if (asprintf(&p, "%d , %d : USERID : %s : %s\r\n", lport, fport, osname,
+ cp) == -1) {
+ syslog(LOG_ERR, "asprintf: %m");
+ exit(EX_OSERR);
+ }
+ write(s, p, strlen(p));
+ free(p);
+
+ exit(0);
+}
+
+/*
+ * RFC738 Time Server.
+ * Return a machine readable date and time, in the form of the
+ * number of seconds since midnight, Jan 1, 1900. Since gettimeofday
+ * returns the number of seconds since midnight, Jan 1, 1970,
+ * we must add 2208988800 seconds to this figure to make up for
+ * some seventy years Bell Labs was asleep.
+ */
+
+unsigned long
+machtime()
+{
+ struct timeval tv;
+
+ if (gettimeofday(&tv, (struct timezone *)NULL) < 0) {
+ if (debug)
+ warnx("unable to get time of day");
+ return (0L);
+ }
+#define OFFSET ((u_long)25567 * 24*60*60)
+ return (htonl((long)(tv.tv_sec + OFFSET)));
+#undef OFFSET
+}
+
+/* ARGSUSED */
+void
+machtime_dg(s, sep)
+ int s;
+ struct servtab *sep;
+{
+ unsigned long result;
+ struct sockaddr_in sin;
+ int size;
+
+ size = sizeof(sin);
+ if (recvfrom(s, (char *)&result, sizeof(result), 0,
+ (struct sockaddr *)&sin, &size) < 0)
+ return;
+
+ if (check_loop(&sin, sep))
+ return;
+
+ result = machtime();
+ (void) sendto(s, (char *) &result, sizeof(result), 0,
+ (struct sockaddr *)&sin, sizeof(sin));
+}
+
+/* ARGSUSED */
+void
+machtime_stream(s, sep)
+ int s;
+ struct servtab *sep;
+{
+ unsigned long result;
+
+ result = machtime();
+ (void) write(s, (char *) &result, sizeof(result));
+}
+
+/*
+ * RFC1078 TCP Port Service Multiplexer (TCPMUX). Service connections to
+ * services based on the service name sent.
+ *
+ * Based on TCPMUX.C by Mark K. Lottor November 1988
+ * sri-nic::ps:<mkl>tcpmux.c
+ */
+
+#define MAX_SERV_LEN (256+2) /* 2 bytes for \r\n */
+#define strwrite(fd, buf) (void) write(fd, buf, sizeof(buf)-1)
+
+static int /* # of characters upto \r,\n or \0 */
+getline(fd, buf, len)
+ int fd;
+ char *buf;
+ int len;
+{
+ int count = 0, n;
+ struct sigaction sa;
+
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_handler = SIG_DFL;
+ sigaction(SIGALRM, &sa, (struct sigaction *)0);
+ do {
+ alarm(10);
+ n = read(fd, buf, len-count);
+ alarm(0);
+ if (n == 0)
+ return (count);
+ if (n < 0)
+ return (-1);
+ while (--n >= 0) {
+ if (*buf == '\r' || *buf == '\n' || *buf == '\0')
+ return (count);
+ count++;
+ buf++;
+ }
+ } while (count < len);
+ return (count);
+}
+
+struct servtab *
+tcpmux(s)
+ int s;
+{
+ struct servtab *sep;
+ char service[MAX_SERV_LEN+1];
+ int len;
+
+ /* Get requested service name */
+ if ((len = getline(s, service, MAX_SERV_LEN)) < 0) {
+ strwrite(s, "-Error reading service name\r\n");
+ return (NULL);
+ }
+ service[len] = '\0';
+
+ if (debug)
+ warnx("tcpmux: someone wants %s", service);
+
+ /*
+ * Help is a required command, and lists available services,
+ * one per line.
+ */
+ if (!strcasecmp(service, "help")) {
+ for (sep = servtab; sep; sep = sep->se_next) {
+ if (!ISMUX(sep))
+ continue;
+ (void)write(s,sep->se_service,strlen(sep->se_service));
+ strwrite(s, "\r\n");
+ }
+ return (NULL);
+ }
+
+ /* Try matching a service in inetd.conf with the request */
+ for (sep = servtab; sep; sep = sep->se_next) {
+ if (!ISMUX(sep))
+ continue;
+ if (!strcasecmp(service, sep->se_service)) {
+ if (ISMUXPLUS(sep)) {
+ strwrite(s, "+Go\r\n");
+ }
+ return (sep);
+ }
+ }
+ strwrite(s, "-Service not available\r\n");
+ return (NULL);
+}
diff --git a/usr.sbin/inetd/inetd.h b/usr.sbin/inetd/inetd.h
new file mode 100644
index 000000000000..ab78c734c54e
--- /dev/null
+++ b/usr.sbin/inetd/inetd.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 1983, 1991, 1993, 1994
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include <stdio.h>
+
+#define BUFSIZE 8192
+#define LINESIZ 72
+
+#define NORM_TYPE 0
+#define MUX_TYPE 1
+#define MUXPLUS_TYPE 2
+#define TTCP_TYPE 3
+#define ISMUX(sep) (((sep)->se_type == MUX_TYPE) || \
+ ((sep)->se_type == MUXPLUS_TYPE))
+#define ISMUXPLUS(sep) ((sep)->se_type == MUXPLUS_TYPE)
+#define ISTTCP(sep) ((sep)->se_type == TTCP_TYPE)
+
+struct servtab {
+ char *se_service; /* name of service */
+ int se_socktype; /* type of socket to use */
+ char *se_proto; /* protocol used */
+ int se_maxchild; /* max number of children */
+ int se_maxcpm; /* max connects per IP per minute */
+ int se_numchild; /* current number of children */
+ pid_t *se_pids; /* array of child pids */
+ char *se_user; /* user name to run as */
+ char *se_group; /* group name to run as */
+#ifdef LOGIN_CAP
+ char *se_class; /* login class name to run with */
+#endif
+ struct biltin *se_bi; /* if built-in, description */
+ char *se_server; /* server program */
+ char *se_server_name; /* server program without path */
+#define MAXARGV 20
+ char *se_argv[MAXARGV+1]; /* program arguments */
+ int se_fd; /* open descriptor */
+ struct sockaddr_in se_ctrladdr;/* bound address */
+ u_char se_type; /* type: normal, mux, or mux+ */
+ u_char se_checked; /* looked at during merge */
+ u_char se_accept; /* i.e., wait/nowait mode */
+ u_char se_rpc; /* ==1 if RPC service */
+ int se_rpc_prog; /* RPC program number */
+ u_int se_rpc_lowvers; /* RPC low version */
+ u_int se_rpc_highvers; /* RPC high version */
+ int se_count; /* number started since se_time */
+ struct timeval se_time; /* start of se_count */
+ struct servtab *se_next;
+};
+
+void chargen_dg __P((int, struct servtab *));
+void chargen_stream __P((int, struct servtab *));
+void close_sep __P((struct servtab *));
+void flag_signal __P((char));
+void flag_config __P((int));
+void config __P((void));
+void daytime_dg __P((int, struct servtab *));
+void daytime_stream __P((int, struct servtab *));
+void discard_dg __P((int, struct servtab *));
+void discard_stream __P((int, struct servtab *));
+void echo_dg __P((int, struct servtab *));
+void echo_stream __P((int, struct servtab *));
+void endconfig __P((void));
+struct servtab *enter __P((struct servtab *));
+void freeconfig __P((struct servtab *));
+struct servtab *getconfigent __P((void));
+void iderror __P((int, int, int, int));
+void ident_stream __P((int, struct servtab *));
+void machtime_dg __P((int, struct servtab *));
+void machtime_stream __P((int, struct servtab *));
+int matchservent __P((char *, char *, char *));
+char *newstr __P((char *));
+char *nextline __P((FILE *));
+void print_service __P((char *, struct servtab *));
+void addchild __P((struct servtab *, int));
+void flag_reapchild __P((int));
+void reapchild __P((void));
+void enable __P((struct servtab *));
+void disable __P((struct servtab *));
+void flag_retry __P((int));
+void retry __P((void));
+int setconfig __P((void));
+void setup __P((struct servtab *));
+char *sskip __P((char **));
+char *skip __P((char **));
+struct servtab *tcpmux __P((int));
+int cpmip __P((struct servtab *, int));
+void inetd_setproctitle __P((char *, int));
+
+void unregisterrpc __P((register struct servtab *sep));
+
+struct biltin {
+ char *bi_service; /* internally provided service name */
+ int bi_socktype; /* type of socket supported */
+ short bi_fork; /* 1 if should fork before call */
+ int bi_maxchild; /* max number of children, -1=default */
+ void (*bi_fn)(); /* function which performs it */
+};
diff --git a/usr.sbin/memcontrol/memcontrol.c b/usr.sbin/memcontrol/memcontrol.c
new file mode 100644
index 000000000000..f4af0cddea5a
--- /dev/null
+++ b/usr.sbin/memcontrol/memcontrol.c
@@ -0,0 +1,341 @@
+/*-
+ * Copyright (c) 1999 Michael Smith <msmith@freebsd.org>
+ * 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/memrange.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+struct
+{
+ char *name;
+ int val;
+ int kind;
+#define MDF_SETTABLE (1<<0)
+} attrnames[] = {
+ {"uncacheable", MDF_UNCACHEABLE, MDF_SETTABLE},
+ {"write-combine", MDF_WRITECOMBINE, MDF_SETTABLE},
+ {"write-through", MDF_WRITETHROUGH, MDF_SETTABLE},
+ {"write-back", MDF_WRITEBACK, MDF_SETTABLE},
+ {"write-protect", MDF_WRITEPROTECT, MDF_SETTABLE},
+ {"fixed-base", MDF_FIXBASE, 0},
+ {"fixed-length", MDF_FIXLEN, 0},
+ {"set-by-firmware", MDF_FIRMWARE, 0},
+ {"active", MDF_ACTIVE, MDF_SETTABLE},
+ {"bogus", MDF_BOGUS, 0},
+ {NULL, 0, 0}
+};
+
+static void listfunc(int memfd, int argc, char *argv[]);
+static void setfunc(int memfd, int argc, char *argv[]);
+static void clearfunc(int memfd, int argc, char *argv[]);
+static void helpfunc(int memfd, int argc, char *argv[]);
+static void help(char *what);
+
+struct
+{
+ char *cmd;
+ char *desc;
+ void (*func)(int memfd, int argc, char *argv[]);
+} functions[] = {
+ {"list",
+ "List current memory range attributes\n"
+ " list [-a]\n"
+ " -a list all range slots, even those that are inactive",
+ listfunc},
+ {"set",
+ "Set memory range attributes\n"
+ " set -b <base> -l <length> -o <owner> <attribute>\n"
+ " <base> memory range base address\n"
+ " <length> length of memory range in bytes, power of 2\n"
+ " <owner> text identifier for this setting (7 char max)\n"
+ " <attribute> attribute(s) to be applied to this range:\n"
+ " uncacheable\n"
+ " write-combine\n"
+ " write-through\n"
+ " write-back\n"
+ " write-protect",
+ setfunc},
+ {"clear",
+ "Clear memory range attributes\n"
+ " clear -o <owner>\n"
+ " <owner> all ranges with this owner will be cleared\n"
+ " clear -b <base> -l <length>\n"
+ " <base> memory range base address\n"
+ " <length> length of memory range in bytes, power of 2\n"
+ " Base and length must exactly match an existing range",
+ clearfunc},
+ {NULL, NULL, helpfunc}
+};
+
+int
+main(int argc, char *argv[])
+{
+ int i, memfd;
+
+ if (argc < 2) {
+ help(NULL);
+ } else {
+ if ((memfd = open("/dev/mem", O_RDONLY)) == -1)
+ err(1, "can't open /dev/mem");
+
+ for (i = 0; functions[i].cmd != NULL; i++)
+ if (!strcmp(argv[1], functions[i].cmd))
+ break;
+ functions[i].func(memfd, argc - 1, argv + 1);
+ close(memfd);
+ }
+ return(0);
+}
+
+static struct mem_range_desc *
+mrgetall(int memfd, int *nmr)
+{
+ struct mem_range_desc *mrd;
+ struct mem_range_op mro;
+
+ mro.mo_arg[0] = 0;
+ if (ioctl(memfd, MEMRANGE_GET, &mro))
+ err(1, "can't size range descriptor array");
+
+ *nmr = mro.mo_arg[0];
+ mrd = malloc(*nmr * sizeof(struct mem_range_desc));
+ if (mrd == NULL)
+ errx(1, "can't allocate %d bytes for %d range descriptors",
+ *nmr * sizeof(struct mem_range_desc), *nmr);
+
+ mro.mo_arg[0] = *nmr;
+ mro.mo_desc = mrd;
+ if (ioctl(memfd, MEMRANGE_GET, &mro))
+ err(1, "can't fetch range descriptor array");
+
+ return(mrd);
+}
+
+
+static void
+listfunc(int memfd, int argc, char *argv[])
+{
+ struct mem_range_desc *mrd;
+ int nd, i, j;
+ int error;
+ int ch;
+ int showall = 0;
+ char *owner;
+
+ owner = NULL;
+ while ((ch = getopt(argc, argv, "ao:")) != -1)
+ switch(ch) {
+ case 'a':
+ showall = 1;
+ break;
+ case 'o':
+ owner = strdup(optarg);
+ break;
+ case '?':
+ default:
+ help("list");
+ }
+
+ mrd = mrgetall(memfd, &nd);
+
+ for (i = 0; i < nd; i++) {
+ if (!showall && !(mrd[i].mr_flags & MDF_ACTIVE))
+ continue;
+ if (owner && strcmp(mrd[i].mr_owner, owner))
+ continue;
+ printf("%qx/%qx %.8s ", mrd[i].mr_base, mrd[i].mr_len,
+ mrd[i].mr_owner[0] ? mrd[i].mr_owner : "-");
+ for (j = 0; attrnames[j].name != NULL; j++)
+ if (mrd[i].mr_flags & attrnames[j].val)
+ printf("%s ", attrnames[j].name);
+ printf("\n");
+ }
+ free(mrd);
+ if (owner)
+ free(owner);
+}
+
+static void
+setfunc(int memfd, int argc, char *argv[])
+{
+ struct mem_range_desc mrd;
+ struct mem_range_op mro;
+ int i;
+ int ch;
+ char *ep;
+
+ mrd.mr_base = 0;
+ mrd.mr_len = 0;
+ mrd.mr_flags = 0;
+ strcpy(mrd.mr_owner, "user");
+ while ((ch = getopt(argc, argv, "b:l:o:")) != -1)
+ switch(ch) {
+ case 'b':
+ mrd.mr_base = strtouq(optarg, &ep, 0);
+ if ((ep == optarg) || (*ep != 0))
+ help("set");
+ break;
+ case 'l':
+ mrd.mr_len = strtouq(optarg, &ep, 0);
+ if ((ep == optarg) || (*ep != 0))
+ help("set");
+ break;
+ case 'o':
+ if ((*optarg == 0) || (strlen(optarg) > 7))
+ help("set");
+ strcpy(mrd.mr_owner, optarg);
+ break;
+
+ case '?':
+ default:
+ help("set");
+ }
+
+ if (mrd.mr_len == 0)
+ help("set");
+
+ argc -= optind;
+ argv += optind;
+
+ while(argc--) {
+ for (i = 0; attrnames[i].name != NULL; i++) {
+ if (!strcmp(attrnames[i].name, argv[0])) {
+ if (!attrnames[i].kind & MDF_SETTABLE)
+ help("flags");
+ mrd.mr_flags |= attrnames[i].val;
+ break;
+ }
+ }
+ if (attrnames[i].name == NULL)
+ help("flags");
+ argv++;
+ }
+
+ mro.mo_desc = &mrd;
+ mro.mo_arg[0] = 0;
+ if (ioctl(memfd, MEMRANGE_SET, &mro))
+ err(1, "can't set range");
+}
+
+static void
+clearfunc(int memfd, int argc, char *argv[])
+{
+ struct mem_range_desc mrd, *mrdp;
+ struct mem_range_op mro;
+ int i, nd;
+ int ch;
+ char *ep, *owner;
+
+ mrd.mr_base = 0;
+ mrd.mr_len = 0;
+ owner = NULL;
+ while ((ch = getopt(argc, argv, "b:l:o:")) != -1)
+ switch(ch) {
+ case 'b':
+ mrd.mr_base = strtouq(optarg, &ep, 0);
+ if ((ep == optarg) || (*ep != 0))
+ help("clear");
+ break;
+ case 'l':
+ mrd.mr_len = strtouq(optarg, &ep, 0);
+ if ((ep == optarg) || (*ep != 0))
+ help("clear");
+ break;
+ case 'o':
+ if ((*optarg == 0) || (strlen(optarg) > 7))
+ help("clear");
+ owner = strdup(optarg);
+ break;
+
+ case '?':
+ default:
+ help("clear");
+ }
+
+ if (owner != NULL) {
+ /* clear-by-owner */
+ if ((mrd.mr_base != 0) || (mrd.mr_len != 0))
+ help("clear");
+
+ mrdp = mrgetall(memfd, &nd);
+ mro.mo_arg[0] = MEMRANGE_SET_REMOVE;
+ for (i = 0; i < nd; i++) {
+ if (!strcmp(owner, mrdp[i].mr_owner) &&
+ (mrdp[i].mr_flags & MDF_ACTIVE) &&
+ !(mrdp[i].mr_flags & MDF_FIXACTIVE)) {
+
+ mro.mo_desc = mrdp + i;
+ if (ioctl(memfd, MEMRANGE_SET, &mro))
+ warn("couldn't clear range owned by '%s'", owner);
+ }
+ }
+ } else if ((mrd.mr_base != 0) && (mrd.mr_len != 0)) {
+ /* clear-by-base/len */
+ mro.mo_arg[0] = MEMRANGE_SET_REMOVE;
+ mro.mo_desc = &mrd;
+ if (ioctl(memfd, MEMRANGE_SET, &mro))
+ err(1, "couldn't clear range");
+ } else {
+ help("clear");
+ }
+}
+
+static void
+helpfunc(int memfd, int argc, char *argv[])
+{
+ help(argv[1]);
+}
+
+static void
+help(char *what)
+{
+ int i;
+
+ if (what != NULL) {
+ /* find a function that matches */
+ for (i = 0; functions[i].cmd != NULL; i++)
+ if (!strcmp(what, functions[i].cmd)) {
+ fprintf(stderr, "%s\n", functions[i].desc);
+ return;
+ }
+ fprintf(stderr, "Unknown command '%s'\n", what);
+ }
+
+ /* print general help */
+ fprintf(stderr, "Valid commands are :\n");
+ for (i = 0; functions[i].cmd != NULL; i++)
+ fprintf(stderr, " %s\n", functions[i].cmd);
+ fprintf(stderr, "Use help <command> for command-specific help\n");
+}
diff --git a/usr.sbin/ppp/nat_cmd.h b/usr.sbin/ppp/nat_cmd.h
new file mode 100644
index 000000000000..1ce19d10c76d
--- /dev/null
+++ b/usr.sbin/ppp/nat_cmd.h
@@ -0,0 +1,15 @@
+/*-
+ * The code in this file was written by Eivind Eklund <perhaps@yes.no>,
+ * who places it in the public domain without restriction.
+ *
+ * $FreeBSD$
+ */
+
+struct cmdargs;
+
+extern int nat_RedirectPort(struct cmdargs const *);
+extern int nat_RedirectAddr(struct cmdargs const *);
+extern int nat_ProxyRule(struct cmdargs const *);
+extern int nat_Pptp(struct cmdargs const *);
+
+extern struct layer natlayer;
diff --git a/usr.sbin/pw/pw_vpw.c b/usr.sbin/pw/pw_vpw.c
new file mode 100644
index 000000000000..ef12437a15ef
--- /dev/null
+++ b/usr.sbin/pw/pw_vpw.c
@@ -0,0 +1,316 @@
+/*-
+ * Copyright (C) 1996
+ * David L. Nugent. 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 DAVID L. NUGENT 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 DAVID L. NUGENT 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 const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/param.h>
+
+#include "pwupd.h"
+
+static FILE * pwd_fp = NULL;
+
+void
+vendpwent(void)
+{
+ if (pwd_fp != NULL) {
+ fclose(pwd_fp);
+ pwd_fp = NULL;
+ }
+}
+
+void
+vsetpwent(void)
+{
+ vendpwent();
+}
+
+static struct passwd *
+vnextpwent(char const * nam, uid_t uid, int doclose)
+{
+ struct passwd * pw = NULL;
+ static char pwtmp[1024];
+
+ strncpy(pwtmp, getpwpath(_MASTERPASSWD), sizeof pwtmp);
+ pwtmp[sizeof pwtmp - 1] = '\0';
+
+ if (pwd_fp != NULL || (pwd_fp = fopen(pwtmp, "r")) != NULL) {
+ int done = 0;
+
+ static struct passwd pwd;
+
+ while (!done && fgets(pwtmp, sizeof pwtmp, pwd_fp) != NULL)
+ {
+ int i, quickout = 0;
+ char * q;
+ char * p = strchr(pwtmp, '\n');
+
+ if (p == NULL) {
+ while (fgets(pwtmp, sizeof pwtmp, pwd_fp) != NULL && strchr(pwtmp, '\n')==NULL)
+ ; /* Skip long lines */
+ continue;
+ }
+
+ /* skip comments & empty lines */
+ if (*pwtmp =='\n' || *pwtmp == '#')
+ continue;
+
+ i = 0;
+ q = p = pwtmp;
+ bzero(&pwd, sizeof pwd);
+ while (!quickout && (p = strsep(&q, ":\n")) != NULL) {
+ switch (i++)
+ {
+ case 0: /* username */
+ pwd.pw_name = p;
+ if (nam) {
+ if (strcmp(nam, p) == 0)
+ done = 1;
+ else
+ quickout = 1;
+ }
+ break;
+ case 1: /* password */
+ pwd.pw_passwd = p;
+ break;
+ case 2: /* uid */
+ pwd.pw_uid = atoi(p);
+ if (uid != (uid_t)-1) {
+ if (uid == pwd.pw_uid)
+ done = 1;
+ else
+ quickout = 1;
+ }
+ break;
+ case 3: /* gid */
+ pwd.pw_gid = atoi(p);
+ break;
+ case 4: /* class */
+ if (nam == NULL && uid == (uid_t)-1)
+ done = 1;
+ pwd.pw_class = p;
+ break;
+ case 5: /* change */
+ pwd.pw_change = (time_t)atol(p);
+ break;
+ case 6: /* expire */
+ pwd.pw_expire = (time_t)atol(p);
+ break;
+ case 7: /* gecos */
+ pwd.pw_gecos = p;
+ break;
+ case 8: /* directory */
+ pwd.pw_dir = p;
+ break;
+ case 9: /* shell */
+ pwd.pw_shell = p;
+ break;
+ }
+ }
+ }
+ if (doclose)
+ vendpwent();
+ if (done && pwd.pw_name) {
+ pw = &pwd;
+
+ #define CKNULL(s) s = s ? s : ""
+ CKNULL(pwd.pw_passwd);
+ CKNULL(pwd.pw_class);
+ CKNULL(pwd.pw_gecos);
+ CKNULL(pwd.pw_dir);
+ CKNULL(pwd.pw_shell);
+ }
+ }
+ return pw;
+}
+
+struct passwd *
+vgetpwent(void)
+{
+ return vnextpwent(NULL, -1, 0);
+}
+
+struct passwd *
+vgetpwuid(uid_t uid)
+{
+ return vnextpwent(NULL, uid, 1);
+}
+
+struct passwd *
+vgetpwnam(const char * nam)
+{
+ return vnextpwent(nam, -1, 1);
+}
+
+int vpwdb(char *arg, ...)
+{
+ arg=arg;
+ return 0;
+}
+
+
+
+static FILE * grp_fp = NULL;
+
+void
+vendgrent(void)
+{
+ if (grp_fp != NULL) {
+ fclose(grp_fp);
+ grp_fp = NULL;
+ }
+}
+
+int
+vsetgrent(void)
+{
+ vendgrent();
+ return 0;
+}
+
+static struct group *
+vnextgrent(char const * nam, gid_t gid, int doclose)
+{
+ struct group * gr = NULL;
+
+ static char * grtmp = NULL;
+ static int grlen = 0;
+ static char ** mems = NULL;
+ static int memlen = 0;
+
+ extendline(&grtmp, &grlen, MAXPATHLEN);
+ strncpy(grtmp, getgrpath(_GROUP), MAXPATHLEN);
+ grtmp[MAXPATHLEN - 1] = '\0';
+
+ if (grp_fp != NULL || (grp_fp = fopen(grtmp, "r")) != NULL) {
+ int done = 0;
+
+ static struct group grp;
+
+ while (!done && fgets(grtmp, grlen, grp_fp) != NULL)
+ {
+ int i, quickout = 0;
+ int mno = 0;
+ char * q, * p;
+ char * sep = ":\n";
+
+ if ((p = strchr(grtmp, '\n')) == NULL) {
+ int l;
+ extendline(&grtmp, &grlen, grlen + PWBUFSZ);
+ l = strlen(grtmp);
+ if (fgets(grtmp + l, grlen - l, grp_fp) == NULL)
+ break; /* No newline terminator on last line */
+ }
+ /* Skip comments and empty lines */
+ if (*grtmp == '\n' || *grtmp == '#')
+ continue;
+ i = 0;
+ q = p = grtmp;
+ bzero(&grp, sizeof grp);
+ extendarray(&mems, &memlen, 200);
+ while (!quickout && (p = strsep(&q, sep)) != NULL) {
+ switch (i++)
+ {
+ case 0: /* groupname */
+ grp.gr_name = p;
+ if (nam) {
+ if (strcmp(nam, p) == 0)
+ done = 1;
+ else
+ quickout = 1;
+ }
+ break;
+ case 1: /* password */
+ grp.gr_passwd = p;
+ break;
+ case 2: /* gid */
+ grp.gr_gid = atoi(p);
+ if (gid != (gid_t)-1) {
+ if (gid == (gid_t)grp.gr_gid)
+ done = 1;
+ else
+ quickout = 1;
+ } else if (nam == NULL)
+ done = 1;
+ break;
+ case 3:
+ q = p;
+ sep = ",\n";
+ break;
+ default:
+ if (*p) {
+ extendarray(&mems, &memlen, mno + 2);
+ mems[mno++] = p;
+ }
+ break;
+ }
+ }
+ grp.gr_mem = mems;
+ mems[mno] = NULL;
+ }
+ if (doclose)
+ vendgrent();
+ if (done && grp.gr_name) {
+ gr = &grp;
+
+ CKNULL(grp.gr_passwd);
+ }
+ }
+ return gr;
+}
+
+struct group *
+vgetgrent(void)
+{
+ return vnextgrent(NULL, -1, 0);
+}
+
+
+struct group *
+vgetgrgid(gid_t gid)
+{
+ return vnextgrent(NULL, gid, 1);
+}
+
+struct group *
+vgetgrnam(const char * nam)
+{
+ return vnextgrent(nam, -1, 1);
+}
+
+int
+vgrdb(char *arg, ...)
+{
+ arg=arg;
+ return 0;
+}
+