diff options
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; +} + |
