diff options
| author | cvs2svn <cvs2svn@FreeBSD.org> | 2000-10-30 14:49:27 +0000 |
|---|---|---|
| committer | cvs2svn <cvs2svn@FreeBSD.org> | 2000-10-30 14:49:27 +0000 |
| commit | 4cc01a5a9b96095be1eaab76a18ffdf868f4ee96 (patch) | |
| tree | 0990600be3b5b619add9593e2dc7e95fd6ad5cd8 | |
| parent | 5c6ab3f47bc128e9725b235983fdaf82204ca86c (diff) | |
Notes
| -rw-r--r-- | etc/rc.firewall6 | 257 | ||||
| -rw-r--r-- | lib/csu/alpha/crti.S | 51 | ||||
| -rw-r--r-- | lib/csu/alpha/crtn.S | 43 | ||||
| -rw-r--r-- | sys/crypto/rijndael/rijndael.h | 3 | ||||
| -rw-r--r-- | sys/dev/awi/awi_wep.c | 528 | ||||
| -rw-r--r-- | sys/dev/awi/awi_wicfg.c | 625 | ||||
| -rw-r--r-- | sys/dev/usb/uscanner.c | 658 | ||||
| -rw-r--r-- | sys/i4b/layer1/i4b_l1lib.c | 76 | ||||
| -rw-r--r-- | sys/i4b/layer1/ifpi/i4b_ifpi_isac.c | 666 | ||||
| -rw-r--r-- | sys/i4b/layer1/ifpi/i4b_ifpi_l1.c | 244 | ||||
| -rw-r--r-- | sys/i4b/layer1/ifpi/i4b_ifpi_l1fsm.c | 517 | ||||
| -rw-r--r-- | sys/i4b/layer1/ifpnp/i4b_ifpnp_isac.c | 666 | ||||
| -rw-r--r-- | sys/i4b/layer1/ifpnp/i4b_ifpnp_l1.c | 244 | ||||
| -rw-r--r-- | sys/i4b/layer1/ifpnp/i4b_ifpnp_l1fsm.c | 517 | ||||
| -rw-r--r-- | sys/net/if_ieee80211.h | 171 |
15 files changed, 5266 insertions, 0 deletions
diff --git a/etc/rc.firewall6 b/etc/rc.firewall6 new file mode 100644 index 000000000000..df2d7a23c8f6 --- /dev/null +++ b/etc/rc.firewall6 @@ -0,0 +1,257 @@ +############ +# Setup system for IPv6 firewall service. +# $FreeBSD$ + +# Suck in the configuration variables. +if [ -z "${source_rc_confs_defined}" ]; then + if [ -r /etc/defaults/rc.conf ]; then + . /etc/defaults/rc.conf + source_rc_confs + elif [ -r /etc/rc.conf ]; then + . /etc/rc.conf + fi +fi + +############ +# Define the firewall type in /etc/rc.conf. Valid values are: +# open - will allow anyone in +# client - will try to protect just this machine +# simple - will try to protect a whole network +# closed - totally disables IP services except via lo0 interface +# UNKNOWN - disables the loading of firewall rules. +# filename - will load the rules in the given filename (full path required) +# +# For ``client'' and ``simple'' the entries below should be customized +# appropriately. + +############ +# +# If you don't know enough about packet filtering, we suggest that you +# take time to read this book: +# +# Building Internet Firewalls +# Brent Chapman and Elizabeth Zwicky +# +# O'Reilly & Associates, Inc +# ISBN 1-56592-124-0 +# http://www.ora.com/ +# +# For a more advanced treatment of Internet Security read: +# +# Firewalls & Internet Security +# Repelling the wily hacker +# William R. Cheswick, Steven M. Bellowin +# +# Addison-Wesley +# ISBN 0-201-6337-4 +# http://www.awl.com/ +# + +if [ -n "${1}" ]; then + ipv6_firewall_type="${1}" +fi + +############ +# Set quiet mode if requested +# +case ${ipv6_firewall_quiet} in +[Yy][Ee][Ss]) + fw6cmd="/sbin/ip6fw -q" + ;; +*) + fw6cmd="/sbin/ip6fw" + ;; +esac + +############ +# Flush out the list before we begin. +# +${fw6cmd} -f flush + +############ +# If you just configured ipfw in the kernel as a tool to solve network +# problems or you just want to disallow some particular kinds of traffic +# then you will want to change the default policy to open. You can also +# do this as your only action by setting the ipv6_firewall_type to ``open''. +# +# ${fw6cmd} add 65000 pass all from any to any + +############ +# Only in rare cases do you want to change these rules +# +${fw6cmd} add 100 pass all from any to any via lo0 +# +# ND +# +# DAD +${fw6cmd} add pass ipv6-icmp from ff02::/16 to :: +${fw6cmd} add pass ipv6-icmp from :: to ff02::/16 +# RS, RA, NS, NA, redirect... +${fw6cmd} add pass ipv6-icmp from fe80::/10 to fe80::/10 +${fw6cmd} add pass ipv6-icmp from fe80::/10 to ff02::/16 + + +# Prototype setups. +# +case ${ipv6_firewall_type} in +[Oo][Pp][Ee][Nn]) + ${fw6cmd} add 65000 pass all from any to any + ;; + +[Cc][Ll][Ii][Ee][Nn][Tt]) + ############ + # This is a prototype setup that will protect your system somewhat + # against people from outside your own network. + ############ + + # set these to your network and prefixlen and ip + # + # This needs more work + # + net="3ffe:505:2:1::" + prefixlen="64" + ip="3ffe:505:2:1::1" + + # Allow any traffic to or from my own net. + ${fw6cmd} add pass all from ${ip} to ${net}/${prefixlen} + ${fw6cmd} add pass all from ${net}/${prefixlen} to ${ip} + + # Allow TCP through if setup succeeded + ${fw6cmd} add pass tcp from any to any established + + # Allow IP fragments to pass through + ${fw6cmd} add pass all from any to any frag + + # Allow setup of incoming email + ${fw6cmd} add pass tcp from any to ${ip} 25 setup + + # Allow setup of outgoing TCP connections only + ${fw6cmd} add pass tcp from ${ip} to any setup + + # Disallow setup of all other TCP connections + ${fw6cmd} add deny tcp from any to any setup + + # Allow DNS queries out in the world + ${fw6cmd} add pass udp from any 53 to ${ip} + ${fw6cmd} add pass udp from ${ip} to any 53 + + # Allow NTP queries out in the world + ${fw6cmd} add pass udp from any 123 to ${ip} + ${fw6cmd} add pass udp from ${ip} to any 123 + + # Everything else is denied by default, unless the + # IPFIREWALL_DEFAULT_TO_ACCEPT option is set in your kernel + # config file. + ;; + +[Ss][Ii][Mm][Pp][Ll][Ee]) + ############ + # This is a prototype setup for a simple firewall. Configure this + # machine as a named server and ntp server, and point all the machines + # on the inside at this machine for those services. + ############ + + # set these to your outside interface network and prefixlen and ip + oif="ed0" + onet="3ffe:505:2:1::" + oprefixlen="64" + oip="3ffe:505:2:1::1" + + # set these to your inside interface network and prefixlen and ip + iif="ed1" + inet="3ffe:505:2:2::" + iprefixlen="64" + iip="3ffe:505:2:2::1" + + # Stop spoofing + ${fw6cmd} add deny all from ${inet}/${iprefixlen} to any in via ${oif} + ${fw6cmd} add deny all from ${onet}/${oprefixlen} to any in via ${iif} + + # Stop site-local on the outside interface + ${fw6cmd} add deny all from ff02::/16 to any via ${oif} + ${fw6cmd} add deny all from any to ff02::/16 via ${oif} + + # Disallow "internal" addresses to appear on the wire. + ${fw6cmd} add deny all from ::ffff:0.0.0.0/96 to any via ${oif} + ${fw6cmd} add deny all from any to ::ffff:0.0.0.0/96 via ${oif} + + # Disallow packets to malicious IPv4 compatible prefix. + ${fw6cmd} add deny all from ::224.0.0.0/100 to any via ${oif} + ${fw6cmd} add deny all from any to ::224.0.0.0/100 via ${oif} + ${fw6cmd} add deny all from ::127.0.0.0/104 to any via ${oif} + ${fw6cmd} add deny all from any to ::127.0.0.0/104 via ${oif} + ${fw6cmd} add deny all from ::0.0.0.0/104 to any via ${oif} + ${fw6cmd} add deny all from any to ::0.0.0.0/104 via ${oif} + ${fw6cmd} add deny all from ::255.0.0.0/104 to any via ${oif} + ${fw6cmd} add deny all from any to ::255.0.0.0/104 via ${oif} + + ${fw6cmd} add deny all from ::0.0.0.0/96 to any via ${oif} + ${fw6cmd} add deny all from any to ::0.0.0.0/96 via ${oif} + + # Disallow packets to malicious 6to4 prefix. + ${fw6cmd} add deny all from 2002:e000::/20 to any via ${oif} + ${fw6cmd} add deny all from any to 2002:e000::/20 via ${oif} + ${fw6cmd} add deny all from 2002:7f00::/24 to any via ${oif} + ${fw6cmd} add deny all from any to 2002:7f00::/24 via ${oif} + ${fw6cmd} add deny all from 2002:0000::/24 to any via ${oif} + ${fw6cmd} add deny all from any to 2002:0000::/24 via ${oif} + ${fw6cmd} add deny all from 2002:ff00::/24 to any via ${oif} + ${fw6cmd} add deny all from any to 2002:ff00::/24 via ${oif} + + ${fw6cmd} add deny all from 2002:0a00::/24 to any via ${oif} + ${fw6cmd} add deny all from any to 2002:0a00::/24 via ${oif} + ${fw6cmd} add deny all from 2002:ac10::/28 to any via ${oif} + ${fw6cmd} add deny all from any to 2002:ac10::/28 via ${oif} + ${fw6cmd} add deny all from 2002:c0a8::/32 to any via ${oif} + ${fw6cmd} add deny all from any to 2002:c0a8::/32 via ${oif} + + ${fw6cmd} add deny all from ff05::/32 to any via ${oif} + ${fw6cmd} add deny all from any to ff05::/32 via ${oif} + + # Allow TCP through if setup succeeded + ${fw6cmd} add pass tcp from any to any established + + # Allow IP fragments to pass through + ${fw6cmd} add pass all from any to any frag + + # Allow setup of incoming email + ${fw6cmd} add pass tcp from any to ${oip} 25 setup + + # Allow access to our DNS + ${fw6cmd} add pass tcp from any to ${oip} 53 setup + ${fw6cmd} add pass udp from any to ${oip} 53 + ${fw6cmd} add pass udp from ${oip} 53 to any + + # Allow access to our WWW + ${fw6cmd} add pass tcp from any to ${oip} 80 setup + + # Reject&Log all setup of incoming connections from the outside + ${fw6cmd} add deny log tcp from any to any in via ${oif} setup + + # Allow setup of any other TCP connection + ${fw6cmd} add pass tcp from any to any setup + + # Allow DNS queries out in the world + ${fw6cmd} add pass udp from any 53 to ${oip} + ${fw6cmd} add pass udp from ${oip} to any 53 + + # Allow NTP queries out in the world + ${fw6cmd} add pass udp from any 123 to ${oip} + ${fw6cmd} add pass udp from ${oip} to any 123 + + # RIPng + #${fw6cmd} add pass udp from fe80::/10 521 to ff02::9 521 + + # Everything else is denied by default, unless the + # IPFIREWALL_DEFAULT_TO_ACCEPT option is set in your kernel + # config file. + ;; + +[Uu][Nn][Kk][Nn][Oo][Ww][Nn]) + ;; +*) + if [ -r "${ipv6_firewall_type}" ]; then + ${fw6cmd} ${ipv6_firewall_flags} ${ipv6_firewall_type} + fi + ;; +esac diff --git a/lib/csu/alpha/crti.S b/lib/csu/alpha/crti.S new file mode 100644 index 000000000000..3f58a0b433c7 --- /dev/null +++ b/lib/csu/alpha/crti.S @@ -0,0 +1,51 @@ +/*- + * Copyright 2000 David O'Brien, John D. Polstra. + * 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 ``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$ + */ + + .section .init,"ax",@progbits + .align 5 + .globl _init +_init: + ldgp $29,0($27) +$_init..ng: + lda $30,-16($30) + stq $26,0($30) + stq $15,8($30) + mov $30,$15 + .align 5 + + .section .fini,"ax",@progbits + .align 5 + .globl _fini +_fini: + ldgp $29,0($27) +$_fini..ng: + lda $30,-16($30) + stq $26,0($30) + stq $15,8($30) + mov $30,$15 + .align 5 + diff --git a/lib/csu/alpha/crtn.S b/lib/csu/alpha/crtn.S new file mode 100644 index 000000000000..63024ffe2452 --- /dev/null +++ b/lib/csu/alpha/crtn.S @@ -0,0 +1,43 @@ +/*- + * Copyright 2000 David O'Brien, John D. Polstra. + * 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 ``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$ + */ + + .section .init,"ax",@progbits + ldgp $29,0($26) + mov $15,$30 + ldq $26,0($30) + ldq $15,8($30) + lda $30,16($30) + ret $31,($26),1 + + + .section .fini,"ax",@progbits + ldgp $29,0($26) + mov $15,$30 + ldq $26,0($30) + ldq $15,8($30) + lda $30,16($30) + ret $31,($26),1 diff --git a/sys/crypto/rijndael/rijndael.h b/sys/crypto/rijndael/rijndael.h new file mode 100644 index 000000000000..8f2cc895b433 --- /dev/null +++ b/sys/crypto/rijndael/rijndael.h @@ -0,0 +1,3 @@ +/* $KAME: rijndael.h,v 1.2 2000/10/02 17:14:27 itojun Exp $ */ + +#include <crypto/rijndael/rijndael-api-fst.h> diff --git a/sys/dev/awi/awi_wep.c b/sys/dev/awi/awi_wep.c new file mode 100644 index 000000000000..a8f76ec793e0 --- /dev/null +++ b/sys/dev/awi/awi_wep.c @@ -0,0 +1,528 @@ +/* $NetBSD: awi_wep.c,v 1.4 2000/08/14 11:28:03 onoe Exp $ */ +/* $FreeBSD$ */ + +/* + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Atsushi Onoe. + * + * 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 NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* + * WEP support framework for the awi driver. + * + * No actual encryption capability is provided here, but any can be added + * to awi_wep_algo table below. + * + * Note that IEEE802.11 specification states WEP uses RC4 with 40bit key, + * which is a proprietary encryption algorithm available under license + * from RSA Data Security Inc. Using another algorithm, includes null + * encryption provided here, the awi driver cannot be able to communicate + * with other stations. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/mbuf.h> +#include <sys/malloc.h> +#include <sys/socket.h> +#include <sys/errno.h> +#include <sys/sockio.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 4 +#include <sys/bus.h> +#else +#include <sys/device.h> +#endif + +#include <net/if.h> +#include <net/if_dl.h> +#ifdef __FreeBSD__ +#include <net/ethernet.h> +#include <net/if_arp.h> +#else +#include <net/if_ether.h> +#endif +#include <net/if_media.h> +#include <net/if_ieee80211.h> + +#include <machine/cpu.h> +#include <machine/bus.h> +#ifdef __FreeBSD__ +#endif + +#ifdef __NetBSD__ +#include <dev/ic/am79c930reg.h> +#include <dev/ic/am79c930var.h> +#include <dev/ic/awireg.h> +#include <dev/ic/awivar.h> + +#include <crypto/arc4/arc4.h> +#endif + +#ifdef __FreeBSD__ +#include <dev/awi/am79c930reg.h> +#include <dev/awi/am79c930var.h> +#include <dev/awi/awireg.h> +#include <dev/awi/awivar.h> + +#include <crypto/rc4/rc4.h> +static __inline int +arc4_ctxlen(void) +{ + return sizeof(struct rc4_state); +} + +static __inline void +arc4_setkey(void *ctx, u_int8_t *key, int keylen) +{ + rc4_init(ctx, key, keylen); +} + +static __inline void +arc4_encrypt(void *ctx, u_int8_t *dst, u_int8_t *src, int len) +{ + rc4_crypt(ctx, src, dst, len); +} +#endif + +static void awi_crc_init __P((void)); +static u_int32_t awi_crc_update __P((u_int32_t crc, u_int8_t *buf, int len)); + +static int awi_null_ctxlen __P((void)); +static void awi_null_setkey __P((void *ctx, u_int8_t *key, int keylen)); +static void awi_null_copy __P((void *ctx, u_int8_t *dst, u_int8_t *src, int len)); + +/* XXX: the order should be known to wiconfig/user */ + +static struct awi_wep_algo awi_wep_algo[] = { +/* 0: no wep */ + { "no" }, /* dummy for no wep */ + +/* 1: normal wep (arc4) */ + { "arc4", arc4_ctxlen, arc4_setkey, + arc4_encrypt, arc4_encrypt }, + +/* 2: debug wep (null) */ + { "null", awi_null_ctxlen, awi_null_setkey, + awi_null_copy, awi_null_copy }, + /* dummy for wep without encryption */ +}; + +int +awi_wep_setnwkey(sc, nwkey) + struct awi_softc *sc; + struct ieee80211_nwkey *nwkey; +{ + int i, len, error; + u_int8_t keybuf[AWI_MAX_KEYLEN]; + + if (nwkey->i_defkid <= 0 || + nwkey->i_defkid > IEEE80211_WEP_NKID) + return EINVAL; + error = 0; + for (i = 0; i < IEEE80211_WEP_NKID; i++) { + if (nwkey->i_key[i].i_keydat == NULL) + continue; + len = nwkey->i_key[i].i_keylen; + if (len > sizeof(keybuf)) { + error = EINVAL; + break; + } + error = copyin(nwkey->i_key[i].i_keydat, keybuf, len); + if (error) + break; + error = awi_wep_setkey(sc, i, keybuf, len); + if (error) + break; + } + if (error == 0) { + sc->sc_wep_defkid = nwkey->i_defkid - 1; + error = awi_wep_setalgo(sc, nwkey->i_wepon); + if (error == 0 && sc->sc_enabled) { + awi_stop(sc); + error = awi_init(sc); + } + } + return error; +} + +int +awi_wep_getnwkey(sc, nwkey) + struct awi_softc *sc; + struct ieee80211_nwkey *nwkey; +{ + int i, len, error, suerr; + u_int8_t keybuf[AWI_MAX_KEYLEN]; + + nwkey->i_wepon = awi_wep_getalgo(sc); + nwkey->i_defkid = sc->sc_wep_defkid + 1; + /* do not show any keys to non-root user */ +#ifdef __FreeBSD__ + suerr = suser(curproc); +#else + suerr = suser(curproc->p_ucred, &curproc->p_acflag); +#endif + error = 0; + for (i = 0; i < IEEE80211_WEP_NKID; i++) { + if (nwkey->i_key[i].i_keydat == NULL) + continue; + if (suerr) { + error = suerr; + break; + } + len = sizeof(keybuf); + error = awi_wep_getkey(sc, i, keybuf, &len); + if (error) + break; + if (nwkey->i_key[i].i_keylen < len) { + error = ENOSPC; + break; + } + nwkey->i_key[i].i_keylen = len; + error = copyout(keybuf, nwkey->i_key[i].i_keydat, len); + if (error) + break; + } + return error; +} + +int +awi_wep_getalgo(sc) + struct awi_softc *sc; +{ + + if (sc->sc_wep_algo == NULL) + return 0; + return sc->sc_wep_algo - awi_wep_algo; +} + +int +awi_wep_setalgo(sc, algo) + struct awi_softc *sc; + int algo; +{ + struct awi_wep_algo *awa; + int ctxlen; + + awi_crc_init(); /* XXX: not belongs here */ + if (algo < 0 || algo > sizeof(awi_wep_algo)/sizeof(awi_wep_algo[0])) + return EINVAL; + awa = &awi_wep_algo[algo]; + if (awa->awa_name == NULL) + return EINVAL; + if (awa->awa_ctxlen == NULL) { + awa = NULL; + ctxlen = 0; + } else + ctxlen = awa->awa_ctxlen(); + if (sc->sc_wep_ctx != NULL) { + free(sc->sc_wep_ctx, M_DEVBUF); + sc->sc_wep_ctx = NULL; + } + if (ctxlen) { + sc->sc_wep_ctx = malloc(ctxlen, M_DEVBUF, M_NOWAIT); + if (sc->sc_wep_ctx == NULL) + return ENOMEM; + } + sc->sc_wep_algo = awa; + return 0; +} + +int +awi_wep_setkey(sc, kid, key, keylen) + struct awi_softc *sc; + int kid; + unsigned char *key; + int keylen; +{ + + if (kid < 0 || kid >= IEEE80211_WEP_NKID) + return EINVAL; + if (keylen < 0 || keylen + IEEE80211_WEP_IVLEN > AWI_MAX_KEYLEN) + return EINVAL; + sc->sc_wep_keylen[kid] = keylen; + if (keylen > 0) + memcpy(sc->sc_wep_key[kid] + IEEE80211_WEP_IVLEN, key, keylen); + return 0; +} + +int +awi_wep_getkey(sc, kid, key, keylen) + struct awi_softc *sc; + int kid; + unsigned char *key; + int *keylen; +{ + + if (kid < 0 || kid >= IEEE80211_WEP_NKID) + return EINVAL; + if (*keylen < sc->sc_wep_keylen[kid]) + return ENOSPC; + *keylen = sc->sc_wep_keylen[kid]; + if (*keylen > 0) + memcpy(key, sc->sc_wep_key[kid] + IEEE80211_WEP_IVLEN, *keylen); + return 0; +} + +struct mbuf * +awi_wep_encrypt(sc, m0, txflag) + struct awi_softc *sc; + struct mbuf *m0; + int txflag; +{ + struct mbuf *m, *n, *n0; + struct ieee80211_frame *wh; + struct awi_wep_algo *awa; + int left, len, moff, noff, keylen, kid; + u_int32_t iv, crc; + u_int8_t *key, *ivp; + void *ctx; + u_int8_t crcbuf[IEEE80211_WEP_CRCLEN]; + + n0 = NULL; + awa = sc->sc_wep_algo; + if (awa == NULL) + goto fail; + ctx = sc->sc_wep_ctx; + m = m0; + left = m->m_pkthdr.len; + MGET(n, M_DONTWAIT, m->m_type); + n0 = n; + if (n == NULL) + goto fail; + M_COPY_PKTHDR(n, m); + len = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN; + if (txflag) { + n->m_pkthdr.len += len; + } else { + n->m_pkthdr.len -= len; + left -= len; + } + n->m_len = MHLEN; + if (n->m_pkthdr.len >= MINCLSIZE) { + MCLGET(n, M_DONTWAIT); + if (n->m_flags & M_EXT) + n->m_len = n->m_ext.ext_size; + } + len = sizeof(struct ieee80211_frame); + memcpy(mtod(n, caddr_t), mtod(m, caddr_t), len); + left -= len; + moff = len; + noff = len; + if (txflag) { + kid = sc->sc_wep_defkid; + wh = mtod(n, struct ieee80211_frame *); + wh->i_fc[1] |= IEEE80211_FC1_WEP; + iv = random(); + /* + * store IV, byte order is not the matter since it's random. + * assuming IEEE80211_WEP_IVLEN is 3 + */ + ivp = mtod(n, u_int8_t *) + noff; + ivp[0] = (iv >> 16) & 0xff; + ivp[1] = (iv >> 8) & 0xff; + ivp[2] = iv & 0xff; + ivp[3] = kid & 0x03; /* clear pad and keyid */ + noff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN; + } else { + ivp = mtod(m, u_int8_t *) + moff; + moff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN; + kid = ivp[IEEE80211_WEP_IVLEN] & 0x03; + } + key = sc->sc_wep_key[kid]; + keylen = sc->sc_wep_keylen[kid]; + /* assuming IEEE80211_WEP_IVLEN is 3 */ + key[0] = ivp[0]; + key[1] = ivp[1]; + key[2] = ivp[2]; + awa->awa_setkey(ctx, key, IEEE80211_WEP_IVLEN + keylen); + + /* encrypt with calculating CRC */ + crc = ~0; + while (left > 0) { + len = m->m_len - moff; + if (len == 0) { + m = m->m_next; + moff = 0; + continue; + } + if (len > n->m_len - noff) { + len = n->m_len - noff; + if (len == 0) { + MGET(n->m_next, M_DONTWAIT, n->m_type); + if (n->m_next == NULL) + goto fail; + n = n->m_next; + n->m_len = MLEN; + if (left >= MINCLSIZE) { + MCLGET(n, M_DONTWAIT); + if (n->m_flags & M_EXT) + n->m_len = n->m_ext.ext_size; + } + noff = 0; + continue; + } + } + if (len > left) + len = left; + if (txflag) { + awa->awa_encrypt(ctx, mtod(n, caddr_t) + noff, + mtod(m, caddr_t) + moff, len); + crc = awi_crc_update(crc, mtod(m, caddr_t) + moff, len); + } else { + awa->awa_decrypt(ctx, mtod(n, caddr_t) + noff, + mtod(m, caddr_t) + moff, len); + crc = awi_crc_update(crc, mtod(n, caddr_t) + noff, len); + } + left -= len; + moff += len; + noff += len; + } + crc = ~crc; + if (txflag) { + LE_WRITE_4(crcbuf, crc); + if (n->m_len >= noff + sizeof(crcbuf)) + n->m_len = noff + sizeof(crcbuf); + else { + n->m_len = noff; + MGET(n->m_next, M_DONTWAIT, n->m_type); + if (n->m_next == NULL) + goto fail; + n = n->m_next; + n->m_len = sizeof(crcbuf); + noff = 0; + } + awa->awa_encrypt(ctx, mtod(n, caddr_t) + noff, crcbuf, + sizeof(crcbuf)); + } else { + n->m_len = noff; + for (noff = 0; noff < sizeof(crcbuf); noff += len) { + len = sizeof(crcbuf) - noff; + if (len > m->m_len - moff) + len = m->m_len - moff; + if (len > 0) + awa->awa_decrypt(ctx, crcbuf + noff, + mtod(m, caddr_t) + moff, len); + m = m->m_next; + moff = 0; + } + if (crc != LE_READ_4(crcbuf)) + goto fail; + } + m_freem(m0); + return n0; + + fail: + m_freem(m0); + m_freem(n0); + return NULL; +} + +/* + * CRC 32 -- routine from RFC 2083 + */ + +/* Table of CRCs of all 8-bit messages */ +static u_int32_t awi_crc_table[256]; +static int awi_crc_table_computed = 0; + +/* Make the table for a fast CRC. */ +static void +awi_crc_init() +{ + u_int32_t c; + int n, k; + + if (awi_crc_table_computed) + return; + for (n = 0; n < 256; n++) { + c = (u_int32_t)n; + for (k = 0; k < 8; k++) { + if (c & 1) + c = 0xedb88320UL ^ (c >> 1); + else + c = c >> 1; + } + awi_crc_table[n] = c; + } + awi_crc_table_computed = 1; +} + +/* + * Update a running CRC with the bytes buf[0..len-1]--the CRC + * should be initialized to all 1's, and the transmitted value + * is the 1's complement of the final running CRC + */ + +static u_int32_t +awi_crc_update(crc, buf, len) + u_int32_t crc; + u_int8_t *buf; + int len; +{ + u_int8_t *endbuf; + + for (endbuf = buf + len; buf < endbuf; buf++) + crc = awi_crc_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); + return crc; +} + +/* + * Null -- do nothing but copy. + */ + +static int +awi_null_ctxlen() +{ + + return 0; +} + +static void +awi_null_setkey(ctx, key, keylen) + void *ctx; + u_char *key; + int keylen; +{ +} + +static void +awi_null_copy(ctx, dst, src, len) + void *ctx; + u_char *dst; + u_char *src; + int len; +{ + + memcpy(dst, src, len); +} diff --git a/sys/dev/awi/awi_wicfg.c b/sys/dev/awi/awi_wicfg.c new file mode 100644 index 000000000000..80882ba3035a --- /dev/null +++ b/sys/dev/awi/awi_wicfg.c @@ -0,0 +1,625 @@ +/* $NetBSD: awi_wicfg.c,v 1.3 2000/07/06 17:22:25 onoe Exp $ */ +/* $FreeBSD$ */ + +/* + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Atsushi Onoe. + * + * 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 NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* + * WaveLAN compatible configuration support routines for the awi driver. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/mbuf.h> +#include <sys/malloc.h> +#include <sys/socket.h> +#include <sys/errno.h> +#include <sys/sockio.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 4 +#include <sys/bus.h> +#else +#include <sys/device.h> +#endif + +#include <net/if.h> +#include <net/if_dl.h> +#ifdef __FreeBSD__ +#include <net/ethernet.h> +#include <net/if_arp.h> +#else +#include <net/if_ether.h> +#endif +#include <net/if_media.h> +#include <net/if_ieee80211.h> + +#include <machine/cpu.h> +#include <machine/bus.h> +#ifdef __FreeBSD__ +#endif + +#ifdef __NetBSD__ +#include <dev/ic/am79c930reg.h> +#include <dev/ic/am79c930var.h> +#include <dev/ic/awireg.h> +#include <dev/ic/awivar.h> + +#include <dev/pcmcia/if_wi_ieee.h> /* XXX */ +#endif +#ifdef __FreeBSD__ +#include <dev/awi/am79c930reg.h> +#include <dev/awi/am79c930var.h> + +#undef _KERNEL /* XXX */ +#include <i386/include/if_wavelan_ieee.h> /* XXX */ +#define _KERNEL /* XXX */ +#include <dev/awi/awireg.h> +#include <dev/awi/awivar.h> +#endif + +static int awi_cfgget __P((struct ifnet *ifp, u_long cmd, caddr_t data)); +static int awi_cfgset __P((struct ifnet *ifp, u_long cmd, caddr_t data)); + +int +awi_wicfg(ifp, cmd, data) + struct ifnet *ifp; + u_long cmd; + caddr_t data; +{ + int error; + + switch (cmd) { + case SIOCGWAVELAN: + error = awi_cfgget(ifp, cmd, data); + break; + case SIOCSWAVELAN: +#ifdef __FreeBSD__ + error = suser(curproc); +#else + error = suser(curproc->p_ucred, &curproc->p_acflag); +#endif + if (error) + break; + error = awi_cfgset(ifp, cmd, data); + break; + default: + error = EINVAL; + break; + } + return error; +} + +static int +awi_cfgget(ifp, cmd, data) + struct ifnet *ifp; + u_long cmd; + caddr_t data; +{ + int i, error, keylen; + char *p; + struct awi_softc *sc = (struct awi_softc *)ifp->if_softc; + struct ifreq *ifr = (struct ifreq *)data; + struct wi_ltv_keys *keys; + struct wi_key *k; + struct wi_req wreq; +#ifdef WICACHE + struct wi_sigcache wsc; + struct awi_bss *bp; +#endif /* WICACHE */ + + error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); + if (error) + return error; + switch (wreq.wi_type) { + case WI_RID_SERIALNO: + memcpy(wreq.wi_val, sc->sc_banner, AWI_BANNER_LEN); + wreq.wi_len = (AWI_BANNER_LEN + 1) / 2; + break; + case WI_RID_NODENAME: + strcpy((char *)&wreq.wi_val[1], hostname); + wreq.wi_val[0] = strlen(hostname); + wreq.wi_len = (1 + wreq.wi_val[0] + 1) / 2; + break; + case WI_RID_OWN_SSID: + p = sc->sc_ownssid; + wreq.wi_val[0] = p[1]; + memcpy(&wreq.wi_val[1], p + 2, p[1]); + wreq.wi_len = (1 + wreq.wi_val[0] + 1) / 2; + break; + case WI_RID_CURRENT_SSID: + if (ifp->if_flags & IFF_RUNNING) { + p = sc->sc_bss.essid; + wreq.wi_val[0] = p[1]; + memcpy(&wreq.wi_val[1], p + 2, p[1]); + } else { + wreq.wi_val[0] = 0; + wreq.wi_val[1] = '\0'; + } + wreq.wi_len = (1 + wreq.wi_val[0] + 1) / 2; + break; + case WI_RID_DESIRED_SSID: + p = sc->sc_mib_mac.aDesired_ESS_ID; + wreq.wi_val[0] = p[1]; + memcpy(&wreq.wi_val[1], p + 2, p[1]); + wreq.wi_len = (1 + wreq.wi_val[0] + 1) / 2; + break; + case WI_RID_CURRENT_BSSID: + if (ifp->if_flags & IFF_RUNNING) + memcpy(wreq.wi_val, sc->sc_bss.bssid, ETHER_ADDR_LEN); + else + memset(wreq.wi_val, 0, ETHER_ADDR_LEN); + wreq.wi_len = ETHER_ADDR_LEN / 2; + break; + case WI_RID_CHANNEL_LIST: + if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) { + wreq.wi_val[0] = sc->sc_scan_min; + wreq.wi_val[1] = sc->sc_scan_max; + wreq.wi_len = 2; + } else { + wreq.wi_val[0] = 0; + for (i = sc->sc_scan_min; i <= sc->sc_scan_max; i++) + wreq.wi_val[0] |= 1 << (i - 1); + wreq.wi_len = 1; + } + break; + case WI_RID_OWN_CHNL: + wreq.wi_val[0] = sc->sc_ownch; + wreq.wi_len = 1; + break; + case WI_RID_CURRENT_CHAN: + if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) + wreq.wi_val[0] = sc->sc_bss.pattern; + else + wreq.wi_val[0] = sc->sc_bss.chanset; + wreq.wi_len = 1; + break; + case WI_RID_COMMS_QUALITY: + wreq.wi_val[0] = 0; /* quality */ + wreq.wi_val[1] = sc->sc_bss.rssi; /* signal */ + wreq.wi_val[2] = 0; /* noise */ + wreq.wi_len = 3; + break; + case WI_RID_PROMISC: + wreq.wi_val[0] = sc->sc_mib_mac.aPromiscuous_Enable; + wreq.wi_len = 1; + break; + case WI_RID_PORTTYPE: + if (sc->sc_mib_local.Network_Mode) + wreq.wi_val[0] = 1; + else if (!sc->sc_no_bssid) + wreq.wi_val[0] = 2; + else + wreq.wi_val[0] = 3; + wreq.wi_len = 1; + break; + case WI_RID_MAC_NODE: + memcpy(wreq.wi_val, sc->sc_mib_addr.aMAC_Address, + ETHER_ADDR_LEN); + wreq.wi_len = ETHER_ADDR_LEN / 2; + break; + case WI_RID_TX_RATE: + case WI_RID_CUR_TX_RATE: + wreq.wi_val[0] = sc->sc_tx_rate / 10; + wreq.wi_len = 1; + break; + case WI_RID_RTS_THRESH: + wreq.wi_val[0] = LE_READ_2(&sc->sc_mib_mac.aRTS_Threshold); + wreq.wi_len = 1; + break; + case WI_RID_CREATE_IBSS: + wreq.wi_val[0] = sc->sc_start_bss; + wreq.wi_len = 1; + break; + case WI_RID_SYSTEM_SCALE: + wreq.wi_val[0] = 1; /* low density ... not supported */ + wreq.wi_len = 1; + break; + case WI_RID_PM_ENABLED: + wreq.wi_val[0] = sc->sc_mib_local.Power_Saving_Mode_Dis ? 0 : 1; + wreq.wi_len = 1; + break; + case WI_RID_MAX_SLEEP: + wreq.wi_val[0] = 0; /* not implemented */ + wreq.wi_len = 1; + break; + case WI_RID_WEP_AVAIL: + wreq.wi_val[0] = 1; + wreq.wi_len = 1; + break; + case WI_RID_ENCRYPTION: + wreq.wi_val[0] = awi_wep_getalgo(sc); + wreq.wi_len = 1; + break; + case WI_RID_TX_CRYPT_KEY: + wreq.wi_val[0] = sc->sc_wep_defkid; + wreq.wi_len = 1; + break; + case WI_RID_DEFLT_CRYPT_KEYS: + keys = (struct wi_ltv_keys *)&wreq; + /* do not show keys to non-root user */ +#ifdef __FreeBSD__ + error = suser(curproc); +#else + error = suser(curproc->p_ucred, &curproc->p_acflag); +#endif + if (error) { + memset(keys, 0, sizeof(*keys)); + error = 0; + break; + } + for (i = 0; i < IEEE80211_WEP_NKID; i++) { + k = &keys->wi_keys[i]; + keylen = sizeof(k->wi_keydat); + error = awi_wep_getkey(sc, i, k->wi_keydat, &keylen); + if (error) + break; + k->wi_keylen = keylen; + } + wreq.wi_len = sizeof(*keys) / 2; + break; + case WI_RID_MAX_DATALEN: + wreq.wi_val[0] = LE_READ_2(&sc->sc_mib_mac.aMax_Frame_Length); + wreq.wi_len = 1; + break; + case WI_RID_IFACE_STATS: + /* not implemented yet */ + wreq.wi_len = 0; + break; +#ifdef WICACHE + case WI_RID_READ_CACHE: + for (bp = TAILQ_FIRST(&sc->sc_scan), i = 0; + bp != NULL && i < MAXWICACHE; + bp = TAILQ_NEXT(bp, list), i++) { + memcpy(wsc.macsrc, bp->esrc, ETHER_ADDR_LEN); + /*XXX*/ + memcpy(&wsc.ipsrc, bp->bssid, sizeof(wsc.ipsrc)); + wsc.signal = bp->rssi; + wsc.noise = 0; + wsc.quality = 0; + memcpy((caddr_t)wreq.wi_val + sizeof(wsc) * i, + &wsc, sizeof(wsc)); + } + wreq.wi_len = sizeof(wsc) * i / 2; + break; +#endif /* WICACHE */ + default: + error = EINVAL; + break; + } + if (error == 0) { + wreq.wi_len++; + error = copyout(&wreq, ifr->ifr_data, sizeof(wreq)); + } + return error; +} + +static int +awi_cfgset(ifp, cmd, data) + struct ifnet *ifp; + u_long cmd; + caddr_t data; +{ + int i, error, rate, oregion; + u_int8_t *phy_rates; + struct awi_softc *sc = (struct awi_softc *)ifp->if_softc; + struct ifreq *ifr = (struct ifreq *)data; + struct wi_ltv_keys *keys; + struct wi_key *k; + struct wi_req wreq; + + error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); + if (error) + return error; + if (wreq.wi_len-- < 1) + return EINVAL; + switch (wreq.wi_type) { + case WI_RID_SERIALNO: + case WI_RID_NODENAME: + error = EPERM; + break; + case WI_RID_OWN_SSID: + if (wreq.wi_len < (1 + wreq.wi_val[0] + 1) / 2) { + error = EINVAL; + break; + } + if (wreq.wi_val[0] > IEEE80211_NWID_LEN) { + error = EINVAL; + break; + } + memset(sc->sc_ownssid, 0, AWI_ESS_ID_SIZE); + sc->sc_ownssid[0] = IEEE80211_ELEMID_SSID; + sc->sc_ownssid[1] = wreq.wi_val[0]; + memcpy(&sc->sc_ownssid[2], &wreq.wi_val[1], wreq.wi_val[0]); + if (!sc->sc_mib_local.Network_Mode && + !sc->sc_no_bssid && sc->sc_start_bss) + error = ENETRESET; + break; + case WI_RID_CURRENT_SSID: + error = EPERM; + break; + case WI_RID_DESIRED_SSID: + if (wreq.wi_len < (1 + wreq.wi_val[0] + 1) / 2) { + error = EINVAL; + break; + } + if (wreq.wi_val[0] > IEEE80211_NWID_LEN) { + error = EINVAL; + break; + } + memset(sc->sc_mib_mac.aDesired_ESS_ID, 0, AWI_ESS_ID_SIZE); + sc->sc_mib_mac.aDesired_ESS_ID[0] = IEEE80211_ELEMID_SSID; + sc->sc_mib_mac.aDesired_ESS_ID[1] = wreq.wi_val[0]; + memcpy(&sc->sc_mib_mac.aDesired_ESS_ID[2], &wreq.wi_val[1], + wreq.wi_val[0]); + if (sc->sc_mib_local.Network_Mode || !sc->sc_no_bssid) + error = ENETRESET; + break; + case WI_RID_CURRENT_BSSID: + error = EPERM; + break; + case WI_RID_CHANNEL_LIST: + if (wreq.wi_len != 1) { + error = EINVAL; + break; + } + oregion = sc->sc_mib_phy.aCurrent_Reg_Domain; + if (wreq.wi_val[0] == oregion) + break; + sc->sc_mib_phy.aCurrent_Reg_Domain = wreq.wi_val[0]; + error = awi_init_region(sc); + if (error) { + sc->sc_mib_phy.aCurrent_Reg_Domain = oregion; + break; + } + error = ENETRESET; + break; + case WI_RID_OWN_CHNL: + if (wreq.wi_len != 1) { + error = EINVAL; + break; + } + if (wreq.wi_val[0] < sc->sc_scan_min || + wreq.wi_val[0] > sc->sc_scan_max) { + error = EINVAL; + break; + } + sc->sc_ownch = wreq.wi_val[0]; + if (!sc->sc_mib_local.Network_Mode) + error = ENETRESET; + break; + case WI_RID_CURRENT_CHAN: + error = EPERM; + break; + case WI_RID_COMMS_QUALITY: + error = EPERM; + break; + case WI_RID_PROMISC: + if (wreq.wi_len != 1) { + error = EINVAL; + break; + } + if (ifp->if_flags & IFF_PROMISC) { + if (wreq.wi_val[0] == 0) { + ifp->if_flags &= ~IFF_PROMISC; + error = ENETRESET; + } + } else { + if (wreq.wi_val[0] != 0) { + ifp->if_flags |= IFF_PROMISC; + error = ENETRESET; + } + } + break; + case WI_RID_PORTTYPE: + if (wreq.wi_len != 1) { + error = EINVAL; + break; + } + switch (wreq.wi_val[0]) { + case 1: + sc->sc_mib_local.Network_Mode = 1; + sc->sc_no_bssid = 0; + error = ENETRESET; + break; + case 2: + sc->sc_mib_local.Network_Mode = 0; + sc->sc_no_bssid = 0; + error = ENETRESET; + break; + case 3: + if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) { + error = EINVAL; + break; + } + sc->sc_mib_local.Network_Mode = 0; + sc->sc_no_bssid = 1; + error = ENETRESET; + break; + default: + error = EINVAL; + break; + } + break; + case WI_RID_MAC_NODE: + /* XXX: should be implemented? */ + error = EPERM; + break; + case WI_RID_TX_RATE: + if (wreq.wi_len != 1) { + error = EINVAL; + break; + } + phy_rates = sc->sc_mib_phy.aSuprt_Data_Rates; + switch (wreq.wi_val[0]) { + case 1: + case 2: + case 5: + case 11: + rate = wreq.wi_val[0] * 10; + if (rate == 50) + rate += 5; /*XXX*/ + break; + case 3: + case 6: + case 7: + /* auto rate */ + phy_rates = sc->sc_mib_phy.aSuprt_Data_Rates; + rate = AWI_RATE_1MBIT; + for (i = 0; i < phy_rates[1]; i++) { + if (AWI_80211_RATE(phy_rates[2 + i]) > rate) + rate = AWI_80211_RATE(phy_rates[2 + i]); + } + break; + default: + rate = 0; + error = EINVAL; + break; + } + if (error) + break; + for (i = 0; i < phy_rates[1]; i++) { + if (rate == AWI_80211_RATE(phy_rates[2 + i])) + break; + } + if (i == phy_rates[1]) { + error = EINVAL; + break; + } + sc->sc_tx_rate = rate; + break; + case WI_RID_CUR_TX_RATE: + error = EPERM; + break; + case WI_RID_RTS_THRESH: + if (wreq.wi_len != 1) { + error = EINVAL; + break; + } + LE_WRITE_2(&sc->sc_mib_mac.aRTS_Threshold, wreq.wi_val[0]); + error = ENETRESET; + break; + case WI_RID_CREATE_IBSS: + if (wreq.wi_len != 1) { + error = EINVAL; + break; + } + sc->sc_start_bss = wreq.wi_val[0] ? 1 : 0; + error = ENETRESET; + break; + case WI_RID_SYSTEM_SCALE: + if (wreq.wi_len != 1) { + error = EINVAL; + break; + } + if (wreq.wi_val[0] != 1) + error = EINVAL; /* not supported */ + break; + case WI_RID_PM_ENABLED: + if (wreq.wi_len != 1) { + error = EINVAL; + break; + } + if (wreq.wi_val[0] != 0) + error = EINVAL; /* not implemented */ + break; + case WI_RID_MAX_SLEEP: + error = EINVAL; /* not implemented */ + break; + case WI_RID_WEP_AVAIL: + error = EPERM; + break; + case WI_RID_ENCRYPTION: + if (wreq.wi_len != 1) { + error = EINVAL; + break; + } + error = awi_wep_setalgo(sc, wreq.wi_val[0]); + if (error) + break; + error = ENETRESET; + break; + case WI_RID_TX_CRYPT_KEY: + if (wreq.wi_len != 1) { + error = EINVAL; + break; + } + if (wreq.wi_val[0] >= IEEE80211_WEP_NKID) { + error = EINVAL; + break; + } + sc->sc_wep_defkid = wreq.wi_val[1]; + break; + case WI_RID_DEFLT_CRYPT_KEYS: + if (wreq.wi_len != sizeof(*keys) / 2) { + error = EINVAL; + break; + } + keys = (struct wi_ltv_keys *)&wreq; + for (i = 0; i < IEEE80211_WEP_NKID; i++) { + k = &keys->wi_keys[i]; + error = awi_wep_setkey(sc, i, k->wi_keydat, + k->wi_keylen); + if (error) + break; + } + break; + case WI_RID_MAX_DATALEN: + if (wreq.wi_len != 1) { + error = EINVAL; + break; + } + if (wreq.wi_val[0] < 350 || wreq.wi_val[0] > 2304) { + error = EINVAL; + break; + } + LE_WRITE_2(&sc->sc_mib_mac.aMax_Frame_Length, wreq.wi_val[0]); + break; + case WI_RID_IFACE_STATS: + error = EPERM; + break; + default: + error = EINVAL; + break; + } + if (error == ENETRESET) { + if (sc->sc_enabled) { + awi_stop(sc); + error = awi_init(sc); + } else + error = 0; + } + return error; +} diff --git a/sys/dev/usb/uscanner.c b/sys/dev/usb/uscanner.c new file mode 100644 index 000000000000..4a87c475d61d --- /dev/null +++ b/sys/dev/usb/uscanner.c @@ -0,0 +1,658 @@ +/* $NetBSD: uscanner.c,v 1.6 2000/10/13 18:16:36 augustss Exp $ */ +/* $FreeBSD$ */ + +/* + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Lennart Augustsson (lennart@augustsson.net) at + * Carlstedt Research & Technology + * and Nick Hibma (n_hibma@qubesoft.com). + * + * 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 NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#if defined(__NetBSD__) || defined(__OpenBSD__) +#include <sys/device.h> +#elif defined(__FreeBSD__) +#include <sys/module.h> +#include <sys/bus.h> +#include <sys/conf.h> +#include <sys/fcntl.h> +#include <sys/filio.h> +#endif +#include <sys/tty.h> +#include <sys/file.h> +#include <sys/select.h> +#include <sys/proc.h> +#include <sys/vnode.h> +#include <sys/poll.h> +#include <sys/conf.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> +#include <dev/usb/usbdi_util.h> + +#include <dev/usb/usbdevs.h> + +#ifdef USCANNER_DEBUG +#define DPRINTF(x) if (uscannerdebug) logprintf x +#define DPRINTFN(n,x) if (uscannerdebug>(n)) logprintf x +int uscannerdebug = 0; +#else +#define DPRINTF(x) +#define DPRINTFN(n,x) +#endif + +/* Table of scanners that may work with this driver. */ +static const struct scanner_id { + uint16_t vendor; + uint16_t product; +} scanner_ids [] = { + /* Acer Peripherals */ + { USB_VENDOR_ACERP, USB_PRODUCT_ACERP_ACERSCAN_320U }, + { USB_VENDOR_ACERP, USB_PRODUCT_ACERP_ACERSCAN_640U }, + { USB_VENDOR_ACERP, USB_PRODUCT_ACERP_ACERSCAN_620U }, + { USB_VENDOR_ACERP, USB_PRODUCT_ACERP_ACERSCAN_C310U }, + + /* AGFA */ + { USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCAN1212U }, + { USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCAN1212U2 }, + { USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCANTOUCH }, + + /* Kye */ + { USB_VENDOR_KYE, USB_PRODUCT_KYE_VIVIDPRO }, + + /* HP */ + { USB_VENDOR_HP, USB_PRODUCT_HP_3300C }, + { USB_VENDOR_HP, USB_PRODUCT_HP_4100C }, + { USB_VENDOR_HP, USB_PRODUCT_HP_4200C }, + { USB_VENDOR_HP, USB_PRODUCT_HP_S20 }, + { USB_VENDOR_HP, USB_PRODUCT_HP_5200C }, + { USB_VENDOR_HP, USB_PRODUCT_HP_5300C }, + { USB_VENDOR_HP, USB_PRODUCT_HP_6200C }, + { USB_VENDOR_HP, USB_PRODUCT_HP_6300C }, + + /* Avision */ + { USB_VENDOR_AVISION, USB_PRODUCT_AVISION_1200U }, + + /* Microtek */ + { USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_X6U }, + { USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_336CX }, + { USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_336CX2 }, + { USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_C6 }, + { USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_V6USL }, + { USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_V6USL2 }, + { USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_V6UL }, + + /* Mustek */ + { USB_VENDOR_MUSTEK, USB_PRODUCT_MUSTEK_1200CU }, + { USB_VENDOR_NATIONAL, USB_PRODUCT_NATIONAL_BEARPAW }, + { USB_VENDOR_NATIONAL, USB_PRODUCT_MUSTEK_600CU }, + { USB_VENDOR_NATIONAL, USB_PRODUCT_MUSTEK_1200USB }, + { USB_VENDOR_NATIONAL, USB_PRODUCT_MUSTEK_1200UB }, + + /* Primax */ + { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2X300 }, + { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2E300 }, + { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2300 }, + { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2E3002 }, + { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_9600 }, + { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_600U }, + { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_19200 }, + { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_1200U }, + { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G600 }, + { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_636I }, + { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2600 }, + { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2E600 }, + + /* Epson */ + { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_636 }, + { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_610 }, + { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1200 }, + { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1600 }, + + /* UMAX */ + { USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA1220U }, + { USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA1236U }, + { USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA2000U }, + { USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA2200U }, + + /* Visioneer */ + { USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_5300 }, + { USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_7600 }, + { USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_6100 }, + { USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_6200 }, + { USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_8100 }, + { USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_8600 }, + + { 0, 0 } +}; + +#define USCANNER_BUFFERSIZE 1024 + +struct uscanner_softc { + USBBASEDEVICE sc_dev; /* base device */ + usbd_device_handle sc_udev; + usbd_interface_handle sc_iface; + + usbd_pipe_handle sc_bulkin_pipe; + int sc_bulkin; + usbd_xfer_handle sc_bulkin_xfer; + void *sc_bulkin_buffer; + int sc_bulkin_bufferlen; + int sc_bulkin_datalen; + + usbd_pipe_handle sc_bulkout_pipe; + int sc_bulkout; + usbd_xfer_handle sc_bulkout_xfer; + void *sc_bulkout_buffer; + int sc_bulkout_bufferlen; + int sc_bulkout_datalen; + + u_char sc_state; +#define USCANNER_OPEN 0x01 /* opened */ + + int sc_refcnt; + u_char sc_dying; +}; + +#if defined(__NetBSD__) || defined(__OpenBSD__) +cdev_decl(uscanner); +#elif defined(__FreeBSD__) +d_open_t uscanneropen; +d_close_t uscannerclose; +d_read_t uscannerread; +d_write_t uscannerwrite; +d_poll_t uscannerpoll; + +#define USCANNER_CDEV_MAJOR 156 + +Static struct cdevsw uscanner_cdevsw = { + /* open */ uscanneropen, + /* close */ uscannerclose, + /* read */ uscannerread, + /* write */ uscannerwrite, + /* ioctl */ noioctl, + /* poll */ uscannerpoll, + /* mmap */ nommap, + /* strategy */ nostrategy, + /* name */ "uscanner", + /* maj */ USCANNER_CDEV_MAJOR, + /* dump */ nodump, + /* psize */ nopsize, + /* flags */ 0, + /* bmaj */ -1 +}; +#endif + +Static int uscanner_do_read(struct uscanner_softc *, struct uio *, int); +Static int uscanner_do_write(struct uscanner_softc *, struct uio *, int); +Static void uscanner_do_close(struct uscanner_softc *); + +#define USCANNERUNIT(n) (minor(n)) + +USB_DECLARE_DRIVER(uscanner); + +USB_MATCH(uscanner) +{ + USB_MATCH_START(uscanner, uaa); + int i; + + if (uaa->iface != NULL) + return UMATCH_NONE; + + for (i = 0; scanner_ids[i].vendor != 0; i++) { + if (scanner_ids[i].vendor == uaa->vendor && + scanner_ids[i].product == uaa->product) { + return (UMATCH_VENDOR_PRODUCT); + } + } + + return (UMATCH_NONE); +} + +USB_ATTACH(uscanner) +{ + USB_ATTACH_START(uscanner, sc, uaa); + usb_interface_descriptor_t *id = 0; + usb_endpoint_descriptor_t *ed, *ed_bulkin = NULL, *ed_bulkout = NULL; + char devinfo[1024]; + int i; + usbd_status err; + + usbd_devinfo(uaa->device, 0, devinfo); + USB_ATTACH_SETUP; + printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo); + + sc->sc_udev = uaa->device; + + err = usbd_set_config_no(uaa->device, 1, 0); /* XXX */ + if (err) { + printf("%s: setting config no failed\n", + USBDEVNAME(sc->sc_dev)); + USB_ATTACH_ERROR_RETURN; + } + + /* XXX We only check the first interface */ + err = usbd_device2interface_handle(sc->sc_udev, 0, &sc->sc_iface); + if (!err && sc->sc_iface) + id = usbd_get_interface_descriptor(sc->sc_iface); + if (err || id == 0) { + printf("%s: could not get interface descriptor, err=%d,id=%p\n", + USBDEVNAME(sc->sc_dev), err, id); + USB_ATTACH_ERROR_RETURN; + } + + /* Find the two first bulk endpoints */ + for (i = 0 ; i < id->bNumEndpoints; i++) { + ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); + if (ed == 0) { + printf("%s: could not read endpoint descriptor\n", + USBDEVNAME(sc->sc_dev)); + USB_ATTACH_ERROR_RETURN; + } + + if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN + && (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) { + ed_bulkin = ed; + } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT + && (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) { + ed_bulkout = ed; + } + + if (ed_bulkin && ed_bulkout) /* found all we need */ + break; + } + + /* Verify that we goething sensible */ + if (ed_bulkin == NULL || ed_bulkout == NULL) { + printf("%s: bulk-in and/or bulk-out endpoint not found\n", + USBDEVNAME(sc->sc_dev)); + USB_ATTACH_ERROR_RETURN; + } + + sc->sc_bulkin = ed_bulkin->bEndpointAddress; + sc->sc_bulkout = ed_bulkout->bEndpointAddress; + +#ifdef __FreeBSD__ + /* the main device, ctrl endpoint */ + make_dev(&uscanner_cdevsw, USBDEVUNIT(sc->sc_dev), + UID_ROOT, GID_OPERATOR, 0644, "%s", USBDEVNAME(sc->sc_dev)); +#endif + + USB_ATTACH_SUCCESS_RETURN; +} + +int +uscanneropen(dev, flag, mode, p) + dev_t dev; + int flag; + int mode; + struct proc *p; +{ + struct uscanner_softc *sc; + int unit = USCANNERUNIT(dev); + usbd_status err; + + USB_GET_SC_OPEN(uscanner, unit, sc); + + DPRINTFN(5, ("uscanneropen: flag=%d, mode=%d, unit=%d\n", + flag, mode, unit)); + + if (sc->sc_dying) + return (ENXIO); + + if (sc->sc_state & USCANNER_OPEN) + return (EBUSY); + + sc->sc_bulkin_buffer = malloc(USCANNER_BUFFERSIZE, M_USBDEV, M_WAITOK); + sc->sc_bulkout_buffer = malloc(USCANNER_BUFFERSIZE, M_USBDEV, M_WAITOK); + /* No need to check buffers for NULL since we have WAITOK */ + + sc->sc_bulkin_bufferlen = USCANNER_BUFFERSIZE; + sc->sc_bulkout_bufferlen = USCANNER_BUFFERSIZE; + + /* We have decided on which endpoints to use, now open the pipes */ + err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin, + USBD_EXCLUSIVE_USE, &sc->sc_bulkin_pipe); + if (err) { + printf("%s: cannot open bulk-in pipe (addr %d)\n", + USBDEVNAME(sc->sc_dev), sc->sc_bulkin); + uscanner_do_close(sc); + return (EIO); + } + err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout, + USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe); + if (err) { + printf("%s: cannot open bulk-out pipe (addr %d)\n", + USBDEVNAME(sc->sc_dev), sc->sc_bulkout); + uscanner_do_close(sc); + return (EIO); + } + + sc->sc_bulkin_xfer = usbd_alloc_xfer(sc->sc_udev); + if (sc->sc_bulkin_xfer == NULL) { + uscanner_do_close(sc); + return (ENOMEM); + } + sc->sc_bulkout_xfer = usbd_alloc_xfer(sc->sc_udev); + if (sc->sc_bulkout_xfer == NULL) { + uscanner_do_close(sc); + return (ENOMEM); + } + + return (0); /* success */ +} + +int +uscannerclose(dev, flag, mode, p) + dev_t dev; + int flag; + int mode; + struct proc *p; +{ + struct uscanner_softc *sc; + + USB_GET_SC(uscanner, USCANNERUNIT(dev), sc); + + DPRINTFN(5, ("uscannerclose: flag=%d, mode=%d, unit=%d\n", + flag, mode, USCANNERUNIT(dev))); + +#ifdef DIAGNOSTIC + if (!(sc->sc_state & USCANNER_OPEN)) { + printf("uscannerclose: not open\n"); + return (EINVAL); + } +#endif + + uscanner_do_close(sc); + + return 0; +} + +void +uscanner_do_close(struct uscanner_softc *sc) +{ + if (sc->sc_bulkin_xfer) { + usbd_free_xfer(sc->sc_bulkin_xfer); + sc->sc_bulkin_xfer = NULL; + } + if (sc->sc_bulkout_xfer) { + usbd_free_xfer(sc->sc_bulkout_xfer); + sc->sc_bulkout_xfer = NULL; + } + + if (sc->sc_bulkin_pipe) { + usbd_abort_pipe(sc->sc_bulkin_pipe); + usbd_close_pipe(sc->sc_bulkin_pipe); + sc->sc_bulkin_pipe = NULL; + } + if (sc->sc_bulkout_pipe) { + usbd_abort_pipe(sc->sc_bulkout_pipe); + usbd_close_pipe(sc->sc_bulkout_pipe); + sc->sc_bulkout_pipe = NULL; + } + + if (sc->sc_bulkin_buffer) { + free(sc->sc_bulkin_buffer, M_USBDEV); + sc->sc_bulkin_buffer = NULL; + } + if (sc->sc_bulkout_buffer) { + free(sc->sc_bulkout_buffer, M_USBDEV); + sc->sc_bulkout_buffer = NULL; + } + + sc->sc_state &= ~USCANNER_OPEN; +} + +Static int +uscanner_do_read(sc, uio, flag) + struct uscanner_softc *sc; + struct uio *uio; + int flag; +{ + u_int32_t n, tn; + usbd_status err; + int error = 0; + + DPRINTFN(5, ("%s: uscannerread\n", USBDEVNAME(sc->sc_dev))); + + if (sc->sc_dying) + return (EIO); + + while ((n = min(sc->sc_bulkin_bufferlen, uio->uio_resid)) != 0) { + DPRINTFN(1, ("uscannerread: start transfer %d bytes\n",n)); + tn = n; + + err = usbd_bulk_transfer( + sc->sc_bulkin_xfer, sc->sc_bulkin_pipe, + sc->sc_state & USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, + sc->sc_bulkin_buffer, &tn, + "uscannerrb"); + if (err) { + if (err == USBD_INTERRUPTED) + error = EINTR; + else if (err == USBD_TIMEOUT) + error = ETIMEDOUT; + else + error = EIO; + break; + } + DPRINTFN(1, ("uscannerread: got %d bytes\n", tn)); + error = uiomove(sc->sc_bulkin_buffer, tn, uio); + if (error || tn < n) + break; + } + + return (error); +} + +int +uscannerread(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + struct uscanner_softc *sc; + int error; + + USB_GET_SC(uscanner, USCANNERUNIT(dev), sc); + + sc->sc_refcnt++; + error = uscanner_do_read(sc, uio, flag); + if (--sc->sc_refcnt < 0) + usb_detach_wakeup(USBDEV(sc->sc_dev)); + + return (error); +} + +Static int +uscanner_do_write(sc, uio, flag) + struct uscanner_softc *sc; + struct uio *uio; + int flag; +{ + u_int32_t n; + int error = 0; + usbd_status err; + + DPRINTFN(5, ("%s: uscanner_do_write\n", USBDEVNAME(sc->sc_dev))); + + if (sc->sc_dying) + return (EIO); + + while ((n = min(sc->sc_bulkout_bufferlen, uio->uio_resid)) != 0) { + error = uiomove(sc->sc_bulkout_buffer, n, uio); + if (error) + break; + DPRINTFN(1, ("uscanner_do_write: transfer %d bytes\n", n)); + err = usbd_bulk_transfer( + sc->sc_bulkout_xfer, sc->sc_bulkout_pipe, + 0, USBD_NO_TIMEOUT, + sc->sc_bulkout_buffer, &n, + "uscannerwb"); + if (err) { + if (err == USBD_INTERRUPTED) + error = EINTR; + else + error = EIO; + break; + } + } + + return (error); +} + +int +uscannerwrite(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + struct uscanner_softc *sc; + int error; + + USB_GET_SC(uscanner, USCANNERUNIT(dev), sc); + + sc->sc_refcnt++; + error = uscanner_do_write(sc, uio, flag); + if (--sc->sc_refcnt < 0) + usb_detach_wakeup(USBDEV(sc->sc_dev)); + return (error); +} + +#if defined(__NetBSD__) || defined(__OpenBSD__) +int +uscanner_activate(self, act) + device_ptr_t self; + enum devact act; +{ + struct uscanner_softc *sc = (struct uscanner_softc *)self; + + switch (act) { + case DVACT_ACTIVATE: + return (EOPNOTSUPP); + break; + + case DVACT_DEACTIVATE: + sc->sc_dying = 1; + break; + } + return (0); +} +#endif + +USB_DETACH(uscanner) +{ + USB_DETACH_START(uscanner, sc); + int s; +#if defined(__NetBSD__) || defined(__OpenBSD__) + int maj, mn; +#elif defined(__FreeBSD__) + dev_t dev; + struct vnode *vp; +#endif + +#if defined(__NetBSD__) || defined(__OpenBSD__) + DPRINTF(("uscanner_detach: sc=%p flags=%d\n", sc, flags)); +#elif defined(__FreeBSD__) + DPRINTF(("uscanner_detach: sc=%p\n", sc)); +#endif + + sc->sc_dying = 1; + + /* Abort all pipes. Causes processes waiting for transfer to wake. */ + if (sc->sc_bulkin_pipe) + usbd_abort_pipe(sc->sc_bulkin_pipe); + if (sc->sc_bulkout_pipe) + usbd_abort_pipe(sc->sc_bulkout_pipe); + + s = splusb(); + if (--sc->sc_refcnt >= 0) { + /* Wait for processes to go away. */ + usb_detach_wait(USBDEV(sc->sc_dev)); + } + splx(s); + +#if defined(__NetBSD__) || defined(__OpenBSD__) + /* locate the major number */ + for (maj = 0; maj < nchrdev; maj++) + if (cdevsw[maj].d_open == uscanneropen) + break; + + /* Nuke the vnodes for any open instances (calls close). */ + mn = self->dv_unit * USB_MAX_ENDPOINTS; + vdevgone(maj, mn, mn + USB_MAX_ENDPOINTS - 1, VCHR); +#elif defined(__FreeBSD__) + /* destroy the device for the control endpoint */ + dev = makedev(USCANNER_CDEV_MAJOR, USBDEVUNIT(sc->sc_dev)); + vp = SLIST_FIRST(&dev->si_hlist); + if (vp) + VOP_REVOKE(vp, REVOKEALL); + destroy_dev(dev); +#endif + + return (0); +} + +int +uscannerpoll(dev, events, p) + dev_t dev; + int events; + struct proc *p; +{ + struct uscanner_softc *sc; + int revents = 0; + + USB_GET_SC(uscanner, USCANNERUNIT(dev), sc); + + if (sc->sc_dying) + return (EIO); + + /* + * We have no easy way of determining if a read will + * yield any data or a write will happen. + * Pretend they will. + */ + revents |= events & + (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM); + + return (revents); +} + +#if defined(__FreeBSD__) +DRIVER_MODULE(uscanner, uhub, uscanner_driver, uscanner_devclass, usbd_driver_load, 0); +#endif diff --git a/sys/i4b/layer1/i4b_l1lib.c b/sys/i4b/layer1/i4b_l1lib.c new file mode 100644 index 000000000000..d2e69e48bf94 --- /dev/null +++ b/sys/i4b/layer1/i4b_l1lib.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2000 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_l1lib.c - general useful L1 procedures + * ------------------------------------------ + * + * $Id: i4b_l1lib.c,v 1.3 2000/05/29 15:41:41 hm Exp $ + * + * $FreeBSD$ + * + * last edit-date: [Mon May 29 15:24:21 2000] + * + *---------------------------------------------------------------------------*/ + +#include <sys/param.h> +#include <sys/systm.h> + + +#include <machine/i4b_ioctl.h> +#include <machine/i4b_trace.h> + +#include <i4b/layer1/i4b_l1.h> + +#define TEL_IDLE_MIN (BCH_MAX_DATALEN/2) + +/*---------------------------------------------------------------------------* + * telephony silence detection + *---------------------------------------------------------------------------*/ +int +i4b_l1_bchan_tel_silence(unsigned char *data, int len) +{ + register int i = 0; + register int j = 0; + + /* count idle bytes */ + + for(;i < len; i++) + { + if((*data >= 0xaa) && (*data <= 0xac)) + j++; + data++; + } + +#ifdef NOTDEF + printf("i4b_l1_bchan_tel_silence: got %d silence bytes in frame\n", j); +#endif + + if(j < (TEL_IDLE_MIN)) + return(0); + else + return(1); + +} diff --git a/sys/i4b/layer1/ifpi/i4b_ifpi_isac.c b/sys/i4b/layer1/ifpi/i4b_ifpi_isac.c new file mode 100644 index 000000000000..168506daba10 --- /dev/null +++ b/sys/i4b/layer1/ifpi/i4b_ifpi_isac.c @@ -0,0 +1,666 @@ +/* + * Copyright (c) 1997, 2000 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_ifpi_isac.c - i4b Fritz PCI ISAC handler + * -------------------------------------------- + * + * $Id: i4b_ifpi_isac.c,v 1.3 2000/05/29 15:41:41 hm Exp $ + * + * $FreeBSD$ + * + * last edit-date: [Mon May 29 15:22:52 2000] + * + *---------------------------------------------------------------------------*/ + +#include "ifpi.h" +#include "pci.h" + +#if (NIFPI > 0) && (NPCI > 0) + +#include "opt_i4b.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> + + +#include <net/if.h> + +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_trace.h> + +#include <i4b/layer1/i4b_l1.h> + +#include <i4b/layer1/isic/i4b_isic.h> +#include <i4b/layer1/isic/i4b_isac.h> +#include <i4b/layer1/isic/i4b_hscx.h> + +#include <i4b/layer1/ifpi/i4b_ifpi_ext.h> + +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_mbuf.h> + +static u_char ifpi_isac_exir_hdlr(register struct l1_softc *sc, u_char exir); +static void ifpi_isac_ind_hdlr(register struct l1_softc *sc, int ind); + +/*---------------------------------------------------------------------------* + * ISAC interrupt service routine + *---------------------------------------------------------------------------*/ +void +ifpi_isac_irq(struct l1_softc *sc, int ista) +{ + register u_char c = 0; + NDBGL1(L1_F_MSG, "unit %d: ista = 0x%02x", sc->sc_unit, ista); + + if(ista & ISAC_ISTA_EXI) /* extended interrupt */ + { + c |= ifpi_isac_exir_hdlr(sc, ISAC_READ(I_EXIR)); + } + + if(ista & ISAC_ISTA_RME) /* receive message end */ + { + register int rest; + u_char rsta; + + /* get rx status register */ + + rsta = ISAC_READ(I_RSTA); + + if((rsta & ISAC_RSTA_MASK) != 0x20) + { + int error = 0; + + if(!(rsta & ISAC_RSTA_CRC)) /* CRC error */ + { + error++; + NDBGL1(L1_I_ERR, "unit %d: CRC error", sc->sc_unit); + } + + if(rsta & ISAC_RSTA_RDO) /* ReceiveDataOverflow */ + { + error++; + NDBGL1(L1_I_ERR, "unit %d: Data Overrun error", sc->sc_unit); + } + + if(rsta & ISAC_RSTA_RAB) /* ReceiveABorted */ + { + error++; + NDBGL1(L1_I_ERR, "unit %d: Receive Aborted error", sc->sc_unit); + } + + if(error == 0) + NDBGL1(L1_I_ERR, "unit %d: RME unknown error, RSTA = 0x%02x!", sc->sc_unit, rsta); + + i4b_Dfreembuf(sc->sc_ibuf); + + c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; + + sc->sc_ibuf = NULL; + sc->sc_ib = NULL; + sc->sc_ilen = 0; + + ISAC_WRITE(I_CMDR, ISAC_CMDR_RMC|ISAC_CMDR_RRES); + ISACCMDRWRDELAY(); + + return; + } + + rest = (ISAC_READ(I_RBCL) & (ISAC_FIFO_LEN-1)); + + if(rest == 0) + rest = ISAC_FIFO_LEN; + + if(sc->sc_ibuf == NULL) + { + if((sc->sc_ibuf = i4b_Dgetmbuf(rest)) != NULL) + sc->sc_ib = sc->sc_ibuf->m_data; + else + panic("ifpi_isac_irq: RME, i4b_Dgetmbuf returns NULL!\n"); + sc->sc_ilen = 0; + } + + if(sc->sc_ilen <= (MAX_DFRAME_LEN - rest)) + { + ISAC_RDFIFO(sc->sc_ib, rest); + sc->sc_ilen += rest; + + sc->sc_ibuf->m_pkthdr.len = + sc->sc_ibuf->m_len = sc->sc_ilen; + + if(sc->sc_trace & TRACE_D_RX) + { + i4b_trace_hdr_t hdr; + hdr.unit = L0IFPIUNIT(sc->sc_unit); + hdr.type = TRC_CH_D; + hdr.dir = FROM_NT; + hdr.count = ++sc->sc_trace_dcount; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, sc->sc_ibuf->m_len, sc->sc_ibuf->m_data); + } + + c |= ISAC_CMDR_RMC; + + if(sc->sc_enabled && + (ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S)) + { + i4b_l1_ph_data_ind(L0IFPIUNIT(sc->sc_unit), sc->sc_ibuf); + } + else + { + i4b_Dfreembuf(sc->sc_ibuf); + } + } + else + { + NDBGL1(L1_I_ERR, "RME, input buffer overflow!"); + i4b_Dfreembuf(sc->sc_ibuf); + c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; + } + + sc->sc_ibuf = NULL; + sc->sc_ib = NULL; + sc->sc_ilen = 0; + } + + if(ista & ISAC_ISTA_RPF) /* receive fifo full */ + { + if(sc->sc_ibuf == NULL) + { + if((sc->sc_ibuf = i4b_Dgetmbuf(MAX_DFRAME_LEN)) != NULL) + sc->sc_ib= sc->sc_ibuf->m_data; + else + panic("ifpi_isac_irq: RPF, i4b_Dgetmbuf returns NULL!\n"); + sc->sc_ilen = 0; + } + + if(sc->sc_ilen <= (MAX_DFRAME_LEN - ISAC_FIFO_LEN)) + { + ISAC_RDFIFO(sc->sc_ib, ISAC_FIFO_LEN); + sc->sc_ilen += ISAC_FIFO_LEN; + sc->sc_ib += ISAC_FIFO_LEN; + c |= ISAC_CMDR_RMC; + } + else + { + NDBGL1(L1_I_ERR, "RPF, input buffer overflow!"); + i4b_Dfreembuf(sc->sc_ibuf); + sc->sc_ibuf = NULL; + sc->sc_ib = NULL; + sc->sc_ilen = 0; + c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; + } + } + + if(ista & ISAC_ISTA_XPR) /* transmit fifo empty (XPR bit set) */ + { + if((sc->sc_obuf2 != NULL) && (sc->sc_obuf == NULL)) + { + sc->sc_freeflag = sc->sc_freeflag2; + sc->sc_obuf = sc->sc_obuf2; + sc->sc_op = sc->sc_obuf->m_data; + sc->sc_ol = sc->sc_obuf->m_len; + sc->sc_obuf2 = NULL; +#ifdef NOTDEF + printf("ob2=%x, op=%x, ol=%d, f=%d #", + sc->sc_obuf, + sc->sc_op, + sc->sc_ol, + sc->sc_state); +#endif + } + else + { +#ifdef NOTDEF + printf("ob=%x, op=%x, ol=%d, f=%d #", + sc->sc_obuf, + sc->sc_op, + sc->sc_ol, + sc->sc_state); +#endif + } + + if(sc->sc_obuf) + { + ISAC_WRFIFO(sc->sc_op, min(sc->sc_ol, ISAC_FIFO_LEN)); + + if(sc->sc_ol > ISAC_FIFO_LEN) /* length > 32 ? */ + { + sc->sc_op += ISAC_FIFO_LEN; /* bufferptr+32 */ + sc->sc_ol -= ISAC_FIFO_LEN; /* length - 32 */ + c |= ISAC_CMDR_XTF; /* set XTF bit */ + } + else + { + if(sc->sc_freeflag) + { + i4b_Dfreembuf(sc->sc_obuf); + sc->sc_freeflag = 0; + } + sc->sc_obuf = NULL; + sc->sc_op = NULL; + sc->sc_ol = 0; + + c |= ISAC_CMDR_XTF | ISAC_CMDR_XME; + } + } + else + { + sc->sc_state &= ~ISAC_TX_ACTIVE; + } + } + + if(ista & ISAC_ISTA_CISQ) /* channel status change CISQ */ + { + register u_char ci; + + /* get command/indication rx register*/ + + ci = ISAC_READ(I_CIRR); + + /* if S/Q IRQ, read SQC reg to clr SQC IRQ */ + + if(ci & ISAC_CIRR_SQC) + (void) ISAC_READ(I_SQRR); + + /* C/I code change IRQ (flag already cleared by CIRR read) */ + + if(ci & ISAC_CIRR_CIC0) + ifpi_isac_ind_hdlr(sc, (ci >> 2) & 0xf); + } + + if(c) + { + ISAC_WRITE(I_CMDR, c); + ISACCMDRWRDELAY(); + } +} + +/*---------------------------------------------------------------------------* + * ISAC L1 Extended IRQ handler + *---------------------------------------------------------------------------*/ +static u_char +ifpi_isac_exir_hdlr(register struct l1_softc *sc, u_char exir) +{ + u_char c = 0; + + if(exir & ISAC_EXIR_XMR) + { + NDBGL1(L1_I_ERR, "EXIRQ Tx Message Repeat"); + + c |= ISAC_CMDR_XRES; + } + + if(exir & ISAC_EXIR_XDU) + { + NDBGL1(L1_I_ERR, "EXIRQ Tx Data Underrun"); + + c |= ISAC_CMDR_XRES; + } + + if(exir & ISAC_EXIR_PCE) + { + NDBGL1(L1_I_ERR, "EXIRQ Protocol Error"); + } + + if(exir & ISAC_EXIR_RFO) + { + NDBGL1(L1_I_ERR, "EXIRQ Rx Frame Overflow"); + + c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; + } + + if(exir & ISAC_EXIR_SOV) + { + NDBGL1(L1_I_ERR, "EXIRQ Sync Xfer Overflow"); + } + + if(exir & ISAC_EXIR_MOS) + { + NDBGL1(L1_I_ERR, "EXIRQ Monitor Status"); + } + + if(exir & ISAC_EXIR_SAW) + { + /* cannot happen, STCR:TSF is set to 0 */ + + NDBGL1(L1_I_ERR, "EXIRQ Subscriber Awake"); + } + + if(exir & ISAC_EXIR_WOV) + { + /* cannot happen, STCR:TSF is set to 0 */ + + NDBGL1(L1_I_ERR, "EXIRQ Watchdog Timer Overflow"); + } + + return(c); +} + +/*---------------------------------------------------------------------------* + * ISAC L1 Indication handler + *---------------------------------------------------------------------------*/ +static void +ifpi_isac_ind_hdlr(register struct l1_softc *sc, int ind) +{ + register int event; + + switch(ind) + { + case ISAC_CIRR_IAI8: + NDBGL1(L1_I_CICO, "rx AI8 in state %s", ifpi_printstate(sc)); + if(sc->sc_bustyp == BUS_TYPE_IOM2) + ifpi_isac_l1_cmd(sc, CMD_AR8); + event = EV_INFO48; + i4b_l1_mph_status_ind(L0IFPIUNIT(sc->sc_unit), STI_L1STAT, LAYER_ACTIVE, NULL); + break; + + case ISAC_CIRR_IAI10: + NDBGL1(L1_I_CICO, "rx AI10 in state %s", ifpi_printstate(sc)); + if(sc->sc_bustyp == BUS_TYPE_IOM2) + ifpi_isac_l1_cmd(sc, CMD_AR10); + event = EV_INFO410; + i4b_l1_mph_status_ind(L0IFPIUNIT(sc->sc_unit), STI_L1STAT, LAYER_ACTIVE, NULL); + break; + + case ISAC_CIRR_IRSY: + NDBGL1(L1_I_CICO, "rx RSY in state %s", ifpi_printstate(sc)); + event = EV_RSY; + break; + + case ISAC_CIRR_IPU: + NDBGL1(L1_I_CICO, "rx PU in state %s", ifpi_printstate(sc)); + event = EV_PU; + break; + + case ISAC_CIRR_IDR: + NDBGL1(L1_I_CICO, "rx DR in state %s", ifpi_printstate(sc)); + ifpi_isac_l1_cmd(sc, CMD_DIU); + event = EV_DR; + break; + + case ISAC_CIRR_IDID: + NDBGL1(L1_I_CICO, "rx DID in state %s", ifpi_printstate(sc)); + event = EV_INFO0; + i4b_l1_mph_status_ind(L0IFPIUNIT(sc->sc_unit), STI_L1STAT, LAYER_IDLE, NULL); + break; + + case ISAC_CIRR_IDIS: + NDBGL1(L1_I_CICO, "rx DIS in state %s", ifpi_printstate(sc)); + event = EV_DIS; + break; + + case ISAC_CIRR_IEI: + NDBGL1(L1_I_CICO, "rx EI in state %s", ifpi_printstate(sc)); + ifpi_isac_l1_cmd(sc, CMD_DIU); + event = EV_EI; + break; + + case ISAC_CIRR_IARD: + NDBGL1(L1_I_CICO, "rx ARD in state %s", ifpi_printstate(sc)); + event = EV_INFO2; + break; + + case ISAC_CIRR_ITI: + NDBGL1(L1_I_CICO, "rx TI in state %s", ifpi_printstate(sc)); + event = EV_INFO0; + break; + + case ISAC_CIRR_IATI: + NDBGL1(L1_I_CICO, "rx ATI in state %s", ifpi_printstate(sc)); + event = EV_INFO0; + break; + + case ISAC_CIRR_ISD: + NDBGL1(L1_I_CICO, "rx SD in state %s", ifpi_printstate(sc)); + event = EV_INFO0; + break; + + default: + NDBGL1(L1_I_ERR, "UNKNOWN Indication 0x%x in state %s", ind, ifpi_printstate(sc)); + event = EV_INFO0; + break; + } + ifpi_next_state(sc, event); +} + +/*---------------------------------------------------------------------------* + * execute a layer 1 command + *---------------------------------------------------------------------------*/ +void +ifpi_isac_l1_cmd(struct l1_softc *sc, int command) +{ + u_char cmd; + +#ifdef I4B_SMP_WORKAROUND + + /* XXXXXXXXXXXXXXXXXXX */ + + /* + * patch from Wolfgang Helbig: + * + * Here is a patch that makes i4b work on an SMP: + * The card (TELES 16.3) didn't interrupt on an SMP machine. + * This is a gross workaround, but anyway it works *and* provides + * some information as how to finally fix this problem. + */ + + HSCX_WRITE(0, H_MASK, 0xff); + HSCX_WRITE(1, H_MASK, 0xff); + ISAC_WRITE(I_MASK, 0xff); + DELAY(100); + HSCX_WRITE(0, H_MASK, HSCX_A_IMASK); + HSCX_WRITE(1, H_MASK, HSCX_B_IMASK); + ISAC_WRITE(I_MASK, ISAC_IMASK); + + /* XXXXXXXXXXXXXXXXXXX */ + +#endif /* I4B_SMP_WORKAROUND */ + + if(command < 0 || command > CMD_ILL) + { + NDBGL1(L1_I_ERR, "illegal cmd 0x%x in state %s", command, ifpi_printstate(sc)); + return; + } + + if(sc->sc_bustyp == BUS_TYPE_IOM2) + cmd = ISAC_CIX0_LOW; + else + cmd = 0; + + switch(command) + { + case CMD_TIM: + NDBGL1(L1_I_CICO, "tx TIM in state %s", ifpi_printstate(sc)); + cmd |= (ISAC_CIXR_CTIM << 2); + break; + + case CMD_RS: + NDBGL1(L1_I_CICO, "tx RS in state %s", ifpi_printstate(sc)); + cmd |= (ISAC_CIXR_CRS << 2); + break; + + case CMD_AR8: + NDBGL1(L1_I_CICO, "tx AR8 in state %s", ifpi_printstate(sc)); + cmd |= (ISAC_CIXR_CAR8 << 2); + break; + + case CMD_AR10: + NDBGL1(L1_I_CICO, "tx AR10 in state %s", ifpi_printstate(sc)); + cmd |= (ISAC_CIXR_CAR10 << 2); + break; + + case CMD_DIU: + NDBGL1(L1_I_CICO, "tx DIU in state %s", ifpi_printstate(sc)); + cmd |= (ISAC_CIXR_CDIU << 2); + break; + } + ISAC_WRITE(I_CIXR, cmd); +} + +/*---------------------------------------------------------------------------* + * L1 ISAC initialization + *---------------------------------------------------------------------------*/ +int +ifpi_isac_init(struct l1_softc *sc) +{ + ISAC_IMASK = 0xff; /* disable all irqs */ + + ISAC_WRITE(I_MASK, ISAC_IMASK); + + if(sc->sc_bustyp != BUS_TYPE_IOM2) + { + NDBGL1(L1_I_SETUP, "configuring for IOM-1 mode"); + + /* ADF2: Select mode IOM-1 */ + ISAC_WRITE(I_ADF2, 0x00); + + /* SPCR: serial port control register: + * SPU - software power up = 0 + * SAC - SIP port high Z + * SPM - timing mode 0 + * TLP - test loop = 0 + * C1C, C2C - B1 and B2 switched to/from SPa + */ + ISAC_WRITE(I_SPCR, ISAC_SPCR_C1C1|ISAC_SPCR_C2C1); + + /* SQXR: S/Q channel xmit register: + * SQIE - S/Q IRQ enable = 0 + * SQX1-4 - Fa bits = 1 + */ + ISAC_WRITE(I_SQXR, ISAC_SQXR_SQX1|ISAC_SQXR_SQX2|ISAC_SQXR_SQX3|ISAC_SQXR_SQX4); + + /* ADF1: additional feature reg 1: + * WTC - watchdog = 0 + * TEM - test mode = 0 + * PFS - pre-filter = 0 + * CFS - IOM clock/frame always active + * FSC1/2 - polarity of 8kHz strobe + * ITF - interframe fill = idle + */ + ISAC_WRITE(I_ADF1, ISAC_ADF1_FC2); /* ADF1 */ + + /* STCR: sync transfer control reg: + * TSF - terminal secific functions = 0 + * TBA - TIC bus address = 7 + * STx/SCx = 0 + */ + ISAC_WRITE(I_STCR, ISAC_STCR_TBA2|ISAC_STCR_TBA1|ISAC_STCR_TBA0); + + /* MODE: Mode Register: + * MDSx - transparent mode 2 + * TMD - timer mode = external + * RAC - Receiver enabled + * DIMx - digital i/f mode + */ + ISAC_WRITE(I_MODE, ISAC_MODE_MDS2|ISAC_MODE_MDS1|ISAC_MODE_RAC|ISAC_MODE_DIM0); + } + else + { + NDBGL1(L1_I_SETUP, "configuring for IOM-2 mode"); + + /* ADF2: Select mode IOM-2 */ + ISAC_WRITE(I_ADF2, ISAC_ADF2_IMS); + + /* SPCR: serial port control register: + * SPU - software power up = 0 + * SPM - timing mode 0 + * TLP - test loop = 0 + * C1C, C2C - B1 + C1 and B2 + IC2 monitoring + */ + ISAC_WRITE(I_SPCR, 0x00); + + /* SQXR: S/Q channel xmit register: + * IDC - IOM direction = 0 (master) + * CFS - Config Select = 0 (clock always active) + * CI1E - C/I channel 1 IRQ enable = 0 + * SQIE - S/Q IRQ enable = 0 + * SQX1-4 - Fa bits = 1 + */ + ISAC_WRITE(I_SQXR, ISAC_SQXR_SQX1|ISAC_SQXR_SQX2|ISAC_SQXR_SQX3|ISAC_SQXR_SQX4); + + /* ADF1: additional feature reg 1: + * WTC - watchdog = 0 + * TEM - test mode = 0 + * PFS - pre-filter = 0 + * IOF - IOM i/f off = 0 + * ITF - interframe fill = idle + */ + ISAC_WRITE(I_ADF1, 0x00); + + /* STCR: sync transfer control reg: + * TSF - terminal secific functions = 0 + * TBA - TIC bus address = 7 + * STx/SCx = 0 + */ + ISAC_WRITE(I_STCR, ISAC_STCR_TBA2|ISAC_STCR_TBA1|ISAC_STCR_TBA0); + + /* MODE: Mode Register: + * MDSx - transparent mode 2 + * TMD - timer mode = external + * RAC - Receiver enabled + * DIMx - digital i/f mode + */ + ISAC_WRITE(I_MODE, ISAC_MODE_MDS2|ISAC_MODE_MDS1|ISAC_MODE_RAC|ISAC_MODE_DIM0); + } + +#ifdef NOTDEF + /* + * XXX a transmitter reset causes an ISAC tx IRQ which will not + * be serviced at attach time under some circumstances leaving + * the associated IRQ line on the ISA bus active. This prevents + * any further interrupts to be serviced because no low -> high + * transition can take place anymore. (-hm) + */ + + /* command register: + * RRES - HDLC receiver reset + * XRES - transmitter reset + */ + ISAC_WRITE(I_CMDR, ISAC_CMDR_RRES|ISAC_CMDR_XRES); + ISACCMDRWRDELAY(); +#endif + + /* enabled interrupts: + * =================== + * RME - receive message end + * RPF - receive pool full + * XPR - transmit pool ready + * CISQ - CI or S/Q channel change + * EXI - extended interrupt + */ + + ISAC_IMASK = ISAC_MASK_RSC | /* auto mode only */ + ISAC_MASK_TIN | /* timer irq */ + ISAC_MASK_SIN; /* sync xfer irq */ + + ISAC_WRITE(I_MASK, ISAC_IMASK); + + return(0); +} + +#endif /* NIFPI > 0 */ diff --git a/sys/i4b/layer1/ifpi/i4b_ifpi_l1.c b/sys/i4b/layer1/ifpi/i4b_ifpi_l1.c new file mode 100644 index 000000000000..3d417a35fb95 --- /dev/null +++ b/sys/i4b/layer1/ifpi/i4b_ifpi_l1.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) 1997, 2000 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_ifpi_l1.c - AVM Fritz PCI layer 1 handler + * --------------------------------------------- + * + * $Id: i4b_ifpi_l1.c,v 1.4 2000/06/02 16:14:36 hm Exp $ + * + * $FreeBSD$ + * + * last edit-date: [Fri Jun 2 14:54:30 2000] + * + *---------------------------------------------------------------------------*/ + +#include "ifpi.h" +#include "pci.h" + +#if (NIFPI > 0) && (NPCI > 0) + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> + + +#include <net/if.h> + +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_trace.h> + +#include <i4b/layer1/isic/i4b_isic.h> +#include <i4b/layer1/isic/i4b_isac.h> + +#include <i4b/layer1/ifpi/i4b_ifpi_ext.h> + +#include <i4b/layer1/i4b_l1.h> + +#include <i4b/include/i4b_mbuf.h> +#include <i4b/include/i4b_global.h> + +/*---------------------------------------------------------------------------* + * + * L2 -> L1: PH-DATA-REQUEST + * ========================= + * + * parms: + * unit physical interface unit number + * m mbuf containing L2 frame to be sent out + * freeflag MBUF_FREE: free mbuf here after having sent + * it out + * MBUF_DONTFREE: mbuf is freed by Layer 2 + * returns: + * ==0 fail, nothing sent out + * !=0 ok, frame sent out + * + *---------------------------------------------------------------------------*/ +int +ifpi_ph_data_req(int unit, struct mbuf *m, int freeflag) +{ + u_char cmd; + int s; + struct l1_softc *sc = ifpi_scp[unit]; + +#ifdef NOTDEF + NDBGL1(L1_PRIM, "PH-DATA-REQ, unit %d, freeflag=%d", unit, freeflag); +#endif + + if(m == NULL) /* failsafe */ + return (0); + + s = SPLI4B(); + + if(sc->sc_I430state == ST_F3) /* layer 1 not running ? */ + { + NDBGL1(L1_I_ERR, "still in state F3!"); + ifpi_ph_activate_req(unit); + } + + if(sc->sc_state & ISAC_TX_ACTIVE) + { + if(sc->sc_obuf2 == NULL) + { + sc->sc_obuf2 = m; /* save mbuf ptr */ + + if(freeflag) + sc->sc_freeflag2 = 1; /* IRQ must mfree */ + else + sc->sc_freeflag2 = 0; /* IRQ must not mfree */ + + NDBGL1(L1_I_MSG, "using 2nd ISAC TX buffer, state = %s", ifpi_printstate(sc)); + + if(sc->sc_trace & TRACE_D_TX) + { + i4b_trace_hdr_t hdr; + hdr.unit = L0IFPIUNIT(unit); + hdr.type = TRC_CH_D; + hdr.dir = FROM_TE; + hdr.count = ++sc->sc_trace_dcount; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, m->m_len, m->m_data); + } + splx(s); + return(1); + } + + NDBGL1(L1_I_ERR, "No Space in TX FIFO, state = %s", ifpi_printstate(sc)); + + if(freeflag == MBUF_FREE) + i4b_Dfreembuf(m); + + splx(s); + return (0); + } + + if(sc->sc_trace & TRACE_D_TX) + { + i4b_trace_hdr_t hdr; + hdr.unit = L0IFPIUNIT(unit); + hdr.type = TRC_CH_D; + hdr.dir = FROM_TE; + hdr.count = ++sc->sc_trace_dcount; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, m->m_len, m->m_data); + } + + sc->sc_state |= ISAC_TX_ACTIVE; /* set transmitter busy flag */ + + NDBGL1(L1_I_MSG, "ISAC_TX_ACTIVE set"); + + sc->sc_freeflag = 0; /* IRQ must NOT mfree */ + + ISAC_WRFIFO(m->m_data, min(m->m_len, ISAC_FIFO_LEN)); /* output to TX fifo */ + + if(m->m_len > ISAC_FIFO_LEN) /* message > 32 bytes ? */ + { + sc->sc_obuf = m; /* save mbuf ptr */ + sc->sc_op = m->m_data + ISAC_FIFO_LEN; /* ptr for irq hdl */ + sc->sc_ol = m->m_len - ISAC_FIFO_LEN; /* length for irq hdl */ + + if(freeflag) + sc->sc_freeflag = 1; /* IRQ must mfree */ + + cmd = ISAC_CMDR_XTF; + } + else + { + sc->sc_obuf = NULL; + sc->sc_op = NULL; + sc->sc_ol = 0; + + if(freeflag) + i4b_Dfreembuf(m); + + cmd = ISAC_CMDR_XTF | ISAC_CMDR_XME; + } + + ISAC_WRITE(I_CMDR, cmd); + ISACCMDRWRDELAY(); + + splx(s); + + return(1); +} + +/*---------------------------------------------------------------------------* + * + * L2 -> L1: PH-ACTIVATE-REQUEST + * ============================= + * + * parms: + * unit physical interface unit number + * + * returns: + * ==0 + * !=0 + * + *---------------------------------------------------------------------------*/ +int +ifpi_ph_activate_req(int unit) +{ + struct l1_softc *sc = ifpi_scp[unit]; + NDBGL1(L1_PRIM, "PH-ACTIVATE-REQ, unit %d", unit); + ifpi_next_state(sc, EV_PHAR); + return(0); +} + +/*---------------------------------------------------------------------------* + * command from the upper layers + *---------------------------------------------------------------------------*/ +int +ifpi_mph_command_req(int unit, int command, void *parm) +{ + struct l1_softc *sc = ifpi_scp[unit]; + + switch(command) + { + case CMR_DOPEN: /* daemon running */ + NDBGL1(L1_PRIM, "unit %d, command = CMR_DOPEN", unit); + sc->sc_enabled = 1; + break; + + case CMR_DCLOSE: /* daemon not running */ + NDBGL1(L1_PRIM, "unit %d, command = CMR_DCLOSE", unit); + sc->sc_enabled = 0; + break; + + case CMR_SETTRACE: + NDBGL1(L1_PRIM, "unit %d, command = CMR_SETTRACE, parm = %d", unit, (unsigned int)parm); + sc->sc_trace = (unsigned int)parm; + break; + + default: + NDBGL1(L1_ERROR, "ERROR, unknown command = %d, unit = %d, parm = %d", command, unit, (unsigned int)parm); + break; + } + + return(0); +} + +#endif /* NIFPI > 0 */ diff --git a/sys/i4b/layer1/ifpi/i4b_ifpi_l1fsm.c b/sys/i4b/layer1/ifpi/i4b_ifpi_l1fsm.c new file mode 100644 index 000000000000..274ab9896906 --- /dev/null +++ b/sys/i4b/layer1/ifpi/i4b_ifpi_l1fsm.c @@ -0,0 +1,517 @@ +/* + * Copyright (c) 1997, 2000 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_ifpi_l1fsm.c - AVM Fritz PCI layer 1 I.430 state machine + * ------------------------------------------------------------ + * + * $Id: i4b_ifpi_l1fsm.c,v 1.4 2000/05/29 15:41:41 hm Exp $ + * + * $FreeBSD$ + * + * last edit-date: [Mon May 29 15:23:15 2000] + * + *---------------------------------------------------------------------------*/ + +#include "ifpi.h" +#include "pci.h" + +#if (NIFPI > 0) && (NPCI > 0) + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/socket.h> + + +#include <net/if.h> + +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_trace.h> + +#include <i4b/layer1/isic/i4b_isic.h> + +#include <i4b/layer1/i4b_l1.h> + +#include <i4b/include/i4b_global.h> + +#include <i4b/include/i4b_mbuf.h> + +#include <i4b/layer1/ifpi/i4b_ifpi_ext.h> + +#if DO_I4B_DEBUG +static char *state_text[N_STATES] = { + "F3 Deactivated", + "F4 Awaiting Signal", + "F5 Identifying Input", + "F6 Synchronized", + "F7 Activated", + "F8 Lost Framing", + "Illegal State" +}; + +static char *event_text[N_EVENTS] = { + "EV_PHAR PH_ACT_REQ", + "EV_T3 Timer 3 expired", + "EV_INFO0 INFO0 received", + "EV_RSY Level Detected", + "EV_INFO2 INFO2 received", + "EV_INFO48 INFO4 received", + "EV_INFO410 INFO4 received", + "EV_DR Deactivate Req", + "EV_PU Power UP", + "EV_DIS Disconnected", + "EV_EI Error Ind", + "Illegal Event" +}; +#endif + +/* Function prototypes */ + +static void timer3_expired (struct l1_softc *sc); +static void T3_start (struct l1_softc *sc); +static void T3_stop (struct l1_softc *sc); +static void F_T3ex (struct l1_softc *sc); +static void timer4_expired (struct l1_softc *sc); +static void T4_start (struct l1_softc *sc); +static void T4_stop (struct l1_softc *sc); +static void F_AI8 (struct l1_softc *sc); +static void F_AI10 (struct l1_softc *sc); +static void F_I01 (struct l1_softc *sc); +static void F_I02 (struct l1_softc *sc); +static void F_I03 (struct l1_softc *sc); +static void F_I2 (struct l1_softc *sc); +static void F_ill (struct l1_softc *sc); +static void F_NULL (struct l1_softc *sc); + +/*---------------------------------------------------------------------------* + * I.430 Timer T3 expire function + *---------------------------------------------------------------------------*/ +static void +timer3_expired(struct l1_softc *sc) +{ + if(sc->sc_I430T3) + { + NDBGL1(L1_T_ERR, "state = %s", ifpi_printstate(sc)); + sc->sc_I430T3 = 0; + + /* XXX try some recovery here XXX */ + + ifpi_recover(sc); + + sc->sc_init_tries++; /* increment retry count */ + +/*XXX*/ if(sc->sc_init_tries > 4) + { + int s = SPLI4B(); + + sc->sc_init_tries = 0; + + if(sc->sc_obuf2 != NULL) + { + i4b_Dfreembuf(sc->sc_obuf2); + sc->sc_obuf2 = NULL; + } + if(sc->sc_obuf != NULL) + { + i4b_Dfreembuf(sc->sc_obuf); + sc->sc_obuf = NULL; + sc->sc_freeflag = 0; + sc->sc_op = NULL; + sc->sc_ol = 0; + } + + splx(s); + + i4b_l1_mph_status_ind(L0IFPIUNIT(sc->sc_unit), STI_NOL1ACC, 0, NULL); + } + + ifpi_next_state(sc, EV_T3); + } + else + { + NDBGL1(L1_T_ERR, "expired without starting it ...."); + } +} + +/*---------------------------------------------------------------------------* + * I.430 Timer T3 start + *---------------------------------------------------------------------------*/ +static void +T3_start(struct l1_softc *sc) +{ + NDBGL1(L1_T_MSG, "state = %s", ifpi_printstate(sc)); + sc->sc_I430T3 = 1; + sc->sc_T3_callout = timeout((TIMEOUT_FUNC_T)timer3_expired,(struct l1_softc *)sc, 2*hz); +} + +/*---------------------------------------------------------------------------* + * I.430 Timer T3 stop + *---------------------------------------------------------------------------*/ +static void +T3_stop(struct l1_softc *sc) +{ + NDBGL1(L1_T_MSG, "state = %s", ifpi_printstate(sc)); + + sc->sc_init_tries = 0; /* init connect retry count */ + + if(sc->sc_I430T3) + { + sc->sc_I430T3 = 0; + untimeout((TIMEOUT_FUNC_T)timer3_expired,(struct l1_softc *)sc, sc->sc_T3_callout); + } +} + +/*---------------------------------------------------------------------------* + * I.430 Timer T3 expiry + *---------------------------------------------------------------------------*/ +static void +F_T3ex(struct l1_softc *sc) +{ + NDBGL1(L1_F_MSG, "FSM function F_T3ex executing"); + if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) + i4b_l1_ph_deactivate_ind(L0IFPIUNIT(sc->sc_unit)); +} + +/*---------------------------------------------------------------------------* + * Timer T4 expire function + *---------------------------------------------------------------------------*/ +static void +timer4_expired(struct l1_softc *sc) +{ + if(sc->sc_I430T4) + { + NDBGL1(L1_T_MSG, "state = %s", ifpi_printstate(sc)); + sc->sc_I430T4 = 0; + i4b_l1_mph_status_ind(L0IFPIUNIT(sc->sc_unit), STI_PDEACT, 0, NULL); + } + else + { + NDBGL1(L1_T_ERR, "expired without starting it ...."); + } +} + +/*---------------------------------------------------------------------------* + * Timer T4 start + *---------------------------------------------------------------------------*/ +static void +T4_start(struct l1_softc *sc) +{ + NDBGL1(L1_T_MSG, "state = %s", ifpi_printstate(sc)); + sc->sc_I430T4 = 1; + sc->sc_T4_callout = timeout((TIMEOUT_FUNC_T)timer4_expired,(struct l1_softc *)sc, hz); +} + +/*---------------------------------------------------------------------------* + * Timer T4 stop + *---------------------------------------------------------------------------*/ +static void +T4_stop(struct l1_softc *sc) +{ + NDBGL1(L1_T_MSG, "state = %s", ifpi_printstate(sc)); + + if(sc->sc_I430T4) + { + sc->sc_I430T4 = 0; + untimeout((TIMEOUT_FUNC_T)timer4_expired,(struct l1_softc *)sc, sc->sc_T4_callout); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: received AI8 + *---------------------------------------------------------------------------*/ +static void +F_AI8(struct l1_softc *sc) +{ + T4_stop(sc); + + NDBGL1(L1_F_MSG, "FSM function F_AI8 executing"); + + if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) + i4b_l1_ph_activate_ind(L0IFPIUNIT(sc->sc_unit)); + + T3_stop(sc); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO4_8; + + hdr.unit = L0IFPIUNIT(sc->sc_unit); + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, 1, &info); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: received AI10 + *---------------------------------------------------------------------------*/ +static void +F_AI10(struct l1_softc *sc) +{ + T4_stop(sc); + + NDBGL1(L1_F_MSG, "FSM function F_AI10 executing"); + + if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) + i4b_l1_ph_activate_ind(L0IFPIUNIT(sc->sc_unit)); + + T3_stop(sc); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO4_10; + + hdr.unit = L0IFPIUNIT(sc->sc_unit); + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, 1, &info); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: received INFO 0 in states F3 .. F5 + *---------------------------------------------------------------------------*/ +static void +F_I01(struct l1_softc *sc) +{ + NDBGL1(L1_F_MSG, "FSM function F_I01 executing"); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO0; + + hdr.unit = L0IFPIUNIT(sc->sc_unit); + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, 1, &info); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: received INFO 0 in state F6 + *---------------------------------------------------------------------------*/ +static void +F_I02(struct l1_softc *sc) +{ + NDBGL1(L1_F_MSG, "FSM function F_I02 executing"); + + if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) + i4b_l1_ph_deactivate_ind(L0IFPIUNIT(sc->sc_unit)); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO0; + + hdr.unit = L0IFPIUNIT(sc->sc_unit); + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, 1, &info); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: received INFO 0 in state F7 or F8 + *---------------------------------------------------------------------------*/ +static void +F_I03(struct l1_softc *sc) +{ + NDBGL1(L1_F_MSG, "FSM function F_I03 executing"); + + if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) + i4b_l1_ph_deactivate_ind(L0IFPIUNIT(sc->sc_unit)); + + T4_start(sc); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO0; + + hdr.unit = L0IFPIUNIT(sc->sc_unit); + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, 1, &info); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: activate request + *---------------------------------------------------------------------------*/ +static void +F_AR(struct l1_softc *sc) +{ + NDBGL1(L1_F_MSG, "FSM function F_AR executing"); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO1_8; + + hdr.unit = L0IFPIUNIT(sc->sc_unit); + hdr.type = TRC_CH_I; + hdr.dir = FROM_TE; + hdr.count = 0; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, 1, &info); + } + + ifpi_isac_l1_cmd(sc, CMD_AR8); + + T3_start(sc); +} + +/*---------------------------------------------------------------------------* + * FSM function: received INFO2 + *---------------------------------------------------------------------------*/ +static void +F_I2(struct l1_softc *sc) +{ + NDBGL1(L1_F_MSG, "FSM function F_I2 executing"); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO2; + + hdr.unit = L0IFPIUNIT(sc->sc_unit); + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, 1, &info); + } + +} + +/*---------------------------------------------------------------------------* + * illegal state default action + *---------------------------------------------------------------------------*/ +static void +F_ill(struct l1_softc *sc) +{ + NDBGL1(L1_F_ERR, "FSM function F_ill executing"); +} + +/*---------------------------------------------------------------------------* + * No action + *---------------------------------------------------------------------------*/ +static void +F_NULL(struct l1_softc *sc) +{ + NDBGL1(L1_F_MSG, "FSM function F_NULL executing"); +} + + +/*---------------------------------------------------------------------------* + * layer 1 state transition table + *---------------------------------------------------------------------------*/ +struct ifpi_state_tab { + void (*func) (struct l1_softc *sc); /* function to execute */ + int newstate; /* next state */ +} ifpi_state_tab[N_EVENTS][N_STATES] = { + +/* STATE: F3 F4 F5 F6 F7 F8 ILLEGAL STATE */ +/* -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +/* EV_PHAR x*/ {{F_AR, ST_F4}, {F_NULL, ST_F4}, {F_NULL, ST_F5}, {F_NULL, ST_F6}, {F_ill, ST_ILL}, {F_NULL, ST_F8}, {F_ill, ST_ILL}}, +/* EV_T3 x*/ {{F_NULL, ST_F3}, {F_T3ex, ST_F3}, {F_T3ex, ST_F3}, {F_T3ex, ST_F3}, {F_NULL, ST_F7}, {F_NULL, ST_F8}, {F_ill, ST_ILL}}, +/* EV_INFO0 */ {{F_I01, ST_F3}, {F_I01, ST_F4}, {F_I01, ST_F5}, {F_I02, ST_F3}, {F_I03, ST_F3}, {F_I03, ST_F3}, {F_ill, ST_ILL}}, +/* EV_RSY x*/ {{F_NULL, ST_F3}, {F_NULL, ST_F5}, {F_NULL, ST_F5}, {F_NULL, ST_F8}, {F_NULL, ST_F8}, {F_NULL, ST_F8}, {F_ill, ST_ILL}}, +/* EV_INFO2 */ {{F_I2, ST_F6}, {F_I2, ST_F6}, {F_I2, ST_F6}, {F_I2, ST_F6}, {F_I2, ST_F6}, {F_I2, ST_F6}, {F_ill, ST_ILL}}, +/* EV_INFO48*/ {{F_AI8, ST_F7}, {F_AI8, ST_F7}, {F_AI8, ST_F7}, {F_AI8, ST_F7}, {F_NULL, ST_F7}, {F_AI8, ST_F7}, {F_ill, ST_ILL}}, +/* EV_INFO41*/ {{F_AI10, ST_F7}, {F_AI10, ST_F7}, {F_AI10, ST_F7}, {F_AI10, ST_F7}, {F_NULL, ST_F7}, {F_AI10, ST_F7}, {F_ill, ST_ILL}}, +/* EV_DR */ {{F_NULL, ST_F3}, {F_NULL, ST_F4}, {F_NULL, ST_F5}, {F_NULL, ST_F6}, {F_NULL, ST_F7}, {F_NULL, ST_F8}, {F_ill, ST_ILL}}, +/* EV_PU */ {{F_NULL, ST_F3}, {F_NULL, ST_F4}, {F_NULL, ST_F5}, {F_NULL, ST_F6}, {F_NULL, ST_F7}, {F_NULL, ST_F8}, {F_ill, ST_ILL}}, +/* EV_DIS */ {{F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}}, +/* EV_EI */ {{F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_ill, ST_ILL}}, +/* EV_ILL */ {{F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}} +}; + +/*---------------------------------------------------------------------------* + * event handler + *---------------------------------------------------------------------------*/ +void +ifpi_next_state(struct l1_softc *sc, int event) +{ + int currstate, newstate; + + if(event >= N_EVENTS) + panic("i4b_l1fsm.c: event >= N_EVENTS\n"); + + currstate = sc->sc_I430state; + + if(currstate >= N_STATES) + panic("i4b_l1fsm.c: currstate >= N_STATES\n"); + + newstate = ifpi_state_tab[event][currstate].newstate; + + if(newstate >= N_STATES) + panic("i4b_l1fsm.c: newstate >= N_STATES\n"); + + NDBGL1(L1_F_MSG, "FSM event [%s]: [%s => %s]", event_text[event], + state_text[currstate], + state_text[newstate]); + + (*ifpi_state_tab[event][currstate].func)(sc); + + if(newstate == ST_ILL) + { + newstate = ST_F3; + NDBGL1(L1_F_ERR, "FSM Illegal State ERROR, oldstate = %s, newstate = %s, event = %s!", + state_text[currstate], + state_text[newstate], + event_text[event]); + } + + sc->sc_I430state = newstate; +} + +#if DO_I4B_DEBUG +/*---------------------------------------------------------------------------* + * return pointer to current state description + *---------------------------------------------------------------------------*/ +char * +ifpi_printstate(struct l1_softc *sc) +{ + return((char *) state_text[sc->sc_I430state]); +} +#endif + +#endif /* NIFPI > 0 */ diff --git a/sys/i4b/layer1/ifpnp/i4b_ifpnp_isac.c b/sys/i4b/layer1/ifpnp/i4b_ifpnp_isac.c new file mode 100644 index 000000000000..83fe1bf7ef58 --- /dev/null +++ b/sys/i4b/layer1/ifpnp/i4b_ifpnp_isac.c @@ -0,0 +1,666 @@ +/* + * Copyright (c) 1997, 2000 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_ifpnp_isac.c - i4b Fritz PnP ISAC handler + * --------------------------------------------- + * + * $Id: i4b_ifpnp_isac.c,v 1.3 2000/05/29 15:41:41 hm Exp $ + * $Ust: src/i4b/layer1-nb/ifpnp/i4b_ifpnp_isac.c,v 1.4 2000/04/18 08:03:05 ust Exp $ + * + * $FreeBSD$ + * + * last edit-date: [Mon May 29 15:24:49 2000] + * + *---------------------------------------------------------------------------*/ + +#include "ifpnp.h" + +#if (NIFPNP > 0) + +#include "opt_i4b.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> + + +#include <net/if.h> + +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_trace.h> + +#include <i4b/layer1/i4b_l1.h> + +#include <i4b/layer1/isic/i4b_isic.h> +#include <i4b/layer1/isic/i4b_isac.h> +#include <i4b/layer1/isic/i4b_hscx.h> + +#include <i4b/layer1/ifpnp/i4b_ifpnp_ext.h> + +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_mbuf.h> + +static u_char ifpnp_isac_exir_hdlr(register struct l1_softc *sc, u_char exir); +static void ifpnp_isac_ind_hdlr(register struct l1_softc *sc, int ind); + +/*---------------------------------------------------------------------------* + * ISAC interrupt service routine + *---------------------------------------------------------------------------*/ +void +ifpnp_isac_irq(struct l1_softc *sc, int ista) +{ + register u_char c = 0; + NDBGL1(L1_F_MSG, "unit %d: ista = 0x%02x", sc->sc_unit, ista); + + if(ista & ISAC_ISTA_EXI) /* extended interrupt */ + { + c |= ifpnp_isac_exir_hdlr(sc, ISAC_READ(I_EXIR)); + } + + if(ista & ISAC_ISTA_RME) /* receive message end */ + { + register int rest; + u_char rsta; + + /* get rx status register */ + + rsta = ISAC_READ(I_RSTA); + + if((rsta & ISAC_RSTA_MASK) != 0x20) + { + int error = 0; + + if(!(rsta & ISAC_RSTA_CRC)) /* CRC error */ + { + error++; + NDBGL1(L1_I_ERR, "unit %d: CRC error", sc->sc_unit); + } + + if(rsta & ISAC_RSTA_RDO) /* ReceiveDataOverflow */ + { + error++; + NDBGL1(L1_I_ERR, "unit %d: Data Overrun error", sc->sc_unit); + } + + if(rsta & ISAC_RSTA_RAB) /* ReceiveABorted */ + { + error++; + NDBGL1(L1_I_ERR, "unit %d: Receive Aborted error", sc->sc_unit); + } + + if(error == 0) + NDBGL1(L1_I_ERR, "unit %d: RME unknown error, RSTA = 0x%02x!", sc->sc_unit, rsta); + + i4b_Dfreembuf(sc->sc_ibuf); + + c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; + + sc->sc_ibuf = NULL; + sc->sc_ib = NULL; + sc->sc_ilen = 0; + + ISAC_WRITE(I_CMDR, ISAC_CMDR_RMC|ISAC_CMDR_RRES); + ISACCMDRWRDELAY(); + + return; + } + + rest = (ISAC_READ(I_RBCL) & (ISAC_FIFO_LEN-1)); + + if(rest == 0) + rest = ISAC_FIFO_LEN; + + if(sc->sc_ibuf == NULL) + { + if((sc->sc_ibuf = i4b_Dgetmbuf(rest)) != NULL) + sc->sc_ib = sc->sc_ibuf->m_data; + else + panic("ifpnp_isac_irq: RME, i4b_Dgetmbuf returns NULL!\n"); + sc->sc_ilen = 0; + } + + if(sc->sc_ilen <= (MAX_DFRAME_LEN - rest)) + { + ISAC_RDFIFO(sc->sc_ib, rest); + sc->sc_ilen += rest; + + sc->sc_ibuf->m_pkthdr.len = + sc->sc_ibuf->m_len = sc->sc_ilen; + + if(sc->sc_trace & TRACE_D_RX) + { + i4b_trace_hdr_t hdr; + hdr.unit = L0IFPNPUNIT(sc->sc_unit); + hdr.type = TRC_CH_D; + hdr.dir = FROM_NT; + hdr.count = ++sc->sc_trace_dcount; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, sc->sc_ibuf->m_len, sc->sc_ibuf->m_data); + } + + c |= ISAC_CMDR_RMC; + + if(sc->sc_enabled && + (ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S)) + { + i4b_l1_ph_data_ind(L0IFPNPUNIT(sc->sc_unit), sc->sc_ibuf); + } + else + { + i4b_Dfreembuf(sc->sc_ibuf); + } + } + else + { + NDBGL1(L1_I_ERR, "RME, input buffer overflow!"); + i4b_Dfreembuf(sc->sc_ibuf); + c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; + } + + sc->sc_ibuf = NULL; + sc->sc_ib = NULL; + sc->sc_ilen = 0; + } + + if(ista & ISAC_ISTA_RPF) /* receive fifo full */ + { + if(sc->sc_ibuf == NULL) + { + if((sc->sc_ibuf = i4b_Dgetmbuf(MAX_DFRAME_LEN)) != NULL) + sc->sc_ib= sc->sc_ibuf->m_data; + else + panic("ifpnp_isac_irq: RPF, i4b_Dgetmbuf returns NULL!\n"); + sc->sc_ilen = 0; + } + + if(sc->sc_ilen <= (MAX_DFRAME_LEN - ISAC_FIFO_LEN)) + { + ISAC_RDFIFO(sc->sc_ib, ISAC_FIFO_LEN); + sc->sc_ilen += ISAC_FIFO_LEN; + sc->sc_ib += ISAC_FIFO_LEN; + c |= ISAC_CMDR_RMC; + } + else + { + NDBGL1(L1_I_ERR, "RPF, input buffer overflow!"); + i4b_Dfreembuf(sc->sc_ibuf); + sc->sc_ibuf = NULL; + sc->sc_ib = NULL; + sc->sc_ilen = 0; + c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; + } + } + + if(ista & ISAC_ISTA_XPR) /* transmit fifo empty (XPR bit set) */ + { + if((sc->sc_obuf2 != NULL) && (sc->sc_obuf == NULL)) + { + sc->sc_freeflag = sc->sc_freeflag2; + sc->sc_obuf = sc->sc_obuf2; + sc->sc_op = sc->sc_obuf->m_data; + sc->sc_ol = sc->sc_obuf->m_len; + sc->sc_obuf2 = NULL; +#ifdef NOTDEF + printf("ob2=%x, op=%x, ol=%d, f=%d #", + sc->sc_obuf, + sc->sc_op, + sc->sc_ol, + sc->sc_state); +#endif + } + else + { +#ifdef NOTDEF + printf("ob=%x, op=%x, ol=%d, f=%d #", + sc->sc_obuf, + sc->sc_op, + sc->sc_ol, + sc->sc_state); +#endif + } + + if(sc->sc_obuf) + { + ISAC_WRFIFO(sc->sc_op, min(sc->sc_ol, ISAC_FIFO_LEN)); + + if(sc->sc_ol > ISAC_FIFO_LEN) /* length > 32 ? */ + { + sc->sc_op += ISAC_FIFO_LEN; /* bufferptr+32 */ + sc->sc_ol -= ISAC_FIFO_LEN; /* length - 32 */ + c |= ISAC_CMDR_XTF; /* set XTF bit */ + } + else + { + if(sc->sc_freeflag) + { + i4b_Dfreembuf(sc->sc_obuf); + sc->sc_freeflag = 0; + } + sc->sc_obuf = NULL; + sc->sc_op = NULL; + sc->sc_ol = 0; + + c |= ISAC_CMDR_XTF | ISAC_CMDR_XME; + } + } + else + { + sc->sc_state &= ~ISAC_TX_ACTIVE; + } + } + + if(ista & ISAC_ISTA_CISQ) /* channel status change CISQ */ + { + register u_char ci; + + /* get command/indication rx register*/ + + ci = ISAC_READ(I_CIRR); + + /* if S/Q IRQ, read SQC reg to clr SQC IRQ */ + + if(ci & ISAC_CIRR_SQC) + (void) ISAC_READ(I_SQRR); + + /* C/I code change IRQ (flag already cleared by CIRR read) */ + + if(ci & ISAC_CIRR_CIC0) + ifpnp_isac_ind_hdlr(sc, (ci >> 2) & 0xf); + } + + if(c) + { + ISAC_WRITE(I_CMDR, c); + ISACCMDRWRDELAY(); + } +} + +/*---------------------------------------------------------------------------* + * ISAC L1 Extended IRQ handler + *---------------------------------------------------------------------------*/ +static u_char +ifpnp_isac_exir_hdlr(register struct l1_softc *sc, u_char exir) +{ + u_char c = 0; + + if(exir & ISAC_EXIR_XMR) + { + NDBGL1(L1_I_ERR, "EXIRQ Tx Message Repeat"); + + c |= ISAC_CMDR_XRES; + } + + if(exir & ISAC_EXIR_XDU) + { + NDBGL1(L1_I_ERR, "EXIRQ Tx Data Underrun"); + + c |= ISAC_CMDR_XRES; + } + + if(exir & ISAC_EXIR_PCE) + { + NDBGL1(L1_I_ERR, "EXIRQ Protocol Error"); + } + + if(exir & ISAC_EXIR_RFO) + { + NDBGL1(L1_I_ERR, "EXIRQ Rx Frame Overflow"); + + c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; + } + + if(exir & ISAC_EXIR_SOV) + { + NDBGL1(L1_I_ERR, "EXIRQ Sync Xfer Overflow"); + } + + if(exir & ISAC_EXIR_MOS) + { + NDBGL1(L1_I_ERR, "EXIRQ Monitor Status"); + } + + if(exir & ISAC_EXIR_SAW) + { + /* cannot happen, STCR:TSF is set to 0 */ + + NDBGL1(L1_I_ERR, "EXIRQ Subscriber Awake"); + } + + if(exir & ISAC_EXIR_WOV) + { + /* cannot happen, STCR:TSF is set to 0 */ + + NDBGL1(L1_I_ERR, "EXIRQ Watchdog Timer Overflow"); + } + + return(c); +} + +/*---------------------------------------------------------------------------* + * ISAC L1 Indication handler + *---------------------------------------------------------------------------*/ +static void +ifpnp_isac_ind_hdlr(register struct l1_softc *sc, int ind) +{ + register int event; + + switch(ind) + { + case ISAC_CIRR_IAI8: + NDBGL1(L1_I_CICO, "rx AI8 in state %s", ifpnp_printstate(sc)); + if(sc->sc_bustyp == BUS_TYPE_IOM2) + ifpnp_isac_l1_cmd(sc, CMD_AR8); + event = EV_INFO48; + i4b_l1_mph_status_ind(L0IFPNPUNIT(sc->sc_unit), STI_L1STAT, LAYER_ACTIVE, NULL); + break; + + case ISAC_CIRR_IAI10: + NDBGL1(L1_I_CICO, "rx AI10 in state %s", ifpnp_printstate(sc)); + if(sc->sc_bustyp == BUS_TYPE_IOM2) + ifpnp_isac_l1_cmd(sc, CMD_AR10); + event = EV_INFO410; + i4b_l1_mph_status_ind(L0IFPNPUNIT(sc->sc_unit), STI_L1STAT, LAYER_ACTIVE, NULL); + break; + + case ISAC_CIRR_IRSY: + NDBGL1(L1_I_CICO, "rx RSY in state %s", ifpnp_printstate(sc)); + event = EV_RSY; + break; + + case ISAC_CIRR_IPU: + NDBGL1(L1_I_CICO, "rx PU in state %s", ifpnp_printstate(sc)); + event = EV_PU; + break; + + case ISAC_CIRR_IDR: + NDBGL1(L1_I_CICO, "rx DR in state %s", ifpnp_printstate(sc)); + ifpnp_isac_l1_cmd(sc, CMD_DIU); + event = EV_DR; + break; + + case ISAC_CIRR_IDID: + NDBGL1(L1_I_CICO, "rx DID in state %s", ifpnp_printstate(sc)); + event = EV_INFO0; + i4b_l1_mph_status_ind(L0IFPNPUNIT(sc->sc_unit), STI_L1STAT, LAYER_IDLE, NULL); + break; + + case ISAC_CIRR_IDIS: + NDBGL1(L1_I_CICO, "rx DIS in state %s", ifpnp_printstate(sc)); + event = EV_DIS; + break; + + case ISAC_CIRR_IEI: + NDBGL1(L1_I_CICO, "rx EI in state %s", ifpnp_printstate(sc)); + ifpnp_isac_l1_cmd(sc, CMD_DIU); + event = EV_EI; + break; + + case ISAC_CIRR_IARD: + NDBGL1(L1_I_CICO, "rx ARD in state %s", ifpnp_printstate(sc)); + event = EV_INFO2; + break; + + case ISAC_CIRR_ITI: + NDBGL1(L1_I_CICO, "rx TI in state %s", ifpnp_printstate(sc)); + event = EV_INFO0; + break; + + case ISAC_CIRR_IATI: + NDBGL1(L1_I_CICO, "rx ATI in state %s", ifpnp_printstate(sc)); + event = EV_INFO0; + break; + + case ISAC_CIRR_ISD: + NDBGL1(L1_I_CICO, "rx SD in state %s", ifpnp_printstate(sc)); + event = EV_INFO0; + break; + + default: + NDBGL1(L1_I_ERR, "UNKNOWN Indication 0x%x in state %s", ind, ifpnp_printstate(sc)); + event = EV_INFO0; + break; + } + ifpnp_next_state(sc, event); +} + +/*---------------------------------------------------------------------------* + * execute a layer 1 command + *---------------------------------------------------------------------------*/ +void +ifpnp_isac_l1_cmd(struct l1_softc *sc, int command) +{ + u_char cmd; + +#ifdef I4B_SMP_WORKAROUND + + /* XXXXXXXXXXXXXXXXXXX */ + + /* + * patch from Wolfgang Helbig: + * + * Here is a patch that makes i4b work on an SMP: + * The card (TELES 16.3) didn't interrupt on an SMP machine. + * This is a gross workaround, but anyway it works *and* provides + * some information as how to finally fix this problem. + */ + + HSCX_WRITE(0, H_MASK, 0xff); + HSCX_WRITE(1, H_MASK, 0xff); + ISAC_WRITE(I_MASK, 0xff); + DELAY(100); + HSCX_WRITE(0, H_MASK, HSCX_A_IMASK); + HSCX_WRITE(1, H_MASK, HSCX_B_IMASK); + ISAC_WRITE(I_MASK, ISAC_IMASK); + + /* XXXXXXXXXXXXXXXXXXX */ + +#endif /* I4B_SMP_WORKAROUND */ + + if(command < 0 || command > CMD_ILL) + { + NDBGL1(L1_I_ERR, "illegal cmd 0x%x in state %s", command, ifpnp_printstate(sc)); + return; + } + + if(sc->sc_bustyp == BUS_TYPE_IOM2) + cmd = ISAC_CIX0_LOW; + else + cmd = 0; + + switch(command) + { + case CMD_TIM: + NDBGL1(L1_I_CICO, "tx TIM in state %s", ifpnp_printstate(sc)); + cmd |= (ISAC_CIXR_CTIM << 2); + break; + + case CMD_RS: + NDBGL1(L1_I_CICO, "tx RS in state %s", ifpnp_printstate(sc)); + cmd |= (ISAC_CIXR_CRS << 2); + break; + + case CMD_AR8: + NDBGL1(L1_I_CICO, "tx AR8 in state %s", ifpnp_printstate(sc)); + cmd |= (ISAC_CIXR_CAR8 << 2); + break; + + case CMD_AR10: + NDBGL1(L1_I_CICO, "tx AR10 in state %s", ifpnp_printstate(sc)); + cmd |= (ISAC_CIXR_CAR10 << 2); + break; + + case CMD_DIU: + NDBGL1(L1_I_CICO, "tx DIU in state %s", ifpnp_printstate(sc)); + cmd |= (ISAC_CIXR_CDIU << 2); + break; + } + ISAC_WRITE(I_CIXR, cmd); +} + +/*---------------------------------------------------------------------------* + * L1 ISAC initialization + *---------------------------------------------------------------------------*/ +int +ifpnp_isac_init(struct l1_softc *sc) +{ + ISAC_IMASK = 0xff; /* disable all irqs */ + + ISAC_WRITE(I_MASK, ISAC_IMASK); + + if(sc->sc_bustyp != BUS_TYPE_IOM2) + { + NDBGL1(L1_I_SETUP, "configuring for IOM-1 mode"); + + /* ADF2: Select mode IOM-1 */ + ISAC_WRITE(I_ADF2, 0x00); + + /* SPCR: serial port control register: + * SPU - software power up = 0 + * SAC - SIP port high Z + * SPM - timing mode 0 + * TLP - test loop = 0 + * C1C, C2C - B1 and B2 switched to/from SPa + */ + ISAC_WRITE(I_SPCR, ISAC_SPCR_C1C1|ISAC_SPCR_C2C1); + + /* SQXR: S/Q channel xmit register: + * SQIE - S/Q IRQ enable = 0 + * SQX1-4 - Fa bits = 1 + */ + ISAC_WRITE(I_SQXR, ISAC_SQXR_SQX1|ISAC_SQXR_SQX2|ISAC_SQXR_SQX3|ISAC_SQXR_SQX4); + + /* ADF1: additional feature reg 1: + * WTC - watchdog = 0 + * TEM - test mode = 0 + * PFS - pre-filter = 0 + * CFS - IOM clock/frame always active + * FSC1/2 - polarity of 8kHz strobe + * ITF - interframe fill = idle + */ + ISAC_WRITE(I_ADF1, ISAC_ADF1_FC2); /* ADF1 */ + + /* STCR: sync transfer control reg: + * TSF - terminal secific functions = 0 + * TBA - TIC bus address = 7 + * STx/SCx = 0 + */ + ISAC_WRITE(I_STCR, ISAC_STCR_TBA2|ISAC_STCR_TBA1|ISAC_STCR_TBA0); + + /* MODE: Mode Register: + * MDSx - transparent mode 2 + * TMD - timer mode = external + * RAC - Receiver enabled + * DIMx - digital i/f mode + */ + ISAC_WRITE(I_MODE, ISAC_MODE_MDS2|ISAC_MODE_MDS1|ISAC_MODE_RAC|ISAC_MODE_DIM0); + } + else + { + NDBGL1(L1_I_SETUP, "configuring for IOM-2 mode"); + + /* ADF2: Select mode IOM-2 */ + ISAC_WRITE(I_ADF2, ISAC_ADF2_IMS); + + /* SPCR: serial port control register: + * SPU - software power up = 0 + * SPM - timing mode 0 + * TLP - test loop = 0 + * C1C, C2C - B1 + C1 and B2 + IC2 monitoring + */ + ISAC_WRITE(I_SPCR, 0x00); + + /* SQXR: S/Q channel xmit register: + * IDC - IOM direction = 0 (master) + * CFS - Config Select = 0 (clock always active) + * CI1E - C/I channel 1 IRQ enable = 0 + * SQIE - S/Q IRQ enable = 0 + * SQX1-4 - Fa bits = 1 + */ + ISAC_WRITE(I_SQXR, ISAC_SQXR_SQX1|ISAC_SQXR_SQX2|ISAC_SQXR_SQX3|ISAC_SQXR_SQX4); + + /* ADF1: additional feature reg 1: + * WTC - watchdog = 0 + * TEM - test mode = 0 + * PFS - pre-filter = 0 + * IOF - IOM i/f off = 0 + * ITF - interframe fill = idle + */ + ISAC_WRITE(I_ADF1, 0x00); + + /* STCR: sync transfer control reg: + * TSF - terminal secific functions = 0 + * TBA - TIC bus address = 7 + * STx/SCx = 0 + */ + ISAC_WRITE(I_STCR, ISAC_STCR_TBA2|ISAC_STCR_TBA1|ISAC_STCR_TBA0); + + /* MODE: Mode Register: + * MDSx - transparent mode 2 + * TMD - timer mode = external + * RAC - Receiver enabled + * DIMx - digital i/f mode + */ + ISAC_WRITE(I_MODE, ISAC_MODE_MDS2|ISAC_MODE_MDS1|ISAC_MODE_RAC|ISAC_MODE_DIM0); + } + +#ifdef NOTDEF + /* + * XXX a transmitter reset causes an ISAC tx IRQ which will not + * be serviced at attach time under some circumstances leaving + * the associated IRQ line on the ISA bus active. This prevents + * any further interrupts to be serviced because no low -> high + * transition can take place anymore. (-hm) + */ + + /* command register: + * RRES - HDLC receiver reset + * XRES - transmitter reset + */ + ISAC_WRITE(I_CMDR, ISAC_CMDR_RRES|ISAC_CMDR_XRES); + ISACCMDRWRDELAY(); +#endif + + /* enabled interrupts: + * =================== + * RME - receive message end + * RPF - receive pool full + * XPR - transmit pool ready + * CISQ - CI or S/Q channel change + * EXI - extended interrupt + */ + + ISAC_IMASK = ISAC_MASK_RSC | /* auto mode only */ + ISAC_MASK_TIN | /* timer irq */ + ISAC_MASK_SIN; /* sync xfer irq */ + + ISAC_WRITE(I_MASK, ISAC_IMASK); + + return(0); +} + +#endif /* NIFPNP > 0 */ diff --git a/sys/i4b/layer1/ifpnp/i4b_ifpnp_l1.c b/sys/i4b/layer1/ifpnp/i4b_ifpnp_l1.c new file mode 100644 index 000000000000..f2b4ad228397 --- /dev/null +++ b/sys/i4b/layer1/ifpnp/i4b_ifpnp_l1.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) 1997, 2000 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_ifpnp_l1.c - AVM Fritz PnP layer 1 handler + * ---------------------------------------------- + * + * $Id: i4b_ifpnp_l1.c,v 1.4 2000/06/02 16:14:36 hm Exp $ + * $Ust: src/i4b/layer1-nb/ifpnp/i4b_ifpnp_l1.c,v 1.4 2000/04/18 08:03:05 ust Exp $ + * + * $FreeBSD$ + * + * last edit-date: [Fri Jun 2 14:55:49 2000] + * + *---------------------------------------------------------------------------*/ + +#include "ifpnp.h" + +#if (NIFPNP > 0) + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> + + +#include <net/if.h> + +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_trace.h> + +#include <i4b/layer1/isic/i4b_isic.h> +#include <i4b/layer1/isic/i4b_isac.h> + +#include <i4b/layer1/ifpnp/i4b_ifpnp_ext.h> + +#include <i4b/layer1/i4b_l1.h> + +#include <i4b/include/i4b_mbuf.h> +#include <i4b/include/i4b_global.h> + +/*---------------------------------------------------------------------------* + * + * L2 -> L1: PH-DATA-REQUEST + * ========================= + * + * parms: + * unit physical interface unit number + * m mbuf containing L2 frame to be sent out + * freeflag MBUF_FREE: free mbuf here after having sent + * it out + * MBUF_DONTFREE: mbuf is freed by Layer 2 + * returns: + * ==0 fail, nothing sent out + * !=0 ok, frame sent out + * + *---------------------------------------------------------------------------*/ +int +ifpnp_ph_data_req(int unit, struct mbuf *m, int freeflag) +{ + u_char cmd; + int s; + struct l1_softc *sc = ifpnp_scp[unit]; + +#ifdef NOTDEF + NDBGL1(L1_PRIM, "PH-DATA-REQ, unit %d, freeflag=%d", unit, freeflag); +#endif + + if(m == NULL) /* failsafe */ + return (0); + + s = SPLI4B(); + + if(sc->sc_I430state == ST_F3) /* layer 1 not running ? */ + { + NDBGL1(L1_I_ERR, "still in state F3!"); + ifpnp_ph_activate_req(unit); + } + + if(sc->sc_state & ISAC_TX_ACTIVE) + { + if(sc->sc_obuf2 == NULL) + { + sc->sc_obuf2 = m; /* save mbuf ptr */ + + if(freeflag) + sc->sc_freeflag2 = 1; /* IRQ must mfree */ + else + sc->sc_freeflag2 = 0; /* IRQ must not mfree */ + + NDBGL1(L1_I_MSG, "using 2nd ISAC TX buffer, state = %s", ifpnp_printstate(sc)); + + if(sc->sc_trace & TRACE_D_TX) + { + i4b_trace_hdr_t hdr; + hdr.unit = L0IFPNPUNIT(unit); + hdr.type = TRC_CH_D; + hdr.dir = FROM_TE; + hdr.count = ++sc->sc_trace_dcount; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, m->m_len, m->m_data); + } + splx(s); + return(1); + } + + NDBGL1(L1_I_ERR, "No Space in TX FIFO, state = %s", ifpnp_printstate(sc)); + + if(freeflag == MBUF_FREE) + i4b_Dfreembuf(m); + + splx(s); + return (0); + } + + if(sc->sc_trace & TRACE_D_TX) + { + i4b_trace_hdr_t hdr; + hdr.unit = L0IFPNPUNIT(unit); + hdr.type = TRC_CH_D; + hdr.dir = FROM_TE; + hdr.count = ++sc->sc_trace_dcount; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, m->m_len, m->m_data); + } + + sc->sc_state |= ISAC_TX_ACTIVE; /* set transmitter busy flag */ + + NDBGL1(L1_I_MSG, "ISAC_TX_ACTIVE set"); + + sc->sc_freeflag = 0; /* IRQ must NOT mfree */ + + ISAC_WRFIFO(m->m_data, min(m->m_len, ISAC_FIFO_LEN)); /* output to TX fifo */ + + if(m->m_len > ISAC_FIFO_LEN) /* message > 32 bytes ? */ + { + sc->sc_obuf = m; /* save mbuf ptr */ + sc->sc_op = m->m_data + ISAC_FIFO_LEN; /* ptr for irq hdl */ + sc->sc_ol = m->m_len - ISAC_FIFO_LEN; /* length for irq hdl */ + + if(freeflag) + sc->sc_freeflag = 1; /* IRQ must mfree */ + + cmd = ISAC_CMDR_XTF; + } + else + { + sc->sc_obuf = NULL; + sc->sc_op = NULL; + sc->sc_ol = 0; + + if(freeflag) + i4b_Dfreembuf(m); + + cmd = ISAC_CMDR_XTF | ISAC_CMDR_XME; + } + + ISAC_WRITE(I_CMDR, cmd); + ISACCMDRWRDELAY(); + + splx(s); + + return(1); +} + +/*---------------------------------------------------------------------------* + * + * L2 -> L1: PH-ACTIVATE-REQUEST + * ============================= + * + * parms: + * unit physical interface unit number + * + * returns: + * ==0 + * !=0 + * + *---------------------------------------------------------------------------*/ +int +ifpnp_ph_activate_req(int unit) +{ + struct l1_softc *sc = ifpnp_scp[unit]; + NDBGL1(L1_PRIM, "PH-ACTIVATE-REQ, unit %d\n", unit); + ifpnp_next_state(sc, EV_PHAR); + return(0); +} + +/*---------------------------------------------------------------------------* + * command from the upper layers + *---------------------------------------------------------------------------*/ +int +ifpnp_mph_command_req(int unit, int command, void *parm) +{ + struct l1_softc *sc = ifpnp_scp[unit]; + + switch(command) + { + case CMR_DOPEN: /* daemon running */ + NDBGL1(L1_PRIM, "unit %d, command = CMR_DOPEN", unit); + sc->sc_enabled = 1; + break; + + case CMR_DCLOSE: /* daemon not running */ + NDBGL1(L1_PRIM, "unit %d, command = CMR_DCLOSE", unit); + sc->sc_enabled = 0; + break; + + case CMR_SETTRACE: + NDBGL1(L1_PRIM, "unit %d, command = CMR_SETTRACE, parm = %d", unit, (unsigned int)parm); + sc->sc_trace = (unsigned int)parm; + break; + + default: + NDBGL1(L1_ERROR, "ERROR, unknown command = %d, unit = %d, parm = %d", command, unit, (unsigned int)parm); + break; + } + + return(0); +} + +#endif /* NIFPNP > 0 */ diff --git a/sys/i4b/layer1/ifpnp/i4b_ifpnp_l1fsm.c b/sys/i4b/layer1/ifpnp/i4b_ifpnp_l1fsm.c new file mode 100644 index 000000000000..26b154031b5e --- /dev/null +++ b/sys/i4b/layer1/ifpnp/i4b_ifpnp_l1fsm.c @@ -0,0 +1,517 @@ +/* + * Copyright (c) 1997, 2000 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_ifpnp_l1fsm.c - AVM Fritz PnP layer 1 I.430 state machine + * ------------------------------------------------------------- + * + * $Id: i4b_ifpnp_l1fsm.c,v 1.4 2000/05/29 15:41:41 hm Exp $ + * $Ust: src/i4b/layer1-nb/ifpnp/i4b_ifpnp_l1fsm.c,v 1.4 2000/04/18 08:03:05 ust Exp $ + * + * $FreeBSD$ + * + * last edit-date: [Mon May 29 15:25:04 2000] + * + *---------------------------------------------------------------------------*/ + +#include "ifpnp.h" + +#if (NIFPNP > 0) + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/socket.h> + + +#include <net/if.h> + +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_trace.h> + +#include <i4b/layer1/isic/i4b_isic.h> + +#include <i4b/layer1/i4b_l1.h> + +#include <i4b/include/i4b_global.h> + +#include <i4b/include/i4b_mbuf.h> + +#include <i4b/layer1/ifpnp/i4b_ifpnp_ext.h> + +#if DO_I4B_DEBUG +static char *state_text[N_STATES] = { + "F3 Deactivated", + "F4 Awaiting Signal", + "F5 Identifying Input", + "F6 Synchronized", + "F7 Activated", + "F8 Lost Framing", + "Illegal State" +}; + +static char *event_text[N_EVENTS] = { + "EV_PHAR PH_ACT_REQ", + "EV_T3 Timer 3 expired", + "EV_INFO0 INFO0 received", + "EV_RSY Level Detected", + "EV_INFO2 INFO2 received", + "EV_INFO48 INFO4 received", + "EV_INFO410 INFO4 received", + "EV_DR Deactivate Req", + "EV_PU Power UP", + "EV_DIS Disconnected", + "EV_EI Error Ind", + "Illegal Event" +}; +#endif + +/* Function prototypes */ + +static void timer3_expired (struct l1_softc *sc); +static void T3_start (struct l1_softc *sc); +static void T3_stop (struct l1_softc *sc); +static void F_T3ex (struct l1_softc *sc); +static void timer4_expired (struct l1_softc *sc); +static void T4_start (struct l1_softc *sc); +static void T4_stop (struct l1_softc *sc); +static void F_AI8 (struct l1_softc *sc); +static void F_AI10 (struct l1_softc *sc); +static void F_I01 (struct l1_softc *sc); +static void F_I02 (struct l1_softc *sc); +static void F_I03 (struct l1_softc *sc); +static void F_I2 (struct l1_softc *sc); +static void F_ill (struct l1_softc *sc); +static void F_NULL (struct l1_softc *sc); + +/*---------------------------------------------------------------------------* + * I.430 Timer T3 expire function + *---------------------------------------------------------------------------*/ +static void +timer3_expired(struct l1_softc *sc) +{ + if(sc->sc_I430T3) + { + NDBGL1(L1_T_ERR, "state = %s", ifpnp_printstate(sc)); + sc->sc_I430T3 = 0; + + /* XXX try some recovery here XXX */ + + ifpnp_recover(sc); + + sc->sc_init_tries++; /* increment retry count */ + +/*XXX*/ if(sc->sc_init_tries > 4) + { + int s = SPLI4B(); + + sc->sc_init_tries = 0; + + if(sc->sc_obuf2 != NULL) + { + i4b_Dfreembuf(sc->sc_obuf2); + sc->sc_obuf2 = NULL; + } + if(sc->sc_obuf != NULL) + { + i4b_Dfreembuf(sc->sc_obuf); + sc->sc_obuf = NULL; + sc->sc_freeflag = 0; + sc->sc_op = NULL; + sc->sc_ol = 0; + } + + splx(s); + + i4b_l1_mph_status_ind(L0IFPNPUNIT(sc->sc_unit), STI_NOL1ACC, 0, NULL); + } + + ifpnp_next_state(sc, EV_T3); + } + else + { + NDBGL1(L1_T_ERR, "expired without starting it ...."); + } +} + +/*---------------------------------------------------------------------------* + * I.430 Timer T3 start + *---------------------------------------------------------------------------*/ +static void +T3_start(struct l1_softc *sc) +{ + NDBGL1(L1_T_MSG, "state = %s", ifpnp_printstate(sc)); + sc->sc_I430T3 = 1; + sc->sc_T3_callout = timeout((TIMEOUT_FUNC_T)timer3_expired,(struct l1_softc *)sc, 2*hz); +} + +/*---------------------------------------------------------------------------* + * I.430 Timer T3 stop + *---------------------------------------------------------------------------*/ +static void +T3_stop(struct l1_softc *sc) +{ + NDBGL1(L1_T_MSG, "state = %s", ifpnp_printstate(sc)); + + sc->sc_init_tries = 0; /* init connect retry count */ + + if(sc->sc_I430T3) + { + sc->sc_I430T3 = 0; + untimeout((TIMEOUT_FUNC_T)timer3_expired,(struct l1_softc *)sc, sc->sc_T3_callout); + } +} + +/*---------------------------------------------------------------------------* + * I.430 Timer T3 expiry + *---------------------------------------------------------------------------*/ +static void +F_T3ex(struct l1_softc *sc) +{ + NDBGL1(L1_F_MSG, "FSM function F_T3ex executing"); + if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) + i4b_l1_ph_deactivate_ind(L0IFPNPUNIT(sc->sc_unit)); +} + +/*---------------------------------------------------------------------------* + * Timer T4 expire function + *---------------------------------------------------------------------------*/ +static void +timer4_expired(struct l1_softc *sc) +{ + if(sc->sc_I430T4) + { + NDBGL1(L1_T_MSG, "state = %s", ifpnp_printstate(sc)); + sc->sc_I430T4 = 0; + i4b_l1_mph_status_ind(L0IFPNPUNIT(sc->sc_unit), STI_PDEACT, 0, NULL); + } + else + { + NDBGL1(L1_T_ERR, "expired without starting it ...."); + } +} + +/*---------------------------------------------------------------------------* + * Timer T4 start + *---------------------------------------------------------------------------*/ +static void +T4_start(struct l1_softc *sc) +{ + NDBGL1(L1_T_MSG, "state = %s", ifpnp_printstate(sc)); + sc->sc_I430T4 = 1; + sc->sc_T4_callout = timeout((TIMEOUT_FUNC_T)timer4_expired,(struct l1_softc *)sc, hz); +} + +/*---------------------------------------------------------------------------* + * Timer T4 stop + *---------------------------------------------------------------------------*/ +static void +T4_stop(struct l1_softc *sc) +{ + NDBGL1(L1_T_MSG, "state = %s", ifpnp_printstate(sc)); + + if(sc->sc_I430T4) + { + sc->sc_I430T4 = 0; + untimeout((TIMEOUT_FUNC_T)timer4_expired,(struct l1_softc *)sc, sc->sc_T4_callout); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: received AI8 + *---------------------------------------------------------------------------*/ +static void +F_AI8(struct l1_softc *sc) +{ + T4_stop(sc); + + NDBGL1(L1_F_MSG, "FSM function F_AI8 executing"); + + if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) + i4b_l1_ph_activate_ind(L0IFPNPUNIT(sc->sc_unit)); + + T3_stop(sc); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO4_8; + + hdr.unit = L0IFPNPUNIT(sc->sc_unit); + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, 1, &info); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: received AI10 + *---------------------------------------------------------------------------*/ +static void +F_AI10(struct l1_softc *sc) +{ + T4_stop(sc); + + NDBGL1(L1_F_MSG, "FSM function F_AI10 executing"); + + if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) + i4b_l1_ph_activate_ind(L0IFPNPUNIT(sc->sc_unit)); + + T3_stop(sc); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO4_10; + + hdr.unit = L0IFPNPUNIT(sc->sc_unit); + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, 1, &info); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: received INFO 0 in states F3 .. F5 + *---------------------------------------------------------------------------*/ +static void +F_I01(struct l1_softc *sc) +{ + NDBGL1(L1_F_MSG, "FSM function F_I01 executing"); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO0; + + hdr.unit = L0IFPNPUNIT(sc->sc_unit); + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, 1, &info); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: received INFO 0 in state F6 + *---------------------------------------------------------------------------*/ +static void +F_I02(struct l1_softc *sc) +{ + NDBGL1(L1_F_MSG, "FSM function F_I02 executing"); + + if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) + i4b_l1_ph_deactivate_ind(L0IFPNPUNIT(sc->sc_unit)); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO0; + + hdr.unit = L0IFPNPUNIT(sc->sc_unit); + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, 1, &info); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: received INFO 0 in state F7 or F8 + *---------------------------------------------------------------------------*/ +static void +F_I03(struct l1_softc *sc) +{ + NDBGL1(L1_F_MSG, "FSM function F_I03 executing"); + + if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) + i4b_l1_ph_deactivate_ind(L0IFPNPUNIT(sc->sc_unit)); + + T4_start(sc); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO0; + + hdr.unit = L0IFPNPUNIT(sc->sc_unit); + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, 1, &info); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: activate request + *---------------------------------------------------------------------------*/ +static void +F_AR(struct l1_softc *sc) +{ + NDBGL1(L1_F_MSG, "FSM function F_AR executing"); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO1_8; + + hdr.unit = L0IFPNPUNIT(sc->sc_unit); + hdr.type = TRC_CH_I; + hdr.dir = FROM_TE; + hdr.count = 0; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, 1, &info); + } + + ifpnp_isac_l1_cmd(sc, CMD_AR8); + + T3_start(sc); +} + +/*---------------------------------------------------------------------------* + * FSM function: received INFO2 + *---------------------------------------------------------------------------*/ +static void +F_I2(struct l1_softc *sc) +{ + NDBGL1(L1_F_MSG, "FSM function F_I2 executing"); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO2; + + hdr.unit = L0IFPNPUNIT(sc->sc_unit); + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, 1, &info); + } + +} + +/*---------------------------------------------------------------------------* + * illegal state default action + *---------------------------------------------------------------------------*/ +static void +F_ill(struct l1_softc *sc) +{ + NDBGL1(L1_F_ERR, "FSM function F_ill executing"); +} + +/*---------------------------------------------------------------------------* + * No action + *---------------------------------------------------------------------------*/ +static void +F_NULL(struct l1_softc *sc) +{ + NDBGL1(L1_F_MSG, "FSM function F_NULL executing"); +} + + +/*---------------------------------------------------------------------------* + * layer 1 state transition table + *---------------------------------------------------------------------------*/ +struct ifpnp_state_tab { + void (*func) (struct l1_softc *sc); /* function to execute */ + int newstate; /* next state */ +} ifpnp_state_tab[N_EVENTS][N_STATES] = { + +/* STATE: F3 F4 F5 F6 F7 F8 ILLEGAL STATE */ +/* -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +/* EV_PHAR x*/ {{F_AR, ST_F4}, {F_NULL, ST_F4}, {F_NULL, ST_F5}, {F_NULL, ST_F6}, {F_ill, ST_ILL}, {F_NULL, ST_F8}, {F_ill, ST_ILL}}, +/* EV_T3 x*/ {{F_NULL, ST_F3}, {F_T3ex, ST_F3}, {F_T3ex, ST_F3}, {F_T3ex, ST_F3}, {F_NULL, ST_F7}, {F_NULL, ST_F8}, {F_ill, ST_ILL}}, +/* EV_INFO0 */ {{F_I01, ST_F3}, {F_I01, ST_F4}, {F_I01, ST_F5}, {F_I02, ST_F3}, {F_I03, ST_F3}, {F_I03, ST_F3}, {F_ill, ST_ILL}}, +/* EV_RSY x*/ {{F_NULL, ST_F3}, {F_NULL, ST_F5}, {F_NULL, ST_F5}, {F_NULL, ST_F8}, {F_NULL, ST_F8}, {F_NULL, ST_F8}, {F_ill, ST_ILL}}, +/* EV_INFO2 */ {{F_I2, ST_F6}, {F_I2, ST_F6}, {F_I2, ST_F6}, {F_I2, ST_F6}, {F_I2, ST_F6}, {F_I2, ST_F6}, {F_ill, ST_ILL}}, +/* EV_INFO48*/ {{F_AI8, ST_F7}, {F_AI8, ST_F7}, {F_AI8, ST_F7}, {F_AI8, ST_F7}, {F_NULL, ST_F7}, {F_AI8, ST_F7}, {F_ill, ST_ILL}}, +/* EV_INFO41*/ {{F_AI10, ST_F7}, {F_AI10, ST_F7}, {F_AI10, ST_F7}, {F_AI10, ST_F7}, {F_NULL, ST_F7}, {F_AI10, ST_F7}, {F_ill, ST_ILL}}, +/* EV_DR */ {{F_NULL, ST_F3}, {F_NULL, ST_F4}, {F_NULL, ST_F5}, {F_NULL, ST_F6}, {F_NULL, ST_F7}, {F_NULL, ST_F8}, {F_ill, ST_ILL}}, +/* EV_PU */ {{F_NULL, ST_F3}, {F_NULL, ST_F4}, {F_NULL, ST_F5}, {F_NULL, ST_F6}, {F_NULL, ST_F7}, {F_NULL, ST_F8}, {F_ill, ST_ILL}}, +/* EV_DIS */ {{F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}}, +/* EV_EI */ {{F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_ill, ST_ILL}}, +/* EV_ILL */ {{F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}} +}; + +/*---------------------------------------------------------------------------* + * event handler + *---------------------------------------------------------------------------*/ +void +ifpnp_next_state(struct l1_softc *sc, int event) +{ + int currstate, newstate; + + if(event >= N_EVENTS) + panic("i4b_l1fsm.c: event >= N_EVENTS\n"); + + currstate = sc->sc_I430state; + + if(currstate >= N_STATES) + panic("i4b_l1fsm.c: currstate >= N_STATES\n"); + + newstate = ifpnp_state_tab[event][currstate].newstate; + + if(newstate >= N_STATES) + panic("i4b_l1fsm.c: newstate >= N_STATES\n"); + + NDBGL1(L1_F_MSG, "FSM event [%s]: [%s => %s]", event_text[event], + state_text[currstate], + state_text[newstate]); + + (*ifpnp_state_tab[event][currstate].func)(sc); + + if(newstate == ST_ILL) + { + newstate = ST_F3; + NDBGL1(L1_F_ERR, "FSM Illegal State ERROR, oldstate = %s, newstate = %s, event = %s!", + state_text[currstate], + state_text[newstate], + event_text[event]); + } + + sc->sc_I430state = newstate; +} + +#if DO_I4B_DEBUG +/*---------------------------------------------------------------------------* + * return pointer to current state description + *---------------------------------------------------------------------------*/ +char * +ifpnp_printstate(struct l1_softc *sc) +{ + return((char *) state_text[sc->sc_I430state]); +} +#endif + +#endif /* NIFPNP > 0 */ diff --git a/sys/net/if_ieee80211.h b/sys/net/if_ieee80211.h new file mode 100644 index 000000000000..d4364c77d2c8 --- /dev/null +++ b/sys/net/if_ieee80211.h @@ -0,0 +1,171 @@ +/* $NetBSD: if_ieee80211.h,v 1.5 2000/07/21 04:47:40 onoe Exp $ */ +/* $FreeBSD$ */ + +#ifndef _NET_IF_IEEE80211_H_ +#define _NET_IF_IEEE80211_H_ + +/* + * generic definitions for IEEE 802.11 frames + */ +struct ieee80211_frame { + u_int8_t i_fc[2]; + u_int8_t i_dur[2]; + u_int8_t i_addr1[ETHER_ADDR_LEN]; + u_int8_t i_addr2[ETHER_ADDR_LEN]; + u_int8_t i_addr3[ETHER_ADDR_LEN]; + u_int8_t i_seq[2]; + /* possibly followed by addr4[ETHER_ADDR_LEN]; */ +}; + +#define IEEE80211_FC0_VERSION_MASK 0x03 +#define IEEE80211_FC0_VERSION_0 0x00 +#define IEEE80211_FC0_TYPE_MASK 0x0c +#define IEEE80211_FC0_TYPE_MGT 0x00 +#define IEEE80211_FC0_TYPE_CTL 0x04 +#define IEEE80211_FC0_TYPE_DATA 0x08 + +#define IEEE80211_FC0_SUBTYPE_MASK 0xf0 +/* for TYPE_MGT */ +#define IEEE80211_FC0_SUBTYPE_ASSOC_REQ 0x00 +#define IEEE80211_FC0_SUBTYPE_ASSOC_RESP 0x10 +#define IEEE80211_FC0_SUBTYPE_REASSOC_REQ 0x20 +#define IEEE80211_FC0_SUBTYPE_REASSOC_RESP 0x30 +#define IEEE80211_FC0_SUBTYPE_PROBE_REQ 0x40 +#define IEEE80211_FC0_SUBTYPE_PROBE_RESP 0x50 +#define IEEE80211_FC0_SUBTYPE_BEACON 0x80 +#define IEEE80211_FC0_SUBTYPE_ATIM 0x90 +#define IEEE80211_FC0_SUBTYPE_DISASSOC 0xa0 +#define IEEE80211_FC0_SUBTYPE_AUTH 0xb0 +#define IEEE80211_FC0_SUBTYPE_DEAUTH 0xc0 +/* for TYPE_CTL */ +#define IEEE80211_FC0_SUBTYPE_PS_POLL 0xa0 +#define IEEE80211_FC0_SUBTYPE_RTS 0xb0 +#define IEEE80211_FC0_SUBTYPE_CTS 0xc0 +#define IEEE80211_FC0_SUBTYPE_ACK 0xd0 +#define IEEE80211_FC0_SUBTYPE_CF_END 0xe0 +#define IEEE80211_FC0_SUBTYPE_CF_END_ACK 0xf0 +/* for TYPE_DATA (bit combination) */ +#define IEEE80211_FC0_SUBTYPE_DATA 0x00 +#define IEEE80211_FC0_SUBTYPE_CF_ACK 0x10 +#define IEEE80211_FC0_SUBTYPE_CF_POLL 0x20 +#define IEEE80211_FC0_SUBTYPE_CF_ACPL 0x30 +#define IEEE80211_FC0_SUBTYPE_NODATA 0x40 +#define IEEE80211_FC0_SUBTYPE_CFACK 0x50 +#define IEEE80211_FC0_SUBTYPE_CFPOLL 0x60 +#define IEEE80211_FC0_SUBTYPE_CF_ACK_CF_ACK 0x70 + +#define IEEE80211_FC1_DIR_MASK 0x03 +#define IEEE80211_FC1_DIR_NODS 0x00 /* STA->STA */ +#define IEEE80211_FC1_DIR_TODS 0x01 /* STA->AP */ +#define IEEE80211_FC1_DIR_FROMDS 0x02 /* AP ->STA */ +#define IEEE80211_FC1_DIR_DSTODS 0x03 /* AP ->AP */ + +#define IEEE80211_FC1_MORE_FRAG 0x04 +#define IEEE80211_FC1_RETRY 0x08 +#define IEEE80211_FC1_PWR_MGT 0x10 +#define IEEE80211_FC1_MORE_DATA 0x20 +#define IEEE80211_FC1_WEP 0x40 +#define IEEE80211_FC1_ORDER 0x80 + +/* + * Management Frames + */ + +#define IEEE80211_ELEMID_SSID 0 +#define IEEE80211_ELEMID_RATES 1 +#define IEEE80211_ELEMID_FHPARMS 2 +#define IEEE80211_ELEMID_DSPARMS 3 +#define IEEE80211_ELEMID_CFPARMS 4 +#define IEEE80211_ELEMID_TIM 5 +#define IEEE80211_ELEMID_IBSSPARMS 6 +#define IEEE80211_ELEMID_CHALLENGE 16 + +/* + * AUTH management packets + * + * octect algo[2] + * octect seq[2] + * octect status[2] + * octect chal.id + * octect chal.length + * octect chal.text[253] + */ +typedef u_int8_t * ieee80211_mgt_auth_t; + +#define IEEE80211_AUTH_ALGORITHM(auth) \ + (auth[0] + (auth[1] << 8)) +#define IEEE80211_AUTH_TRANSACTION(auth) \ + (auth[2] + (auth[3] << 8)) +#define IEEE80211_AUTH_STATUS(auth) \ + (auth[4] + (auth[5] << 8)) + +#define IEEE80211_AUTH_ALG_OPEN 0x0000 +#define IEEE80211_AUTH_ALG_SHARED 0x0001 + +#define IEEE80211_CAPINFO_ESS 0x01 +#define IEEE80211_CAPINFO_IBSS 0x02 +#define IEEE80211_CAPINFO_CF_POLLABLE 0x04 +#define IEEE80211_CAPINFO_CF_POLLREQ 0x08 +#define IEEE80211_CAPINFO_PRIVACY 0x10 + +/* + * Reason codes + * + * Unlisted codes are reserved + */ +#define IEEE80211_REASON_UNSPECIFIED 1 +#define IEEE80211_REASON_AUTH_EXPIRE 2 +#define IEEE80211_REASON_AUTH_LEAVE 3 +#define IEEE80211_REASON_ASSOC_EXPIRE 4 +#define IEEE80211_REASON_ASSOC_TOOMANY 5 +#define IEEE80211_REASON_NOT_AUTHED 6 +#define IEEE80211_REASON_NOT_ASSOCED 7 +#define IEEE80211_REASON_ASSOC_LEAVE 8 +#define IEEE80211_REASON_ASSOC_NOT_AUTHED 9 + +/* + * Status code + * + * Unlisted codes are reserved + */ +#define IEEE80211_STATUS_SUCCESS 0x0000 +#define IEEE80211_STATUS_UNSPECIFIED 1 +#define IEEE80211_STATUS_CAPINFO 10 +#define IEEE80211_STATUS_NOT_ASSOCED 11 +#define IEEE80211_STATUS_OTHER 12 +#define IEEE80211_STATUS_ALG 13 +#define IEEE80211_STATUS_SEQUENCE 14 +#define IEEE80211_STATUS_CHALLENGE 15 +#define IEEE80211_STATUS_TIMEOUT 16 + +#define IEEE80211_WEP_KEYLEN 5 /* 40bit */ +#define IEEE80211_WEP_IVLEN 3 /* 24bit */ +#define IEEE80211_WEP_KIDLEN 1 /* 1 octet */ +#define IEEE80211_WEP_CRCLEN 4 /* CRC-32 */ +#define IEEE80211_WEP_NKID 4 /* number of key ids */ + +#define IEEE80211_NWID_LEN 32 + +/* nwid is pointed at by ifr.ifr_data */ +struct ieee80211_nwid { + u_int8_t i_len; + u_int8_t i_nwid[IEEE80211_NWID_LEN]; +}; + +#define SIOCS80211NWID _IOWR('i', 230, struct ifreq) +#define SIOCG80211NWID _IOWR('i', 231, struct ifreq) + +/* the first member must be matched with struct ifreq */ +struct ieee80211_nwkey { + char i_name[IFNAMSIZ]; /* if_name, e.g. "wi0" */ + int i_wepon; /* wep enabled flag */ + int i_defkid; /* default encrypt key id */ + struct { + int i_keylen; + u_int8_t *i_keydat; + } i_key[IEEE80211_WEP_NKID]; +}; +#define SIOCS80211NWKEY _IOW('i', 232, struct ieee80211_nwkey) +#define SIOCG80211NWKEY _IOWR('i', 233, struct ieee80211_nwkey) + +#endif /* !_NET_IF_IEEE80211_H_ */ |
