From aad8058264cfbb51ec169e8ecd7f04209b706634 Mon Sep 17 00:00:00 2001 From: David Leonard Date: Fri, 30 Jul 1999 13:43:38 +0000 Subject: rename rl2->rln for sanity --- sys/dev/ic/rl2.c | 1155 --------------------------------------- sys/dev/ic/rl2.h | 39 -- sys/dev/ic/rl2cmd.h | 247 --------- sys/dev/ic/rl2reg.h | 250 --------- sys/dev/ic/rl2subr.c | 931 -------------------------------- sys/dev/ic/rl2var.h | 141 ----- sys/dev/ic/rln.c | 1163 ++++++++++++++++++++++++++++++++++++++++ sys/dev/ic/rln.h | 39 ++ sys/dev/ic/rlncmd.h | 247 +++++++++ sys/dev/ic/rlnreg.h | 250 +++++++++ sys/dev/ic/rlnsubr.c | 934 ++++++++++++++++++++++++++++++++ sys/dev/ic/rlnvar.h | 141 +++++ sys/dev/pcmcia/files.pcmcia | 4 +- sys/dev/pcmcia/if_rl2_pcmcia.c | 300 ----------- sys/dev/pcmcia/if_rln_pcmcia.c | 300 +++++++++++ 15 files changed, 3076 insertions(+), 3065 deletions(-) delete mode 100644 sys/dev/ic/rl2.c delete mode 100644 sys/dev/ic/rl2.h delete mode 100644 sys/dev/ic/rl2cmd.h delete mode 100644 sys/dev/ic/rl2reg.h delete mode 100644 sys/dev/ic/rl2subr.c delete mode 100644 sys/dev/ic/rl2var.h create mode 100644 sys/dev/ic/rln.c create mode 100644 sys/dev/ic/rln.h create mode 100644 sys/dev/ic/rlncmd.h create mode 100644 sys/dev/ic/rlnreg.h create mode 100644 sys/dev/ic/rlnsubr.c create mode 100644 sys/dev/ic/rlnvar.h delete mode 100644 sys/dev/pcmcia/if_rl2_pcmcia.c create mode 100644 sys/dev/pcmcia/if_rln_pcmcia.c (limited to 'sys/dev') diff --git a/sys/dev/ic/rl2.c b/sys/dev/ic/rl2.c deleted file mode 100644 index f8fbaafcc95..00000000000 --- a/sys/dev/ic/rl2.c +++ /dev/null @@ -1,1155 +0,0 @@ -/* $OpenBSD: rl2.c,v 1.3 1999/07/14 03:51:08 d Exp $ */ -/* - * David Leonard , 1999. Public Domain. - * - * Driver for the Proxim RangeLAN2 wireless network adaptor. - * - * Information and ideas gleaned from disassembly of Dave Koberstein's - * Linux driver (apparently based on Proxim source), - * from Yoichi Shinoda's BSDI driver, and - * Geoff Voelker's Linux port of the same. - * - */ - -#include "bpfilter.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef INET -#include -#include -#endif - -#if NBPFILTER > 0 -#include -#include -#endif - -#include -#include - -#include -#include -#include -#include - -/* Autoconfig definition of driver back-end. */ -struct cfdriver rln_cd = { - NULL, "rln", DV_IFNET -}; - -static void rl2init __P((struct rl2_softc *)); -static void rl2start __P((struct ifnet*)); -static void rl2watchdog __P((struct ifnet*)); -static int rl2ioctl __P((struct ifnet *, u_long, caddr_t)); -static int rl2_probe __P((struct rl2_softc *)); -static void rl2stop __P((struct rl2_softc *)); - -/* Interrupt handler. */ -static void rl2softintr __P((void *)); - -/* Packet I/O. */ -static int rl2_transmit __P((struct rl2_softc *, struct mbuf *, - int, int)); -static struct mbuf * rl2get __P((struct rl2_softc *, struct rl2_mm_cmd *, - int)); - -/* Card protocol-level functions. */ -static int rl2_getenaddr __P((struct rl2_softc *, u_int8_t *)); -static int rl2_getpromvers __P((struct rl2_softc *, char *, int)); -static int rl2_sendinit __P((struct rl2_softc *)); -#if notyet -static int rl2_roamconfig __P((struct rl2_softc *)); -static int rl2_roam __P((struct rl2_softc *)); -static int rl2_multicast __P((struct rl2_softc *, int)); -static int rl2_searchsync __P((struct rl2_softc *)); -static int rl2_iosetparam __P((struct rl2_softc *, struct rl2_param *)); -static int rl2_lockprom __P((struct rl2_softc *)); -static int rl2_ito __P((struct rl2_softc *)); -static int rl2_standby __P((struct rl2_softc *)); -#endif - -/* Back-end attach and configure. */ -void -rl2config(sc) - struct rl2_softc * sc; -{ - struct ifnet * ifp = &sc->sc_arpcom.ac_if; - char promvers[7]; - int i; - - dprintf(" [attach %p]", sc); - - /* Use the flags supplied from config. */ - sc->sc_cardtype |= sc->sc_dev.dv_cfdata->cf_flags; - - /* Initialise values in the soft state. */ - sc->sc_pktseq = 0; /* rl2_newseq() */ - sc->sc_txseq = 0; - - /* Initialise user-configurable params. */ - sc->sc_param.rp_roam_config = RL2_ROAM_NORMAL; - sc->sc_param.rp_security = RL2_SECURITY_DEFAULT; - sc->sc_param.rp_station_type = RL2_STATIONTYPE_ALTMASTER; - sc->sc_param.rp_domain = 0; - sc->sc_param.rp_channel = 1; - sc->sc_param.rp_subchannel = 1; - - bzero(sc->sc_param.rp_master, sizeof sc->sc_param.rp_master); - - /* Initialise the message mailboxes. */ - for (i = 0; i < RL2_NMBOX; i++) - sc->sc_mbox[i].mb_state = RL2MBOX_VOID; - - /* Keep the sys admin informed. */ - printf(", %s-piece", - (sc->sc_cardtype & RL2_CTYPE_ONE_PIECE) ? "one" : "two"); - if (sc->sc_cardtype & RL2_CTYPE_OEM) - printf(" oem"); - if (sc->sc_cardtype & RL2_CTYPE_UISA) - printf(" micro-isa"); - - /* Probe/reset the card. */ - if (rl2_probe(sc)) - return; - - /* Read the card's PROM revision. */ - if (rl2_getpromvers(sc, promvers, sizeof promvers)) { - printf(": could not read PROM version\n"); - return; - } - printf(", fw %.7s", promvers); - - /* Fetch the card's MAC address. */ - if (rl2_getenaddr(sc, sc->sc_arpcom.ac_enaddr)) { - printf(": could not read MAC address\n"); - return; - } - printf(", addr %s", ether_sprintf(sc->sc_arpcom.ac_enaddr)); - - /* Attach as a network interface. */ - bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); - ifp->if_softc = sc; - ifp->if_start = rl2start; - ifp->if_ioctl = rl2ioctl; - ifp->if_watchdog = rl2watchdog; - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS; - if_attach(ifp); - ether_ifattach(ifp); -#if NBPFILTER > 0 - bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof (struct ether_header)); -#endif -} - -/* Bring device up. */ -static void -rl2init(sc) - struct rl2_softc * sc; -{ - /* LLDInit() */ - struct ifnet * ifp = &sc->sc_arpcom.ac_if; - int s; - extern int cold; - - dprintf(" [init]"); - - sc->sc_intsel = 0; - sc->sc_status = 0; - sc->sc_control = 0; - ifp->if_flags &= ~IFF_RUNNING; - ifp->if_flags &= ~IFF_OACTIVE; - - /* Do a hard reset. */ - if (rl2_reset(sc)) { - printf("%s: could not reset card\n", sc->sc_dev.dv_xname); - goto fail; - } - sc->sc_state = 0; /* Also clears RL2_STATE_NEEDINIT. */ - - /* Use this host's name as a master name. */ - if (!cold && sc->sc_param.rp_master[0] == '\0') { - bcopy(hostname, sc->sc_param.rp_master, - min(hostnamelen, sizeof sc->sc_param.rp_master)); - } - - rl2_enable(sc, 1); - - /* Initialise operational params. */ - if (rl2_sendinit(sc)) { - printf("%s: could not set card parameters\n", - sc->sc_dev.dv_xname); - goto fail; - } -#if 0 - rl2_roamconfig(sc); - /* rl2_lockprom(sc); */ /* XXX error? */ - - /* SendSetITO() */ - - rl2_multicast(sc, 1); - rl2_roam(sc); - - /* Synchronise with something. */ - rl2_searchsync(sc); -#endif - s = splnet(); - ifp->if_flags |= IFF_RUNNING; - rl2start(ifp); - splx(s); - - return; - - fail: - ifp->if_flags &= ~IFF_UP; - return; -} - -/* Start outputting on interface. This is always called at splnet(). */ -static void -rl2start(ifp) - struct ifnet * ifp; -{ - struct rl2_softc * sc = (struct rl2_softc *)ifp->if_softc; - struct mbuf * m0; - int len, pad, ret; - - dprintf(" start["); - - if (sc->sc_state & RL2_STATE_NEEDINIT) - rl2init(sc); - - /* Don't transmit if interface is busy or not running. */ - if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) { - dprintf(" %s] ", (ifp->if_flags & IFF_OACTIVE) ? - "busy" : "stopped"); - return; - } - - /* Don't transmit if we are not synchronised. */ - if ((sc->sc_state & RL2_STATE_SYNC) == 0) { - dprintf(" nosync]"); - return; - } - - startagain: - IF_DEQUEUE(&ifp->if_snd, m0); - - if (m0 == NULL) { - dprintf(" empty]"); - return; - } - -#if NBPFILTER > 0 - /* Tap packet stream here for BPF listeners. */ - if (ifp->if_bpf) - bpf_mtap(ifp->if_bpf, m0); -#endif - - /* We need to use m->m_pkthdr.len, so require the header. */ - if ((m0->m_flags & M_PKTHDR) == 0) { - printf("%s: no mbuf header\n", sc->sc_dev.dv_xname); - goto oerror; - } - - len = m0->m_pkthdr.len; - -#define PACKETMIN (sizeof (struct ether_header) + ETHERMIN) -#define PACKETMAX (sizeof (struct ether_header) + ETHERMTU + 4) - - /* Packet size has to be an even number between 60 and 1518 octets. */ - pad = len & 1; - if (len + pad < PACKETMIN) - pad = PACKETMIN - len; - - if (len + pad > PACKETMAX) { - printf("%s: packet too big (%d > %d)\n", - sc->sc_dev.dv_xname, len + pad, - PACKETMAX); - ++ifp->if_oerrors; - m_freem(m0); - goto startagain; - } - - ret = rl2_transmit(sc, m0, len, pad); - if (ret) - goto oerror; - - ifp->if_flags |= IFF_OACTIVE; - m_freem(m0); - - dprintf(" sent]"); - return; - -oerror: - ++ifp->if_oerrors; - m_freem(m0); - rl2_need_reset(sc); - return; -} - -/* Transmit one packet. */ -static int -rl2_transmit(sc, m0, len, pad) - struct rl2_softc * sc; - struct mbuf * m0; - int len; - int pad; -{ - struct mbuf * m; - int zfirst; - int actlen; - int tlen = len + pad; - struct rl2_msg_tx_state state; - static u_int8_t zeroes[60]; - struct rl2_mm_sendpacket cmd = { RL2_MM_SENDPACKET }; - - /* Does the packet start with a zero bit? */ - zfirst = ((*mtod(m0, u_int8_t *) & 1) == 0); - - cmd.mode = - RL2_MM_SENDPACKET_MODE_BIT7 | - (zfirst ? RL2_MM_SENDPACKET_MODE_ZFIRST : 0) | - (0 ? RL2_MM_SENDPACKET_MODE_QFSK : 0), /* sc->qfsk? */ - cmd.power = 0x70; /* 0x70 or 0xf0 */ - cmd.length_lo = htons(4 + tlen) & 0xff; - cmd.length_hi = (htons(4 + tlen) >> 8) & 0xff; - cmd.xxx1 = 0; - cmd.xxx2 = 0; - cmd.xxx3 = 0; - - /* A unique packet-level sequence number. XXX related to sc_seq? */ - cmd.sequence = sc->sc_txseq; - sc->sc_txseq++; - if (sc->sc_txseq > RL2_MAXSEQ) - sc->sc_txseq = 0; - - dprintf(" T[%d+%d", len, pad); - - if (rl2_msg_tx_start(sc, &cmd, sizeof cmd + tlen, &state)) - goto error; - - cmd.mm_cmd.cmd_seq = rl2_newseq(sc); - -#ifdef RL2DUMP - printf("%s: send %c%d seq %d data ", sc->sc_dev.dv_xname, - cmd.mm_cmd.cmd_letter, cmd.mm_cmd.cmd_fn, cmd.mm_cmd.cmd_seq); - RL2DUMPHEX(&cmd, sizeof cmd); - printf(":"); -#endif - rl2_msg_tx_data(sc, &cmd, sizeof cmd, &state); - - actlen = 0; - for (m = m0; m; m = m->m_next) { - if (m->m_len) { -#ifdef RL2DUMP - RL2DUMPHEX(mtod(m, void *), m->m_len); - printf("|"); -#endif - rl2_msg_tx_data(sc, mtod(m, void *), m->m_len, &state); - } - actlen += m->m_len; - } -#ifdef DIAGNOSTIC - if (actlen != len) - panic("rl2_transmit: len %d != %d", actlen, len); - if (pad > sizeof zeroes) - panic("rl2_transmit: pad %d > %d", pad, sizeof zeroes); -#endif - if (pad) { -#ifdef RL2DUMP - RL2DUMPHEX(zeroes, pad); -#endif - rl2_msg_tx_data(sc, zeroes, pad, &state); - } - -#ifdef RL2DUMP - printf("\n"); -#endif - if (rl2_msg_tx_end(sc, &state)) - goto error; - return (0); - - error: - dprintf(" error]"); - return (-1); -} - -/* (Supposedly) called when interrupts are suspiciously absent. */ -static void -rl2watchdog(ifp) - struct ifnet * ifp; -{ - struct rl2_softc * sc = (struct rl2_softc *)ifp->if_softc; - - log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname); - ++sc->sc_arpcom.ac_if.if_oerrors; - rl2init(sc); - rl2_enable(sc, 1); -} - -/* Handle single card interrupt. */ -int -rl2intr(arg) - void * arg; -{ - struct rl2_softc * sc = (struct rl2_softc *)arg; - extern int cold; - - dprintf("!"); - - /* Tell card not to interrupt any more. */ - rl2_enable(sc, 0); - - if (cold) - /* During autoconfig - must handle interrupts now. */ - rl2softintr(sc); - else - /* Handle later. */ - timeout(rl2softintr, sc, 1); - - return (1); -} - -/* Process earlier card interrupt at splnetintr. */ -static void -rl2softintr(arg) - void * arg; -{ - struct rl2_softc *sc = (struct rl2_softc *)arg; - struct ifnet *ifp = &sc->sc_arpcom.ac_if; - int len; - u_int8_t w; - struct rl2_mm_cmd hdr; - - dprintf(" si("); - - again: - /* Save wakeup state. */ - w = rl2_wakeup(sc, RL2_WAKEUP_SET); - - if ((len = rl2_rx_request(sc, 300)) < 0) { - /* Error in transfer. */ - rl2_need_reset(sc); - rl2_rx_end(sc); - } else if (len < sizeof hdr) { - /* Short message. */ - rl2_rx_end(sc); - printf("%s: short msg (%d)\n", sc->sc_dev.dv_xname, len); - ifp->if_ierrors++; - } else { - /* Valid message: read header and process. */ - rl2_rx_data(sc, &hdr, sizeof hdr); - rl2read(sc, &hdr, len); - } - - /* Ensure that wakeup state is unchanged if transmitting. */ - if (ifp->if_flags & IFF_OACTIVE) - w |= RL2_WAKEUP_NOCHANGE; - rl2_wakeup(sc, w); - - /* Check for more interrupts. */ - if (rl2_status_rx_ready(sc)) { -#ifdef DIAGNOSTIC - printf("%s: intr piggyback\n", sc->sc_dev.dv_xname); -#endif - goto again; - } - - /* Some cards need this? */ - rl2_eoi(sc); - - /* Re-enable card. */ - rl2_enable(sc, 1); - - dprintf(")"); -} - -/* Read and process a message from the card. */ -void -rl2read(sc, hdr, len) - struct rl2_softc *sc; - struct rl2_mm_cmd *hdr; - int len; -{ - struct ifnet *ifp = &sc->sc_arpcom.ac_if; - struct mbuf *m; - struct ether_header *eh; - u_int8_t data[1538]; - u_int8_t *buf; - size_t buflen; - struct rl2_pdata pd = RL2_PDATA_INIT; - struct rl2_mm_synchronised * syncp = (struct rl2_mm_synchronised *)data; - int s; - - dprintf(" [read]"); - - /* Were we waiting for this message? */ - if (rl2_mbox_lock(sc, hdr->cmd_seq, (void **)&buf, &buflen) == 0) { -#ifdef DIAGNOSTIC - if (buflen < sizeof *hdr) - panic("rl2read buflen"); -#endif - bcopy(hdr, buf, sizeof *hdr); - buf += sizeof *hdr; - len -= sizeof *hdr; - buflen -= sizeof *hdr; - if (len) { - if (len == buflen) /* Expected size */ - rl2_rx_pdata(sc, buf, len, &pd); - else if (len < buflen) { /* Underfill */ -#ifdef DIAGNOSTIC - printf("%s: underfill %d<%d, cmd %c%d\n", - sc->sc_dev.dv_xname, - len, buflen, - hdr->cmd_letter, hdr->cmd_fn); -#endif - rl2_rx_pdata(sc, buf, len, &pd); - } else { /* Overflow */ -#ifdef DIAGNOSTIC - printf("%s: overflow %d>%d, cmd %c%d\n", - sc->sc_dev.dv_xname, - len, buflen, - hdr->cmd_letter, hdr->cmd_fn); -#endif - rl2_rx_pdata(sc, buf, buflen, &pd); - /* Drain the rest somewhere. */ - rl2_rx_pdata(sc, data, len - buflen, &pd); - } - } - rl2_rx_end(sc); - - /* This message can now be handled by the waiter. */ - rl2_mbox_unlock(sc, hdr->cmd_seq, len + sizeof *hdr); - return; - } - - /* Otherwise, handle the message, right here, right now. */ - - /* Check if we can cope with the size of this message. */ - if (len > sizeof data) { - printf("%s: msg too big (%d)\n", sc->sc_dev.dv_xname, len); - ifp->if_ierrors++; - rl2_rx_end(sc); - /* rl2_need_reset(sc); */ - return; - } - - /* Check for error results. */ - if (hdr->cmd_error & 0x80) { - printf("%s: command error 0x%02x command %c%d len=%d\n", - sc->sc_dev.dv_xname, - hdr->cmd_error & ~0x80, - hdr->cmd_letter, hdr->cmd_fn, - len); - ifp->if_ierrors++; - rl2_rx_end(sc); - rl2_need_reset(sc); - return; - } - - /* - * "b1": Receiving a packet is a special case. - * We wish to read the data with pio straight into an - * mbuf to avoid a memory-memory copy. - */ - if (hdr->cmd_letter == 'b' && hdr->cmd_fn == 1) { - m = rl2get(sc, hdr, len); - rl2_rx_end(sc); - if (m == NULL) - return; - ifp->if_ipackets++; -#ifdef DIAGNOSTIC - if (bcmp(mtod(m, u_int8_t *), "prox", 4) == 0) { - printf("%s: proxim special packet received\n", - sc->sc_dev.dv_xname); - } -#endif - /* XXX Jean's driver dealt with RFC893 trailers here */ - eh = mtod(m, struct ether_header *); -#if NBPFILTER > 0 - if (ifp->if_bpf) - bpf_mtap(ifp->if_bpf, m); -#endif - m_adj(m, sizeof (struct ether_header)); - ether_input(ifp, eh, m); - return; - } - - - /* Otherwise we read the packet into a buffer on the stack. */ - bcopy(hdr, data, sizeof *hdr); - if (len > sizeof *hdr) - rl2_rx_pdata(sc, data + sizeof *hdr, len - sizeof *hdr, &pd); - rl2_rx_end(sc); - -#ifdef RL2DUMP - printf("%s: recv %c%d seq %d data ", sc->sc_dev.dv_xname, - hdr->cmd_letter, hdr->cmd_fn, hdr->cmd_seq); - RL2DUMPHEX(hdr, sizeof hdr); - printf(":"); - RL2DUMPHEX(data + sizeof hdr, len - sizeof hdr); - printf("\n"); -#endif - - switch (RL2_MM_CMD(hdr->cmd_letter, hdr->cmd_fn)) { - case RL2_MM_CMD('b', 0): /* b0: Transmit done. */ -#ifdef DIAGNOSTIC - if (len != 7) - printf("%s: 'b0' len %d != 7\n", - sc->sc_dev.dv_xname, len); -#endif - ifp->if_flags &= ~IFF_OACTIVE; - ifp->if_opackets++; - s = splnet(); - rl2start(ifp); - splx(s); - break; - - case RL2_MM_CMD('a', 20): /* a20: Card fault. */ - printf("%s: hardware fault\n", sc->sc_dev.dv_xname); - break; - - case RL2_MM_CMD('a', 4): /* a4: Sync'd. */ - if (bcmp(syncp->enaddr, sc->sc_arpcom.ac_enaddr, - ETHER_ADDR_LEN) == 0) { - /* Sync'd to own enaddr. */ - /* - * From http://www.proxim.com/support/faq/7400.shtml - * 3. RL2SETUP reports that I'm synchronized to my own MAC address. What - * does that mean? - * You are the acting Master for this network. Either you are - * configured as the Master or as an Alternate Master. If you are an - * Alternate Master, you may be out of range or on a different Domain - * and Security ID from the true Master. - */ - - printf("%s: nothing to sync to; now master ", - sc->sc_dev.dv_xname); - } - else - printf("%s: synchronised to ", sc->sc_dev.dv_xname); - printf("%.11s (%s) channel %d/%d\n", - syncp->mastername, - ether_sprintf(syncp->enaddr), - syncp->channel, - syncp->subchannel); - - /* Record the new circumstances. */ - sc->sc_param.rp_channel = syncp->channel; - sc->sc_param.rp_subchannel = syncp->subchannel; - sc->sc_state |= RL2_STATE_SYNC; - - /* Resume sending. */ - s = splnet(); - rl2start(ifp); - splx(s); - break; - - case RL2_MM_CMD('a', 5): /* a4: Lost sync. */ - printf("%s: lost sync\n", sc->sc_dev.dv_xname); - sc->sc_state &= ~RL2_STATE_SYNC; - break; - - case RL2_MM_CMD('a', 18): /* a18: Roaming. */ - printf("%s: roaming\n", sc->sc_dev.dv_xname); - break; - default: -#ifdef DIAGNOSTIC - printf("%s: msg `%c%d' seq %d data {", - sc->sc_dev.dv_xname, - hdr->cmd_letter, hdr->cmd_fn, hdr->cmd_seq); - RL2DUMPHEX(hdr, sizeof hdr); - printf(":"); - RL2DUMPHEX(data, len); - printf("}\n"); -#endif - break; - } - -} - -/* Extract a received network packet from the card. */ -static struct mbuf * -rl2get(sc, hdr, totlen) - struct rl2_softc *sc; - struct rl2_mm_cmd *hdr; - int totlen; -{ - struct ifnet *ifp = &sc->sc_arpcom.ac_if; - int len; - struct mbuf *m, **mp, *top; - struct rl2_pdata pd = RL2_PDATA_INIT; - u_int8_t hwhdr[20]; - - dprintf(" [get]"); - -#ifdef RL2DUMP - printf("%s: recv %c%d seq %d data ", sc->sc_dev.dv_xname, - hdr->cmd_letter, hdr->cmd_fn, hdr->cmd_seq); - RL2DUMPHEX(hdr, sizeof hdr); - printf(":"); -#endif - - totlen -= sizeof *hdr; -#ifdef DIAGNOSTIC - if (totlen <= 0) { - printf("%s: empty packet", sc->sc_dev.dv_xname); - goto drop; - } -#endif - - totlen -= sizeof hwhdr; - /* Skip the hardware header. */ - rl2_rx_pdata(sc, hwhdr, sizeof hwhdr, &pd); -#ifdef RL2DUMP - RL2DUMPHEX(hwhdr, sizeof hwhdr); - printf("/"); -#endif - /* (Most of the following code fleeced from elink3.c.) */ - - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) - goto drop; - m->m_pkthdr.rcvif = ifp; - m->m_pkthdr.len = totlen; - len = MHLEN; - top = 0; - mp = ⊤ - - while (totlen > 0) { - if (top) { - MGET(m, M_DONTWAIT, MT_DATA); - if (!m) { - m_freem(top); - goto drop; - } - len = MLEN; - } - if (top && totlen >= MINCLSIZE) { - MCLGET(m, M_DONTWAIT); - if (m->m_flags & M_EXT) - len = MCLBYTES; - } - len = min(totlen, len); - rl2_rx_pdata(sc, mtod(m, u_int8_t *), len, &pd); -#ifdef RL2DUMP - RL2DUMPHEX(mtod(m, u_int8_t *), len); - if (totlen != len) - printf("|"); -#endif - m->m_len = len; - totlen -= len; - *mp = m; - mp = &m->m_next; - } -#ifdef RL2DUMP - printf("\n"); -#endif - return m; - -drop: -#ifdef RL2DUMP - printf(": drop\n"); -#endif - ifp->if_iqdrops++; - return NULL; -} - -/* Interface control. */ -static int -rl2ioctl(ifp, cmd, data) - struct ifnet *ifp; - u_long cmd; - caddr_t data; -{ - struct rl2_softc *sc = ifp->if_softc; - struct ifaddr *ifa = (struct ifaddr *)data; - int s, error; - int need_init; - - s = splnet(); - if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) != 0) { - splx(s); - return error; - } - - switch (cmd) { - case SIOCSIFADDR: - /* Set address. */ - ifp->if_flags |= IFF_UP; - - switch (ifa->ifa_addr->sa_family) { -#ifdef INET - case AF_INET: - rl2init(sc); - arp_ifinit(&sc->sc_arpcom, ifa); - break; -#endif - default: - rl2init(sc); - break; - } - break; - - case SIOCSIFFLAGS: - need_init = 0; - - if ((ifp->if_flags & IFF_UP) == 0 && - (ifp->if_flags & IFF_RUNNING) != 0) { - /* Was running, want down: stop. */ - rl2stop(sc); - } else if ((ifp->if_flags & IFF_UP) != 0 && - (ifp->if_flags & IFF_RUNNING) == 0) { - /* Was not running, want up: start. */ - need_init = 1; - } - - if (ifp->if_flags & IFF_RUNNING) { - if ((ifp->if_flags & IFF_PROMISC) && - (sc->sc_state & RL2_STATE_PROMISC) == 0) { - sc->sc_state |= RL2_STATE_PROMISC; - need_init = 1; - } - else if ((ifp->if_flags & IFF_PROMISC) == 0 && - (sc->sc_state & RL2_STATE_PROMISC)) { - sc->sc_state &= ~RL2_STATE_PROMISC; - need_init = 1; - } - } - - /* XXX Deal with other flag changes? */ - - if (need_init) - rl2init(sc); - - break; - - case SIOCADDMULTI: - case SIOCDELMULTI: - error = EOPNOTSUPP; - break; - -#if notyet - case RL2IOSPARAM: - error = rl2_iosetparam(sc, (struct rl2_param *)&data); - break; - - case RL2IOGPARAM: - bcopy(&sc->sc_param, (struct rl2_param *)&data, - sizeof sc->sc_param); - break; -#endif - - default: - error = EINVAL; - break; - } - - splx(s); - return (error); -} - -/* Stop output from the card. */ -static void -rl2stop(sc) - struct rl2_softc *sc; -{ - struct ifnet *ifp = &sc->sc_arpcom.ac_if; - - dprintf(" [stop]"); - /* XXX Should kill interrupts? */ - /* rl2_enable(sc, 0); */ - ifp->if_flags &= ~IFF_RUNNING; -} - -/* Test for existence of card. */ -static int -rl2_probe(sc) - struct rl2_softc *sc; -{ - - dprintf(" [probe]"); - /* If we can reset it, it's there. */ - return (rl2_reset(sc)); -} - -/* Get MAC address from card. */ -static int -rl2_getenaddr(sc, enaddr) - struct rl2_softc *sc; - u_int8_t * enaddr; -{ - struct rl2_mm_cmd query = RL2_MM_GETENADDR; - struct rl2_mm_gotenaddr response = { RL2_MM_GETENADDR }; - - if (rl2_msg_txrx(sc, &query, sizeof query, - &response, sizeof response)) - return (-1); - bcopy(response.enaddr, enaddr, sizeof response.enaddr); - return (0); -}; - -/* Get firmware version string from card. */ -static int -rl2_getpromvers(sc, ver, verlen) - struct rl2_softc *sc; - char *ver; - int verlen; -{ - struct rl2_mm_cmd query = RL2_MM_GETPROMVERSION; - struct rl2_mm_gotpromversion response = { RL2_MM_GOTPROMVERSION }; - int i; - -#ifdef DIAGNOSTIC - if (verlen != sizeof response.version) - panic("rl2_getpromvers"); -#endif - - if (rl2_msg_txrx(sc, &query, sizeof query, - &response, sizeof response)) - return (-1); - bcopy(response.version, ver, verlen); - /* Nul trailing spaces. */ - for (i = verlen - 1; i >= 0 && ver[i] <= ' '; i--) - ver[i] = '\0'; - return (0); -}; - -/* Set default operational parameters on card. */ -static int -rl2_sendinit(sc) - struct rl2_softc *sc; -{ - struct rl2_mm_init init = { RL2_MM_INIT }; - struct rl2_mm_initted iresponse; -#if 0 - struct rl2_mm_setmagic magic = { RL2_MM_SETMAGIC }; - struct rl2_mm_disablehopping hop = { RL2_MM_DISABLEHOPPING }; - struct rl2_mm_cmd response; -#endif - - bzero((char*)&init + sizeof init.mm_cmd, - sizeof init - sizeof init.mm_cmd); - - dprintf(" [setting parameters]"); - init.opmode = (sc->sc_state & RL2_STATE_PROMISC ? - RL2_MM_INIT_OPMODE_PROMISC : RL2_MM_INIT_OPMODE_NORMAL); - init.stationtype = sc->sc_param.rp_station_type; - - /* Spread-spectrum frequency hopping. */ - init.hop_period = 1; - init.bfreq = 2; - init.sfreq = 7; - - /* Choose channel. */ - init.channel = sc->sc_param.rp_channel; - init.subchannel = sc->sc_param.rp_subchannel; - init.domain = sc->sc_param.rp_domain; - - /* Name of this station when acting as master. */ - bcopy(sc->sc_param.rp_master, init.mastername, sizeof init.mastername); - - /* Security params. */ - init.sec1 = (sc->sc_param.rp_security & 0x0000ff) >> 0; - init.sec2 = (sc->sc_param.rp_security & 0x00ff00) >> 8; - init.sec3 = (sc->sc_param.rp_security & 0xff0000) >> 16; - - init.sync_to = 1; - bzero(init.syncname, sizeof init.syncname); - - if (rl2_msg_txrx(sc, &init, sizeof init, - &iresponse, sizeof iresponse)) - return (-1); -#if 0 - dprintf(" [setting magic]"); - magic.fairness_slot = 3; /* lite: 1, norm: 3, off: -1 */ - magic.deferral_slot = 3; /* lite: 0, norm: 3, off: -1 */ - magic.regular_mac_retry = 7; - magic.frag_mac_retry = 10; - magic.regular_mac_qfsk = 2; - magic.frag_mac_qfsk = 5; - magic.xxx1 = 0xff; - magic.xxx2 = 0xff; - magic.xxx3 = 0xff; - magic.xxx4 = 0x00; - if (rl2_msg_txrx(sc, &magic, sizeof magic, - &response, sizeof response)) - return (-1); - - dprintf(" [disabling freq hopping]"); - hop.hopflag = RL2_MM_DISABLEHOPPING_HOPFLAG_DISABLE; - if (rl2_msg_txrx(sc, &hop, sizeof hop, - &response, sizeof response)) - return (-1); - -#endif - return (0); -} - -#if notyet -/* Configure the way the card leaves a basestation. */ -static int -rl2_roamconfig(sc) - struct rl2_softc *sc; -{ - struct rl2_mm_setroaming roam = { RL2_MM_SETROAMING }; - struct rl2_mm_cmd response; - static int retry[3] = { 6, 6, 4 }; - static int rssi[3] = { 5, 15, 5 }; - - dprintf(" [roamconfig]"); -#ifdef DIAGNOSTIC - if (sc->sc_param.rp_roam_config > 2) - panic("roamconfig"); -#endif - roam.sync_alarm = 0; - roam.retry_thresh = retry[sc->sc_param.rp_roam_config]; - roam.rssi_threshold = rssi[sc->sc_param.rp_roam_config]; - roam.xxx1 = 0x5a; - roam.sync_rssi_threshold = 0; - roam.xxx2 = 0x5a; - roam.missed_sync = 0x4; - if (rl2_msg_txrx(sc, &roam, sizeof roam, - &response, sizeof response)) - return (-1); - - return (0); -} - -/* Enable roaming. */ -static int -rl2_roam(sc) - struct rl2_softc *sc; -{ - struct rl2_mm_cmd roam = RL2_MM_ROAM; - struct rl2_mm_cmd response; - - return (rl2_msg_txrx(sc, &roam, sizeof roam, - &response, sizeof response)); -} - -/* Enable multicast capability. */ -static int -rl2_multicast(sc, enable) - struct rl2_softc *sc; - int enable; -{ - struct ifnet *ifp = &sc->sc_arpcom.ac_if; - struct rl2_mm_multicast mcast = { RL2_MM_MULTICAST }; - struct rl2_mm_cmd response; - int ret; - - mcast.enable = enable; - - ret = rl2_msg_txrx(sc, &mcast, sizeof mcast, - &response, sizeof response); - if (ret == 0) { - if (enable) - ifp->if_flags |= IFF_MULTICAST; - else - ifp->if_flags &= ~IFF_MULTICAST; - } - return (ret); -} - -/* Search for and sync with any master. */ -static int -rl2_searchsync(sc) - struct rl2_softc *sc; -{ - struct rl2_mm_search search = { RL2_MM_SEARCH }; - struct rl2_mm_searching response; - - bzero(search.xxx1, sizeof search.xxx1); - search.domain = sc->sc_param.rp_domain; - search.roaming = 1; - search.xxx3 = 0; - search.xxx4 = 1; - search.xxx5 = 0; - bzero(search.xxx6, sizeof search.xxx6); - - return (rl2_msg_txrx(sc, &search, sizeof search, - &response, sizeof response)); -} - -/* Set values from an external parameter block. */ -static int -rl2_iosetparam(sc, param) - struct rl2_softc *sc; - struct rl2_param *param; -{ - int error = 0; - - if (param->rp_roam_config > 2) - error = EINVAL; - if (param->rp_security > 0x00ffffff) - error = EINVAL; - if (param->rp_station_type > 2) - error = EINVAL; - if (param->rp_channel > 15) - error = EINVAL; - if (param->rp_subchannel > 15) - error = EINVAL; - if (error == 0) { - /* Apply immediately. */ - bcopy(param, &sc->sc_param, sizeof *param); - if (rl2_sendinit(sc)) - error = EIO; - } - return (error); -} - -/* Protect the eeprom from storing a security ID(?) */ -static int -rl2_lockprom(sc) - struct rl2_softc *sc; -{ - struct rl2_mm_cmd lock = RL2_MM_EEPROM_PROTECT; - struct rl2_mm_cmd response; - - /* XXX Always yields an error? */ - return (rl2_msg_txrx(sc, &lock, sizeof lock, - &response, sizeof response)); -} - -/* Set the h/w Inactivity Time Out timer on the card. */ -static int -rl2_ito(sc) - struct rl2_softc * sc; -{ - struct rl2_mm_setito ito = { RL2_MM_MULTICAST }; - struct rl2_mm_cmd response; - - ito.xxx = 3; - ito.timeout = LLDInactivityTimeOut /* enabler, 0 or 1 */; - ito.bd_wakeup = LLDBDWakeup /* 0 */; - ito.pm_sync = LLDPMSync /* 0 */; - ito.sniff_time = ito.timeout ? LLDSniffTime /* 0 */ : 0; - - if (rl2_msg_txrx(sc, &ito, sizeof ito, - &response, sizeof response)) - return (-1); -} - -/* Put the card into standby mode. */ -static int -rl2_standby(sc) - struct rl2_softc * sc; -{ - struct rl2_mm_standby standby = { RL2_MM_STANDBY }; - - standby.xxx = 0; - if (rl2_msg_txrx(sc, &ito, sizeof ito, NULL, 0)) - return (-1); -} -#endif diff --git a/sys/dev/ic/rl2.h b/sys/dev/ic/rl2.h deleted file mode 100644 index 850dda9331c..00000000000 --- a/sys/dev/ic/rl2.h +++ /dev/null @@ -1,39 +0,0 @@ -/* $OpenBSD: rl2.h,v 1.2 1999/07/14 03:51:50 d Exp $ */ -/* - * David Leonard , 1999. Public domain. - * - * Proxim RangeLAN2 parameters. - */ - -/* - * Eventually, there should be a way of getting and setting these - * from user space. Ideally, via ioctl(). - */ - -/* User-configurable station parameters. */ -struct rl2_param { - u_int32_t rp_security; /* Security ID */ -#define RL2_SECURITY_DEFAULT 0x0010203 - u_int8_t rp_station_type; /* Station type */ -#define RL2_STATIONTYPE_SLAVE 0 -#define RL2_STATIONTYPE_ALTMASTER 1 -#define RL2_STATIONTYPE_MASTER 2 - u_int8_t rp_domain; /* Network domain */ - u_int8_t rp_channel; /* Phys channel when master */ - u_int8_t rp_subchannel; /* Logical master subchannel */ - char rp_master[11]; /* Name when master */ - u_int8_t rp_mac_optimize; -#define RL2_MAC_OPTIM_LIGHT 0 -#define RL2_MAC_OPTIM_NORMAL 1 - u_int8_t rp_roam_config; /* Roaming speed */ -#define RL2_ROAM_SLOW 0 -#define RL2_ROAM_NORMAL 1 -#define RL2_ROAM_FAST 2 - u_int8_t rp_peer_to_peer; /* Ability to talk to peers */ -}; - -#ifdef notyet -#define RL2IOSPARAM _IOW('2', 1, struct rl2_param) /* set params */ -#define RL2IOGPARAM _IOR('2', 2, struct rl2_param) /* get params */ -#endif - diff --git a/sys/dev/ic/rl2cmd.h b/sys/dev/ic/rl2cmd.h deleted file mode 100644 index 0fe4f8365e4..00000000000 --- a/sys/dev/ic/rl2cmd.h +++ /dev/null @@ -1,247 +0,0 @@ -/* $OpenBSD: rl2cmd.h,v 1.2 1999/07/14 03:52:27 d Exp $ */ -/* - * David Leonard , 1999. Public Domain. - * - * RangeLAN2 host-to-card message protocol. - */ - -/* Micro-message command header. */ -struct rl2_mm_cmd { - u_int8_t cmd_letter; /* Command letter */ - u_int8_t cmd_seq; /* Incremented on each command */ -#define RL2_MAXSEQ 0x7c - u_int8_t cmd_fn; /* Function number */ - u_int8_t cmd_error; /* Reserved */ -}; -#define RL2_MM_CMD(l,n) ((((unsigned int)l)<<8) | ((unsigned int)n)) -#define RL2_MM_CMD_LETTER(cmd) ((unsigned char)(((cmd) & 0xff00)>>8)) -#define RL2_MM_CMD_FUNCTION(cmd) ((unsigned char)((cmd) & 0xff)) -#define RL2_CMDCODE(letter, num) ((((letter) & 0xff) << 8) | ((num) & 0xff)) - -/* Initialise card, and set operational parameters. */ -struct rl2_mm_init { - struct rl2_mm_cmd mm_cmd; -#define RL2_MM_INIT { 'A', 0, 0, 0 } - u_int8_t enaddr[6]; - u_int8_t opmode; -#define RL2_MM_INIT_OPMODE_NORMAL 0 -#define RL2_MM_INIT_OPMODE_PROMISC 1 -#define RL2_MM_INIT_OPMODE_PROTOCOL 2 - u_int8_t stationtype; /* RL2_STATIONTYPE_... */ - u_int8_t hop_period; - u_int8_t bfreq; - u_int8_t sfreq; - u_char channel : 4; /* lower bits */ - u_char subchannel : 4; /* upper bits */ - char mastername[11]; - u_char sec1 : 4; /* default 3 */ - u_char domain : 4; /* default 0 */ - u_int8_t sec2; /* default 2 */ - u_int8_t sec3; /* default 1 */ - u_int8_t sync_to; /* 1 if roaming */ - u_int8_t xxx_pad; /* zero */ - char syncname[11]; -}; - -/* Result of initialisation. */ -struct rl2_mm_initted { - struct rl2_mm_cmd mm_cmd; -#define RL2_MM_INITTED { 'a', 0, 0, 0 } - u_int8_t xxx; -}; - -/* Start searching for other masters. */ -struct rl2_mm_search { - struct rl2_mm_cmd mm_cmd; -#define RL2_MM_SEARCH { 'A', 0, 1, 0 } - u_int8_t xxx1[23]; - u_char xxx2 : 4; - u_char domain : 4; - u_int8_t roaming; - u_int8_t xxx3; /* default 0 */ - u_int8_t xxx4; /* default 1 */ - u_int8_t xxx5; /* default 0 */ - u_int8_t xxx6[11]; -}; - -/* Notification that searching has started. */ -struct rl2_mm_searching { - struct rl2_mm_cmd mm_cmd; -#define RL2_MM_SEARCHING { 'a', 0, 1, 0 } - u_int8_t xxx; -}; - -/* Terminate search. */ -#define RL2_MM_ABORTSEARCH { 'A', 0, 3, 0 } - -/* Station synchronised to a master. */ -struct rl2_mm_synchronised { - struct rl2_mm_cmd mm_cmd; -#define RL2_MM_SYNCHRONISED { 'a', 0, 4, 0 } - u_char channel : 4; /* lower bits */ - u_char subchannel : 4; /* upper bits */ - char mastername[11]; - u_int8_t enaddr[6]; -}; - -/* Station lost synchronisation with a master. */ -#define RL2_MM_UNSYNCHRONISED { 'a', 0, 5, 0 } - -/* Send card to sleep. (See rl2_wakeup().) */ -struct rl2_mm_standby { - struct rl2_mm_cmd mm_cmd; -#define RL2_MM_STANDBY { 'A', 0, 6, 0 } - u_int8_t xxx; /* default 0 */ -}; - -/* Set ITO (inactivity timeout timer). */ -struct rl2_mm_setito { - struct rl2_mm_cmd mm_cmd; -#define RL2_MM_SETITO { 'A', 0, 7, 0 } - u_int8_t xxx; /* default 3 */ - u_int8_t timeout; - u_char bd_wakeup : 1; - u_char pm_sync : 7; - u_int8_t sniff_time; -}; - -/* ITO acknowledgment */ -#define RL2_MM_GOTITO { 'a', 0, 7, 0 } - -/* Send keepalive protocol message (?). */ -#define RL2_MM_SENDKEEPALIVE { 'A', 0, 8, 0 } - -/* Set multicast mode. */ -struct rl2_mm_multicast { - struct rl2_mm_cmd mm_cmd; -#define RL2_MM_MULTICAST { 'A', 0, 9, 0 } - u_int8_t enable; -}; - -/* Ack multicast mode change. */ -#define RL2_MM_MULTICASTING { 'a', 0, 9, 0 } - -/* Request statistics. */ -#define RL2_MM_GETSTATS { 'A', 0, 11, 0 } - -/* Statistics results. */ -#define RL2_MM_GOTSTATS { 'a', 0, 11, 0 } - -/* Set security ID used in channel. */ -struct rl2_mm_setsecurity { - struct rl2_mm_cmd mm_cmd; -#define RL2_MM_SETSECURITY { 'A', 0, 12, 0 } - u_int8_t sec1; - u_int8_t sec2; - u_int8_t sec3; -}; - -/* Ack set security ID. */ -#define RL2_MM_GOTSECURITY { 'a', 0, 12, 0 } - -/* Request firmware version. */ -#define RL2_MM_GETPROMVERSION { 'A', 0, 13, 0 } - -/* Reply with firmware version. */ -struct rl2_mm_gotpromversion { - struct rl2_mm_cmd mm_cmd; -#define RL2_MM_GOTPROMVERSION { 'a', 0, 13, 0 } - u_int8_t xxx; /* sizeof version? */ - char version[7]; -}; - -/* Request station's MAC address (same as ethernet). */ -#define RL2_MM_GETENADDR { 'A', 0, 14, 0 } - -/* Reply with station's MAC address. */ -struct rl2_mm_gotenaddr { - struct rl2_mm_cmd mm_cmd; -#define RL2_MM_GOTENADDR { 'a', 0, 14, 0 } - u_int8_t xxx; - u_int8_t enaddr[6]; -}; - -/* Tune various channel parameters. */ -struct rl2_mm_setmagic { - struct rl2_mm_cmd mm_cmd; -#define RL2_MM_SETMAGIC { 'A', 0, 16, 0 } - u_char fairness_slot : 3; - u_char deferral_slot : 5; - u_int8_t regular_mac_retry; /* default 0x07 */ - u_int8_t frag_mac_retry; /* default 0x0a */ - u_int8_t regular_mac_qfsk; /* default 0x02 */ - u_int8_t frag_mac_qfsk; /* default 0x05 */ - u_int8_t xxx1; /* default 0xff */ - u_int8_t xxx2; /* default 0xff */ - u_int8_t xxx3; /* default 0xff */ - u_int8_t xxx4; /* zero */ -}; - -/* Ack channel tuning. */ -#define RL2_MM_GOTMAGIC { 'a', 0, 16, 0 } - -/* Set roaming parameters - used when multiple masters available. */ -struct rl2_mm_setroaming { - struct rl2_mm_cmd mm_cmd; -#define RL2_MM_SETROAMING { 'A', 0, 17, 0 } - u_int8_t sync_alarm; - u_int8_t retry_thresh; - u_int8_t rssi_threshold; - u_int8_t xxx1; /* default 0x5a */ - u_int8_t sync_rssi_threshold; - u_int8_t xxx2; /* default 0xa5 */ - u_int8_t missed_sync; -}; - -/* Ack roaming parameter change. */ -#define RL2_MM_GOTROAMING { 'a', 0, 17, 0 } - -#define RL2_MM_ROAMING { 'a', 0, 18, 0 } -#define RL2_MM_ROAM { 'A', 0, 19, 0 } - -/* Hardware fault notification. (Usually the antenna.) */ -#define RL2_MM_FAULT { 'a', 0, 20, 0 } - -#define RL2_MM_EEPROM_PROTECT { 'A', 0, 23, 0 } -#define RL2_MM_EEPROM_PROTECTED { 'a', 0, 23, 0 } -#define RL2_MM_EEPROM_UNPROTECT { 'A', 0, 24, 0 } -#define RL2_MM_EEPROM_UNPROTECTED { 'a', 0, 24, 0 } - -/* Receive hop statistics. */ -#define RL2_MM_HOP_STATISTICS { 'a', 0, 35, 0 } - -/* Transmit a frame on the channel. */ -struct rl2_mm_sendpacket { - struct rl2_mm_cmd mm_cmd; -#define RL2_MM_SENDPACKET { 'B', 0, 0, 0 } - u_int8_t mode; -#define RL2_MM_SENDPACKET_MODE_BIT7 0x80 -#define RL2_MM_SENDPACKET_MODE_ZFIRST 0x20 -#define RL2_MM_SENDPACKET_MODE_QFSK 0x03 - u_int8_t power; /* default 0x70 */ - u_int8_t length_lo; - u_int8_t length_hi; - u_int8_t xxx1; /* default 0 */ - u_int8_t xxx2; /* default 0 */ - u_int8_t sequence; /* must increment */ - u_int8_t xxx3; /* default 0 */ -}; - -/* Ack packet transmission. */ -#define RL2_MM_SENTPACKET { 'b', 0, 0, 0 } - -/* Notification of frame received from channel. */ -struct rl2_mm_recvpacket { - struct rl2_mm_cmd mm_cmd; -#define RL2_MM_RECVPACKET { 'b', 0, 1, 0 } - u_int8_t xxx[8]; -}; - -/* Disable hopping. (?) */ -struct rl2_mm_disablehopping { - struct rl2_mm_cmd mm_cmd; -#define RL2_MM_DISABLEHOPPING { 'C', 0, 9, 0 } - u_int8_t hopflag; -#define RL2_MM_DISABLEHOPPING_HOPFLAG_DISABLE 0x52 -}; - diff --git a/sys/dev/ic/rl2reg.h b/sys/dev/ic/rl2reg.h deleted file mode 100644 index e311609e69e..00000000000 --- a/sys/dev/ic/rl2reg.h +++ /dev/null @@ -1,250 +0,0 @@ -/* $OpenBSD: rl2reg.h,v 1.2 1999/07/14 03:52:55 d Exp $ */ -/* - * David Leonard , 1999. Public Domain. - * - * RangeLAN2 registers - */ - -/* - * The RangeLAN2 cards provide four control registers for transferring - * messaged between the host and the card using programmed i/o. - * - * A transfer protocol is followed when sending asynchronous messages to, - * and receiving messages from, the card. - * - * DATA - * 7 6 5 4 3 2 1 0 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | data | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * - * STATUS - * 7 6 5 4 3 2 1 0 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * |WAKEUP | tx message state |CLRNAK | rx message state | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * - * CONTROL - * 7 6 5 4 3 2 1 0 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | | | 16BIT | RESET | | | TXINT | RXINT | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * - * INTSEL - * 7 6 5 4 3 2 1 0 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | | | |ENABLE | interrupt line | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - */ - -/* Register offsets. */ -#define RL2_REG_DATA 0 -#define RL2_REG_STATUS 2 -#define RL2_REG_CONTROL 4 -#define RL2_REG_EOI 5 -#define RL2_REG_INTSEL 6 -#define RL2_NPORTS 8 - -/* - * A short delay is needed (16ms?) after register writes on some cards. - * XXX This is done by performing an innocent and harmless bus read. (i386) - * This is what Proxim's driver does, anyway. - */ -#define _rl2_regacc_delay() \ - bus_space_read_1(I386_BUS_SPACE_IO, 0, 0x61) - -static void _rl2_register_write_1 __P((struct rl2_softc *, u_int8_t, - u_int8_t)); -static u_int8_t _rl2_register_read_1 __P((struct rl2_softc *, u_int8_t)); -static int rl2_status_rx_ready __P((struct rl2_softc *)); - -/* Write to a register. */ -static inline void -_rl2_register_write_1(sc, regoff, value) - struct rl2_softc *sc; - u_int8_t regoff; - u_int8_t value; -{ - -#ifdef RL2DEBUG_REG - printf(" %c<%02x", "DDS3CEI7"[regoff], value); -#endif - bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, (regoff), (value)); - _rl2_regacc_delay(); -} - -/* Read from a register. */ -static inline u_int8_t -_rl2_register_read_1(sc, regoff) - struct rl2_softc *sc; - u_int8_t regoff; -{ - u_int8_t ret; - - ret = bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, (regoff)); -#ifdef RL2DEBUG_REG - if (ret != (sc)->dbg_oreg[regoff]) { - /* avoid spewing out too much debug info */ - printf(" %c>%02x", "DDS3CEI7"[regoff], ret); - (sc)->dbg_oreg[regoff] = ret; - } -#endif - return (ret); -} - -/* 8-bit data register access. */ -#define rl2_data_write_1(sc, value) \ - _rl2_register_write_1(sc, RL2_REG_DATA, (value)) -#define rl2_data_read_1(sc) \ - _rl2_register_read_1(sc, RL2_REG_DATA) -#define rl2_data_write_multi_1(sc, buf, len) \ - bus_space_write_multi_1((sc)->sc_iot, (sc)->sc_ioh, \ - RL2_REG_DATA, (buf), (len)) -#define rl2_data_read_multi_1(sc, buf, len) \ - bus_space_read_multi_1((sc)->sc_iot, (sc)->sc_ioh, \ - RL2_REG_DATA, (buf), (len)) - -/* 16-bit data register access. */ -#define rl2_data_write_2(sc, value) \ - bus_space_write_2((sc)->sc_iot, (sc)->sc_ioh, \ - RL2_REG_DATA, (value)) -#define rl2_data_read_2(sc) \ - bus_space_read_2((sc)->sc_iot, (sc)->sc_ioh, \ - RL2_REG_DATA) -#define rl2_data_write_multi_2(sc, buf, len) \ - bus_space_write_multi_2((sc)->sc_iot, (sc)->sc_ioh, \ - RL2_REG_DATA, (buf), (len)) -#define rl2_data_read_multi_2(sc, buf, len) \ - bus_space_read_multi_2((sc)->sc_iot, (sc)->sc_ioh, \ - RL2_REG_DATA, (buf), (len)) - -/* Status register. */ -#define RL2_STATUS_CLRNAK 0x08 -#define RL2_STATUS_WAKEUP 0x80 - -#define RL2_STATUS_TX_IDLE 0x00 -#define RL2_STATUS_TX_HILEN_AVAIL 0x01 -#define RL2_STATUS_TX_HILEN_ACCEPT 0x02 -#define RL2_STATUS_TX_XFR_COMPLETE 0x03 -#define RL2_STATUS_TX_XFR 0x04 -#define RL2_STATUS_TX_ERROR 0x05 -#define RL2_STATUS_TX_LOLEN_AVAIL 0x06 -#define RL2_STATUS_TX_LOLEN_ACCEPT 0x07 -#define RL2_STATUS_TX_MASK 0x0f - -#define RL2_STATUS_RX_IDLE 0x00 -#define RL2_STATUS_RX_HILEN_AVAIL 0x10 -#define RL2_STATUS_RX_HILEN_ACCEPT 0x20 -#define RL2_STATUS_RX_XFR_COMPLETE 0x30 -#define RL2_STATUS_RX_XFR 0x40 -#define RL2_STATUS_RX_ERROR 0x50 -#define RL2_STATUS_RX_LOLEN_AVAIL 0x60 -#define RL2_STATUS_RX_LOLEN_ACCEPT 0x70 -#define RL2_STATUS_RX_MASK 0x70 - -#define rl2_status_write(sc, value) \ - _rl2_register_write_1(sc, RL2_REG_STATUS, (value)) -#define rl2_status_set(sc, bits) \ - rl2_status_write(sc, (sc)->sc_status |= (bits)) -#define rl2_status_clear(sc, bits) \ - rl2_status_write(sc, (sc)->sc_status &= ~(bits)) -#define _rl2_status_setmask(sc, mask, bits) \ -do { \ - int _s; \ - \ - _s = splhigh(); \ - (sc)->sc_status = ((sc)->sc_status & (mask)) | (bits); \ - rl2_status_write(sc, (sc)->sc_status); \ - splx(_s); \ -} while (0); -#define rl2_status_rx_write(sc, state) \ - _rl2_status_setmask((sc), ~RL2_STATUS_RX_MASK, state) -#define rl2_status_tx_write(sc, state) \ - _rl2_status_setmask((sc), ~RL2_STATUS_TX_MASK, state) -#define rl2_status_read(sc) \ - _rl2_register_read_1(sc, RL2_REG_STATUS) -#define rl2_status_rx_read(sc) \ - (rl2_status_read(sc) & ~RL2_STATUS_TX_MASK) -#define rl2_status_tx_read(sc) \ - (rl2_status_read(sc) & ~RL2_STATUS_RX_MASK) - -static inline int -rl2_status_rx_ready(sc) - struct rl2_softc *sc; -{ - u_int8_t status; - - status = rl2_status_rx_read(sc); - return (status == RL2_STATUS_RX_LOLEN_AVAIL || - status == RL2_STATUS_RX_HILEN_AVAIL || - status == RL2_STATUS_RX_ERROR); -} - -#define rl2_status_tx_int(sc) do { \ - int _s = splhigh(); \ - \ - rl2_control_clear(sc, RL2_CONTROL_TXINT); \ - rl2_control_set(sc, RL2_CONTROL_TXINT); \ - splx(_s); \ -} while (0) -#define rl2_status_rx_int(sc) do { \ - int _s = splhigh(); \ - \ - rl2_control_clear(sc, RL2_CONTROL_RXINT); \ - rl2_control_set(sc, RL2_CONTROL_RXINT); \ - splx(_s); \ -} while (0) - -/* Control register. */ -#define RL2_CONTROL_RXINT 0x01 -#define RL2_CONTROL_TXINT 0x02 -#define RL2_CONTROL_BIT2 0x04 -#define RL2_CONTROL_BIT3 0x08 -#define RL2_CONTROL_RESET 0x10 -#define RL2_CONTROL_16BIT 0x20 -#define RL2_CONTROL_MASK 0x3f - -#define rl2_control_write(sc, value) \ - _rl2_register_write_1(sc, RL2_REG_CONTROL, \ - (sc)->sc_control = (value)) -#define rl2_control_read(sc) \ - _rl2_register_read_1(sc, RL2_REG_CONTROL) -#define rl2_control_set(sc, bits) \ - rl2_control_write(sc, (sc)->sc_control | (bits)) -#define rl2_control_clear(sc, bits) \ - rl2_control_write(sc, (sc)->sc_control & ~(bits)) -#define rl2_control_outofstandby(sc) do { \ - rl2_control_write(sc, (sc)->sc_control | RL2_CONTROL_RESET);\ - DELAY(30000); \ - rl2_control_write(sc, (sc)->sc_control); \ -} while (0) - -/* Interrupt selection register. */ -#define RL2_INTSEL_IRQMASK 0x07 -#define RL2_INTSEL_ENABLE 0x10 -#define RL2_INTSEL_BIT7 0x80 - -#define rl2_intsel_disable(sc) do { \ - int _s; \ - \ - _s = splhigh(); \ - _rl2_register_write_1(sc, RL2_REG_INTSEL, \ - (sc)->sc_intsel &= ~RL2_INTSEL_ENABLE); \ - splx(_s); \ -} while (0) -#define rl2_intsel_enable(sc) do { \ - int _s; \ - \ - _s = splhigh(); \ - _rl2_register_write_1(sc, RL2_REG_INTSEL, \ - (sc)->sc_intsel |= RL2_INTSEL_ENABLE); \ - splx(_s); \ -} while (0) -#define rl2_intsel_write(sc, value) \ - _rl2_register_write_1(sc, RL2_REG_INTSEL, \ - (sc)->sc_intsel |= (value)) - -/* End of interrupt signal, used on some newer cards. */ -#define rl2_eoi(sc) \ - (void) _rl2_register_read_1(sc, RL2_REG_EOI) - diff --git a/sys/dev/ic/rl2subr.c b/sys/dev/ic/rl2subr.c deleted file mode 100644 index 468c4ff7e66..00000000000 --- a/sys/dev/ic/rl2subr.c +++ /dev/null @@ -1,931 +0,0 @@ -/* $OpenBSD: rl2subr.c,v 1.3 1999/07/14 03:53:23 d Exp $ */ -/* - * David Leonard , 1999. Public Domain. - * - * Low level card protocol access to the Proxim RangeLAN2 wireless - * network adaptor. - * - * Information and ideas gleaned from - * - disassembly of Dave Koberstein's Linux driver - * (which is built with Proxim source), - * - Yoichi Shinoda's BSDI driver, and - * - Geoff Voelker's Linux port of the same. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifdef INET -#include -#include -#endif - -#include -#include - -#include -#include -#include -#include - -static int rl2_tx_request __P((struct rl2_softc *, u_int16_t)); -static int rl2_tx_end __P((struct rl2_softc *)); - -/* - * Disables or enables interrupts from the card. Returns the old - * interrupt-enable state. - */ -int -rl2_enable(sc, enable) - struct rl2_softc * sc; - int enable; -{ - int s; - int was_enabled; - - s = splhigh(); - was_enabled = (sc->sc_intsel & RL2_INTSEL_ENABLE) ? 1 : 0; - if (enable != was_enabled) { - if (enable) - sc->sc_intsel |= RL2_INTSEL_ENABLE; - else - sc->sc_intsel &=~RL2_INTSEL_ENABLE; - _rl2_register_write_1(sc, RL2_REG_INTSEL, sc->sc_intsel); - } - splx(s); - return (was_enabled); -} - -/* - * Perform a hard reset of the card. Determines bus width (8 or - * 16 bit), if sc->sc_width is unset. Returns 0 on success. - * Note: takes about 200ms at splhigh, meaning this is an expensive call, - * but normal (error-free) operation of the card will not need more than - * two resets - one at probe time, and the other when the interface is - * brought up. - */ -int -rl2_reset(sc) - struct rl2_softc * sc; -{ - int s; - int i; - int status; - u_int8_t op = 0x00; - - s = splhigh(); - dprintf(" R["); - if (sc->sc_cardtype & (RL2_CTYPE_UISA | RL2_CTYPE_ONE_PIECE)) - op = 0x04; - if (rl2_status_read(sc) & RL2_STATUS_WAKEUP) { - rl2_control_write(sc, op); - rl2_control_write(sc, op | RL2_CONTROL_RESET); - dprintf(" 7ms"); - DELAY(7000); - rl2_control_write(sc, op); - dprintf(" 7ms"); - DELAY(7000); - } - rl2_control_write(sc, op); - rl2_control_write(sc, op); - rl2_control_write(sc, op | RL2_CONTROL_BIT3); - dprintf(" 67ms"); - DELAY(67000); - rl2_status_write(sc, 0x00); - if (sc->sc_cardtype & (RL2_CTYPE_UISA | RL2_CTYPE_ONE_PIECE)) - rl2_control_write(sc, 0x38); - /* RL2_CONTROL_BIT3 | RL2_CONTROL_RESET | RL2_CONTROL_16BIT */ - else - rl2_control_write(sc, 0x2c); - /* RL2_CONTROL_BIT3 | RL2_CONTROL_BIT2 | RL2_CONTROL_16BIT */ - dprintf(" 67ms"); - DELAY(67000); - rl2_data_write_2(sc, 0xaa55); - rl2_status_write(sc, 0x5a); - splx(s); - for (i = 0; i < 2000; i++) { /* Proxim says 200 not 2000. */ - if ((status = rl2_status_read(sc)) == 0x5a) - break; - DELAY(1000); - } - dprintf(" (%dms)", i); - s = splhigh(); - if (status != 0x5a) { - splx(s); - printf("%s: reset timeout\n", sc->sc_dev.dv_xname); - dprintf("]=-1"); - return (-1); - } - if (sc->sc_width == 8) { - if (sc->sc_cardtype & (RL2_CTYPE_UISA | RL2_CTYPE_ONE_PIECE)) - rl2_control_write(sc, RL2_CONTROL_BIT3); - else - rl2_control_write(sc, RL2_CONTROL_BIT3 | - RL2_CONTROL_BIT2); - rl2_data_write_1(sc, 0x20); - } else if (sc->sc_width == 16) { - rl2_data_write_2(sc, 0x0000); - } else { - if (rl2_data_read_2(sc) == 0x55aa) { - rl2_data_write_2(sc, 0x0000); - sc->sc_width = 16; - } else { - if (sc->sc_cardtype & (RL2_CTYPE_UISA | - RL2_CTYPE_ONE_PIECE)) - rl2_control_write(sc, RL2_CONTROL_BIT3); - else - rl2_control_write(sc, RL2_CONTROL_BIT3 | - RL2_CONTROL_BIT2); - rl2_data_write_1(sc, 0x20); - sc->sc_width = 8; - } - printf("%s: %d bit bus\n", sc->sc_dev.dv_xname, sc->sc_width); - } - rl2_status_write(sc, 0x00); - sc->sc_intsel = 0; - rl2_intsel_write(sc, sc->sc_irq); - splx(s); - dprintf("]"); - return (0); -} - -/* - * Sets the new 'wakeup' state. Returns the old wakeup state. - * The special state value RL2_WAKEUP_SET should be used to wake the - * card up. The card can be partially put to sleep (presumably to save - * power) by sending it the 'Standby' command. - */ -u_int8_t -rl2_wakeup(sc, wnew) - struct rl2_softc * sc; - u_int8_t wnew; -{ - u_int8_t wold, s; - int i; - - /* Save what the last-written values were. */ - wold = (sc->sc_status & RL2_STATUS_WAKEUP) | - (sc->sc_control & RL2_CONTROL_RESET); - - if (wnew == RL2_WAKEUP_SET) { - /* SetWakeupBit() */ - dprintf(" Ws["); - rl2_status_set(sc, RL2_STATUS_WAKEUP); - if (0/*LLDInactivityTimeOut && - (sc->sc_cardtype & RL2_CTYPE_OEM)*/) { - dprintf (" 167ms"); - DELAY(167000); - } else { - dprintf (" .1ms"); - DELAY(100); - } - s = rl2_status_read(sc); - rl2_control_set(sc, RL2_CONTROL_RESET); - if ((s & RL2_STATUS_WAKEUP) != 0) - for (i = 0; i < 9; i++) { - dprintf(" 2ms"); - DELAY(2000); - rl2_status_set(sc, RL2_STATUS_WAKEUP); - } - dprintf("]"); - } else { - /* ClearWakeupBit() */ - dprintf(" Wc["); - if ((wnew & RL2_STATUS_WAKEUP) == 0) - rl2_status_clear(sc, RL2_STATUS_WAKEUP); - if ((wnew & RL2_CONTROL_RESET) == 0) - rl2_control_clear(sc, RL2_CONTROL_RESET); - dprintf("]"); - } - return (wold); -} - -/* - * Performs the first (request) stage of transmitting a command message - * to the card. 'len' is the expected length of the message is needed. - * Returns: 0 on success - * 1 on timeout - * 2 on NAK (card busy, and will need a rl2_clear_nak() after 100ms) - */ -static int -rl2_tx_request(sc, len) - struct rl2_softc * sc; - u_int16_t len; -{ - /* TxRequest() */ - int s; - int i; - u_int8_t status; - - /* u_int8_t w; */ - /* w = rl2_wakeup(sc, RL2_WAKEUP_SET); */ - - dprintf(" Tr["); - if (sc->sc_width == 16) { - rl2_status_tx_write(sc, RL2_STATUS_TX_HILEN_AVAIL); - rl2_data_write_2(sc, len); - rl2_status_tx_int(sc); - - s = spl0(); - for (i = 0; i < 600; i++) { - status = rl2_status_tx_read(sc); - if (status == RL2_STATUS_TX_HILEN_ACCEPT || - status == RL2_STATUS_TX_ERROR) - break; - DELAY(1000); - } - splx(s); - dprintf(" %dms", i); - if (status == RL2_STATUS_TX_HILEN_ACCEPT) - goto success; - if (status == RL2_STATUS_TX_ERROR) - goto error; - } else if (sc->sc_width == 8) { - rl2_status_tx_write(sc, RL2_STATUS_TX_LOLEN_AVAIL); - rl2_data_write_1(sc, len & 0xff); - rl2_status_tx_int(sc); - s = spl0(); - for (i = 0; i < 6800; i++) { - status = rl2_status_tx_read(sc); - if (status == RL2_STATUS_TX_LOLEN_ACCEPT) - break; - DELAY(1000); - } - splx(s); - dprintf(" %dms", i); - if (status == RL2_STATUS_TX_LOLEN_ACCEPT) { - rl2_data_write_1(sc, (len >> 8) & 0xff); - rl2_status_tx_write(sc, RL2_STATUS_TX_HILEN_AVAIL); - s = spl0(); - for (i = 0; i < 600; i++) { - status = rl2_status_tx_read(sc); - if (status == RL2_STATUS_TX_HILEN_ACCEPT || - status == RL2_STATUS_TX_ERROR) - break; - DELAY(1000); - } - splx(s); - dprintf(" %dms", i); - if (status == RL2_STATUS_TX_HILEN_ACCEPT) - goto success; - if (status == RL2_STATUS_TX_ERROR) - goto error; - } - } -#ifdef DIAGNOSTIC - else - panic("rln: bus width"); -#endif - - printf("%s: tx_request timed out, status 0x%02x", - sc->sc_dev.dv_xname, status); - dprintf("]=(1)"); - return (1); - -error: - /* Will need to clear nak within 100 ms. */ - dprintf("]=2"); -#ifdef DIAGNOSTIC - printf("%s: tx protocol fault (nak)\n", sc->sc_dev.dv_xname); -#endif - return (2); - -success: - /* rl2_wakeup(sc, w); */ - dprintf("]=0"); - return (0); -} - -/* - * Performs the third (and final) stage of transmitting a command - * message to the card. - * Returns: 0 on command success. - * non-zero on failure (card will need reset) - */ -static int -rl2_tx_end(sc) - struct rl2_softc * sc; -{ - /* EndOfTx() */ - int i; - int s; - u_int8_t status; - - dprintf(" Te["); - s = spl0(); - for (i = 0; i < 600; i++) { - status = rl2_status_tx_read(sc); - if (status == RL2_STATUS_TX_XFR_COMPLETE) - break; - DELAY(1000); - } - splx(s); - if (status == RL2_STATUS_TX_XFR_COMPLETE) { - rl2_status_tx_write(sc, RL2_STATUS_TX_IDLE); - dprintf("]=0"); - return (0); - } else { - printf("%s: tx cmd failed (%02x)\n", sc->sc_dev.dv_xname, - status); - rl2_need_reset(sc); - dprintf("]=-1"); - return (-1); - } -} - -/* - * Performs first (request) stage of receiving a message from the card. - * Returns: 0 on failure, - * n>0 on success, where 'n' is the length of the message - */ - -int -rl2_rx_request(sc, timeo) - struct rl2_softc * sc; - int timeo; /* milliseconds */ -{ - /* RxRequest */ - int s; - int len = 0; - int i; - u_int8_t status; - u_int8_t hi, lo; - - dprintf(" Rr["); - status = rl2_status_rx_read(sc); - - /* Short wait for states 1|5|6. */ - s = spl0(); - for (i = 0; i < timeo; i++) { - if (status == RL2_STATUS_RX_LOLEN_AVAIL || - status == RL2_STATUS_RX_HILEN_AVAIL || - status == RL2_STATUS_RX_ERROR) - break; - DELAY(1000); - status = rl2_status_rx_read(sc); - } - splx(s); - dprintf(" (%dms)",i); - - if (sc->sc_width == 16) { - if (status != RL2_STATUS_RX_HILEN_AVAIL) - goto badstatus_quiet; - /* Read 2 octets. */ - len = rl2_data_read_2(sc); - } else if (sc->sc_width == 8) { - if (status != RL2_STATUS_RX_LOLEN_AVAIL) - goto badstatus_quiet; - /* Read low octet. */ - lo = rl2_data_read_1(sc); - rl2_status_rx_write(sc, RL2_STATUS_RX_LOLEN_ACCEPT); - rl2_status_rx_int(sc); - s = spl0(); - for (i = 0; i < 600; i++) { - status = rl2_status_rx_read(sc); - if (status == RL2_STATUS_RX_HILEN_AVAIL) - break; - DELAY(1000); - } - splx(s); - if (status != RL2_STATUS_RX_HILEN_AVAIL) - goto badstatus; - /* Read high octet. */ - hi = rl2_data_read_1(sc); - len = lo | (hi << 8); - } -#ifdef DIAGNOSTIC - else - panic("rl2: bus width %d", sc->sc_width); -#endif - - dprintf(" len=%d]", len); - return (len); - -badstatus: - printf("%s: rx_request timed out, status %02x\n", - sc->sc_dev.dv_xname, status); -badstatus_quiet: - if (status == RL2_STATUS_RX_ERROR) - printf("%s: rx protocol error (nak)\n", sc->sc_dev.dv_xname); - dprintf("]"); - return (-1); -} - -/* Performs part of the second (transfer) stage of receiving a data message. */ -void -rl2_rx_pdata(sc, buf, len, pd) - struct rl2_softc * sc; - void * buf; - int len; - struct rl2_pdata * pd; -{ - char * data = (char *)buf; - - if (pd->p_nremain) { - *data++ = pd->p_data; - if (--len == 0) - return; - } - - pd->p_nremain = 0; - - if (sc->sc_width == 16) { - /* Round down to the closest even multiple. */ - rl2_data_read_multi_2(sc, data, len / 2); -#ifdef RL2DEBUG_REG - dprintf(" D>"); - dprinthex(data, len); -#endif - if (len & 1) { - /* Read the last octet plus a bit extra. */ - union { - u_int16_t w; - u_int8_t b[2]; - } u; - - u.w = rl2_data_read_2(sc); - data[len - 1] = u.b[0]; - pd->p_data = u.b[1]; - pd->p_nremain = 1; -#ifdef RL2DEBUG_REG - dprintf(" D>{%02x%02x}", u.b[0], u.b[1]); -#endif - } - } else if (sc->sc_width == 8) { - rl2_data_read_multi_1(sc, data, len); -#ifdef RL2DEBUG_REG - dprintf(" D>"); - dprinthex(data, len); -#endif - if (len & 1) { - /* Must read multiples of two. */ - pd->p_data = rl2_data_read_1(sc); - pd->p_nremain = 1; -#ifdef RL2DEBUG_REG - dprintf(" D>{%02x}", pd->p_data); -#endif - } - } - -} - -int -rl2_rx_data(sc, buf, len) - struct rl2_softc * sc; - void * buf; - int len; -{ - /* RxData() */ - struct rl2_pdata pd = { 0, 0 }; - int s; - int i; - u_int8_t status; - - dprintf(" Rd["); - rl2_status_rx_write(sc, RL2_STATUS_RX_HILEN_ACCEPT); - rl2_status_rx_int(sc); - s = spl0(); - for (i = 0; i < 600; i++) { - status = rl2_status_rx_read(sc); - if (status == RL2_STATUS_RX_XFR) - break; - DELAY(1000); - } - splx(s); - if (status != RL2_STATUS_RX_XFR) { - dprintf("]=-1"); - return (-1); - } - - rl2_rx_pdata(sc, buf, len, &pd); -#ifdef DIAGNOSTIC - /* We should have nothing left over. */ - if (pd.p_nremain || len & 1) - panic("rl2_rx_data: leftover"); -#endif - - dprintf("]=0"); - return (0); -} - -void -rl2_rx_end(sc) - struct rl2_softc * sc; -{ - /* EndOfRx() */ - - dprintf(" Re["); - rl2_status_rx_write(sc, RL2_STATUS_RX_XFR_COMPLETE); - rl2_status_rx_int(sc); - /* rl2_wakeup(sc, 0); */ - dprintf("]"); -} - -/* Clear a transmission NAK from the card. */ -void -rl2_clear_nak(sc) - struct rl2_softc * sc; -{ - /* ClearNAK() */ - - rl2_status_tx_write(sc, RL2_STATUS_CLRNAK); - rl2_status_tx_int(sc); -} - -/* - * Send a command message to the card. Returns; - * 2: NAK - * -1: failure - * 0: success - */ -int -rl2_msg_tx_start(sc, buf, pktlen, state) - struct rl2_softc * sc; - void * buf; - int pktlen; - struct rl2_msg_tx_state * state; -{ - struct rl2_mm_cmd * cmd = (struct rl2_mm_cmd *)buf; - int ret; - - state->ien = rl2_enable(sc, 0); - state->pd.p_nremain = 0; - - if (!(cmd->cmd_letter == 'A' && cmd->cmd_fn == 6)) /* Standby. */ - state->w = rl2_wakeup(sc, RL2_WAKEUP_SET); - else - state->w = RL2_WAKEUP_NOCHANGE; - - ret = rl2_tx_request(sc, pktlen); - if (ret == 2) { - rl2_clear_nak(sc); - if (sc->sc_cardtype & RL2_CTYPE_OEM) - rl2_need_reset(sc); - ret = 2; - } - else if (ret == 1) { - /* Timeout. */ - rl2_status_tx_write(sc, RL2_STATUS_TX_XFR); - ret = -1; - } - return (ret); -} - -void -rl2_msg_tx_data(sc, buf, len, state) - struct rl2_softc * sc; - void * buf; - u_int16_t len; - struct rl2_msg_tx_state * state; -{ - char * data = (char *)buf; - - if (sc->sc_width == 16 && state->pd.p_nremain) { - /* XXX htons() needed? */ - union { - u_int8_t b[2]; - u_int16_t w; - } u; - - u.b[0] = state->pd.p_data; - if (len) { - u.b[1] = *data++; - len--; - } else - u.b[1] = '\0'; -#ifdef RL2DEBUG_REG - dprintf(" D<%02x%02x", u.b[0], u.b[1]); -#endif - rl2_data_write_2(sc, u.w); - state->pd.p_nremain = 0; - } - - if (len) { - if (sc->sc_width == 16) { - if (len >= 2) - rl2_data_write_multi_2(sc, buf, len / 2); - if (len & 1) { - state->pd.p_nremain = 1; - state->pd.p_data = data[len - 1]; - } - } else if (sc->sc_width == 8) - rl2_data_write_multi_1(sc, buf, len); -#ifdef DIAGNOSTIC - else - panic("rl2_msg_tx_data width %d", sc->sc_width); -#endif -#ifdef RL2DEBUG_REG - dprintf(" D<"); - dprinthex(data, len); -#endif - } -} - - -int -rl2_msg_tx_end(sc, state) - struct rl2_softc * sc; - struct rl2_msg_tx_state * state; -{ - int ret; - - /* Flush the tx buffer. */ - if (state->pd.p_nremain) - rl2_msg_tx_data(sc, NULL, 0, state); - -#ifdef DIAGNOSTIC - if (state->pd.p_nremain) - panic("rl2_msg_tx_end remain %d", state->pd.p_nremain); -#endif - ret = rl2_tx_end(sc); - if (sc->sc_arpcom.ac_if.if_flags & IFF_OACTIVE) - state->w = RL2_WAKEUP_NOCHANGE; - rl2_wakeup(sc, state->w); - rl2_enable(sc, state->ien); - return (ret); -} - -/* Return the next unique sequence number to use for a transmitted command */ -u_int8_t -rl2_newseq(sc) - struct rl2_softc * sc; -{ - int s; - u_int8_t seq; - - s = splhigh(); - seq = sc->sc_pktseq++; - if (sc->sc_pktseq > RL2_MAXSEQ) - sc->sc_pktseq = 0; - splx(s); - return (seq); -} - -/* - * Transmit a command message to, and (optionally) receive a response - * message from the card. Each transmitted message has a sequence - * number, and corresponding reply messages have the same sequence - * number. We use the sequence numbers to index the mailboxes so - * that rl2softintr() can signal this routine when it has serviced - * and correctly received a response. - */ - -int -rl2_msg_txrx(sc, tx, txlen, rx, rxlen) - struct rl2_softc * sc; - void * tx; - int txlen; - void * rx; - int rxlen; -{ - struct rl2_mm_cmd * txc = (struct rl2_mm_cmd *)tx; - struct rl2_mm_cmd * rxc = (struct rl2_mm_cmd *)rx; - struct rl2_msg_tx_state state; - int ien; - int ret; - -#ifdef DIAGNOSTIC - if (rx != NULL && rxlen < sizeof *rxc) - panic("rl2_msg_txrx"); -#endif - - txc->cmd_seq = rl2_newseq(sc); - -#ifdef RL2DUMP - printf("%s: send %c%d seq %d data ", sc->sc_dev.dv_xname, - txc->cmd_letter, txc->cmd_fn, txc->cmd_seq); - RL2DUMPHEX(txc, sizeof *txc); - printf(":"); - RL2DUMPHEX((char *)tx + sizeof *txc, txlen - sizeof *txc); - printf("\n"); -#endif - - if (rx != NULL) - if (rl2_mbox_create(sc, txc->cmd_seq, rx, rxlen) < 0) - /* Mailbox collision. */ - return (-1); - - /* Start the transfer. */ - if ((ret = rl2_msg_tx_start(sc, tx, txlen, &state))) { - if (rx != NULL) - rl2_mbox_wait(sc, txc->cmd_seq, -1); - return (ret); - } - - /* Always send an even number of octets. */ - rl2_msg_tx_data(sc, tx, (txlen + 1) & ~1, &state); - - /* End the transmission. */ - if ((ret = rl2_msg_tx_end(sc, &state))) { - /* Destroy mailbox. */ - if (rx != NULL) - rl2_mbox_wait(sc, txc->cmd_seq, -1); - return (ret); - } - - /* Don't wait for reply if there is nowhere to put it. */ - if (rx == NULL) - return (0); - - /* Enable interrupts if not already. */ - ien = rl2_enable(sc, 1); - - /* Wait for the reply message. */ - if (rl2_mbox_wait(sc, txc->cmd_seq, 2000) <= 0) { - printf("%s: lost message %c%d seq %d\n", sc->sc_dev.dv_xname, - txc->cmd_letter, txc->cmd_fn, txc->cmd_seq); - rl2_enable(sc, ien); - return (-1); - } - rl2_enable(sc, ien); - -#ifdef RL2DUMP - printf("%s: recv %c%d seq %d data ", sc->sc_dev.dv_xname, - rxc->cmd_letter, rxc->cmd_fn, rxc->cmd_seq); - RL2DUMPHEX(rxc, sizeof *rxc); - printf(":"); - RL2DUMPHEX(((char *)rx) + sizeof *rxc, rxlen - sizeof *rxc); - printf("\n"); -#endif - - /* Check for errors in the received message. */ - if (rxc->cmd_error & 0x80) { - printf("%s: command error 0x%02x command %c%d\n", - sc->sc_dev.dv_xname, - rxc->cmd_error & ~0x80, - rxc->cmd_letter, rxc->cmd_fn); - return (-1); - } - - return (0); -} - -/* - * Mailboxes provide a simple way to tell the interrupt - * service routine that someone is expecting a reply message. - * Mailboxes are identified by the message sequence number - * and also hold a pointer to storage supplied by the waiter. - * The interrupt service routine signals the mailbox when it - * gets the reply message. - */ - -/* Create a mailbox for filling. */ -int -rl2_mbox_create(sc, seq, buf, len) - struct rl2_softc * sc; - u_int8_t seq; - void * buf; - size_t len; -{ - int s; - struct rl2_mbox * mb = &sc->sc_mbox[seq]; - - dprintf(" RL2_NMBOX) - panic("mbox create"); -#endif - - s = splhigh(); - if (mb->mb_state != RL2MBOX_VOID) { -#ifdef DIAGNOSTIC - printf("mbox collision"); -#endif - splx(s); - return (-1); - } - mb->mb_buf = buf; - mb->mb_len = len; - mb->mb_actlen = 0; - mb->mb_state = RL2MBOX_EMPTY; - dprintf(" empty>"); - splx(s); - return (0); -} - - -/* Wait for a mailbox to be filled. */ -int -rl2_mbox_wait(sc, seq, timeo) - struct rl2_softc * sc; - u_int8_t seq; - int timeo; -{ - int i; - int s; - int ret; - volatile struct rl2_mbox * mb = &sc->sc_mbox[seq]; - extern int cold; - - dprintf(" RL2_NMBOX) - panic("mbox wait"); -#endif - if (cold) { - /* Autoconfiguration - spin at spl0. */ - s = spl0(); - i = 0; - while (mb->mb_state == RL2MBOX_EMPTY && i < timeo) { - DELAY(1000); - i++; - } - if (i) - dprintf(" %dms", i); - while (mb->mb_state == RL2MBOX_FILLING) - ; - splx(s); - } else { - tsleep((void *)mb, PRIBIO, "rl2mbox", hz * timeo / 1000); - if (mb->mb_state == RL2MBOX_FILLING) { - /* Must wait until filled. */ - s = spl0(); - while (mb->mb_state == RL2MBOX_FILLING) - ; - splx(s); - } - } - - s = splhigh(); -#ifdef DIAGNOSTIC - if (mb->mb_state != RL2MBOX_EMPTY && mb->mb_state != RL2MBOX_FILLED) - panic("mbox wait %d", mb->mb_state); -#endif - ret = mb->mb_actlen; - mb->mb_state = RL2MBOX_VOID; - dprintf(" void>=%d", ret); - splx(s); - return (ret); -} - -/* Lock a mailbox for filling. */ -int -rl2_mbox_lock(sc, seq, bufp, lenp) - struct rl2_softc * sc; - u_int8_t seq; - void ** bufp; - size_t * lenp; -{ - int s; - struct rl2_mbox * mb = &sc->sc_mbox[seq]; - - dprintf(" RL2_NMBOX) - panic("mbox lock"); -#endif - if (mb->mb_state != RL2MBOX_EMPTY) { - splx(s); - dprintf(" ?>"); - return (-1); - } - - mb->mb_state = RL2MBOX_FILLING; - dprintf(" filling>"); - *bufp = mb->mb_buf; - *lenp = mb->mb_len; - - splx(s); - return (0); -} - -/* Unlock a mailbox and inform the waiter of the actual number of octets. */ -void -rl2_mbox_unlock(sc, seq, actlen) - struct rl2_softc * sc; - u_int8_t seq; - size_t actlen; -{ - int s; - struct rl2_mbox * mb = &sc->sc_mbox[seq]; - - dprintf(" RL2_NMBOX) - panic("mbox unlock seq"); - if (mb->mb_state != RL2MBOX_FILLING) - panic("mbox unlock"); -#endif - mb->mb_state = RL2MBOX_FILLED; - dprintf(" filled>"); - mb->mb_actlen = actlen; - wakeup(mb); - splx(s); -} - diff --git a/sys/dev/ic/rl2var.h b/sys/dev/ic/rl2var.h deleted file mode 100644 index be369148f92..00000000000 --- a/sys/dev/ic/rl2var.h +++ /dev/null @@ -1,141 +0,0 @@ -/* $OpenBSD: rl2var.h,v 1.3 1999/07/14 03:54:38 d Exp $ */ -/* - * David Leonard , 1999. Public domain. - * - * Proxim RangeLAN2 soft state copy. - */ - -/* - * Mailboxes are used to communicate card-initiated messages - * from the interrupt handler to other kernel threads. - */ -struct rl2_mbox { - void * mb_buf; /* Message buffer */ - size_t mb_len; /* Message buffer size */ - size_t mb_actlen; /* Actual message size */ - u_int8_t mb_state; /* Mailbox state */ -#define RL2MBOX_VOID 0 -#define RL2MBOX_EMPTY 1 -#define RL2MBOX_FILLING 2 -#define RL2MBOX_FILLED 3 -}; - -#define RL2_NMBOX 0x7c /* Same as max msg seq number */ - -/* Soft state */ -struct rl2_softc { - struct device sc_dev; - void *sc_ih; /* Interrupt handler */ - struct arpcom sc_arpcom; /* Ethernet common part */ - bus_space_tag_t sc_iot; /* Bus cookie */ - bus_space_handle_t sc_ioh; /* Bus i/o handle */ - - u_int8_t sc_width; /* Bus transfer width */ - u_int8_t sc_irq; /* IRQ for card */ - - u_int16_t sc_cardtype; /* Set from config flags */ -#define RL2_CTYPE_OEM 0x01 -#define RL2_CTYPE_UISA 0x02 -#define RL2_CTYPE_ONE_PIECE 0x04 - - u_int8_t sc_intsel; /* Copy of INTSEL */ - u_int8_t sc_status; /* Copy of STATUS */ - u_int8_t sc_control; /* Copy of CONTROL */ -#ifdef RL2DEBUG_REG - u_int8_t dbg_oreg[8]; /* Last reg value written */ -#endif - - u_int8_t sc_pktseq; /* Card message seq no */ - u_int8_t sc_txseq; /* Tx packet seq no */ - - u_int16_t sc_state; /* Soft state. */ -#define RL2_STATE_SYNC 0x0001 /* Card is synchronised */ -#define RL2_STATE_NEEDINIT 0x0002 /* Card needs reset+init */ -#define RL2_STATE_PROMISC 0x0004 /* Receive all packets */ - - struct rl2_mbox sc_mbox[0x80]; /* Per-message mailboxes */ - struct rl2_param sc_param; /* User controlled parameters */ -}; - -#define rl2_need_reset(sc) \ - (sc)->sc_state |= RL2_STATE_NEEDINIT - -/* Structure used to hold partial read state for rl2_rx_pdata() */ -struct rl2_pdata { - u_int8_t p_data; /* extra data read but not consumed */ - int p_nremain; /* size of unconsumed data */ -}; -#define RL2_PDATA_INIT {0,0} - -/* Structure used to hold partial transmit state for rl2_msg_tx_*() */ -struct rl2_msg_tx_state { - int ien; /* saved interrupt state */ - u_int8_t w; /* saved wakup state */ - struct rl2_pdata pd; /* saved partial write state */ -}; - -struct rl2_mm_cmd; /* fwd decl */ - -#define RL2_WAKEUP_SET 0xff -#define RL2_WAKEUP_NOCHANGE (0x80|0x10) - -void rl2config __P((struct rl2_softc *)); -int rl2intr __P((void *)); -void rl2read __P((struct rl2_softc *, struct rl2_mm_cmd *, int)); -int rl2_enable __P((struct rl2_softc *, int)); -int rl2_reset __P((struct rl2_softc *)); -u_int8_t rl2_wakeup __P((struct rl2_softc *, u_int8_t)); -int rl2_rx_request __P((struct rl2_softc *, int)); -int rl2_rx_data __P((struct rl2_softc *, void *, int)); -void rl2_rx_pdata __P((struct rl2_softc *, void *, int, - struct rl2_pdata *)); -void rl2_rx_end __P((struct rl2_softc *)); -void rl2_clear_nak __P((struct rl2_softc *)); -u_int8_t rl2_newseq __P((struct rl2_softc *)); - -void rl2_msg_tx_data __P((struct rl2_softc *, void *, u_int16_t, - struct rl2_msg_tx_state *)); -int rl2_msg_tx_start __P((struct rl2_softc *, void *, int, - struct rl2_msg_tx_state *)); -int rl2_msg_tx_end __P((struct rl2_softc *, - struct rl2_msg_tx_state *)); -int rl2_msg_txrx __P((struct rl2_softc *, void *, int, - void *, int)); - -int rl2_mbox_create __P((struct rl2_softc *, u_int8_t, void *, - size_t)); -int rl2_mbox_wait __P((struct rl2_softc *, u_int8_t, int)); -int rl2_mbox_lock __P((struct rl2_softc *, u_int8_t, void **, - size_t*)); -void rl2_mbox_unlock __P((struct rl2_softc *, u_int8_t, size_t)); - -/* debug all card operations */ -#ifdef RL2DEBUG -#define dprintf(fmt, args...) printf(fmt , ## args) - /* log(LOG_DEBUG, fmt , ## args) */ -#define dprinthex(buf, len) do { \ - unsigned char *_b = (unsigned char*)(buf); \ - int _i, _l=(len); \ - printf("{"); \ - for(_i = 0; _i < _l; _i++) { \ - printf("%02x", _b[_i]); \ - if (_i % 4 == 3 && _i != _l - 1) \ - printf(","); \ - } \ - printf("}"); \ -} while (0) -#else -#define dprintf(fmt, args...) /* nothing */ -#define dprinthex(buf, len) /* nothing */ -#endif - -/* debug messages to/from card. prints 4-octet groups separated by commas */ -#define RL2DUMP -#define RL2DUMPHEX(buf, buflen) do { \ - int _i; \ - for (_i = 0; _i < (buflen); _i++) { \ - printf("%02x", ((unsigned char *)(buf))[_i]); \ - if (_i != (buflen) - 1 && _i % 4 == 3) \ - printf(","); \ - } \ -} while (0) diff --git a/sys/dev/ic/rln.c b/sys/dev/ic/rln.c new file mode 100644 index 00000000000..1c2b2e5ffbb --- /dev/null +++ b/sys/dev/ic/rln.c @@ -0,0 +1,1163 @@ +/* $OpenBSD: rln.c,v 1.1 1999/07/30 13:43:36 d Exp $ */ +/* + * David Leonard , 1999. Public Domain. + * + * Driver for the Proxim RangeLAN2 wireless network adaptor. + * + * Information and ideas gleaned from disassembly of Dave Koberstein's + * Linux driver (apparently based on Proxim source), + * from Yoichi Shinoda's BSDI driver, and + * Geoff Voelker's Linux port of the same. + * + */ + +#include "bpfilter.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef INET +#include +#include +#endif + +#if NBPFILTER > 0 +#include +#include +#endif + +#include +#include + +#include +#include +#include +#include + +/* Autoconfig definition of driver back-end. */ +struct cfdriver rln_cd = { + NULL, "rln", DV_IFNET +}; + +static void rlninit __P((struct rln_softc *)); +static void rlnstart __P((struct ifnet*)); +static void rlnwatchdog __P((struct ifnet*)); +static int rlnioctl __P((struct ifnet *, u_long, caddr_t)); +static int rln_probe __P((struct rln_softc *)); +static void rlnstop __P((struct rln_softc *)); + +/* Interrupt handler. */ +static void rlnsoftintr __P((void *)); + +/* Packet I/O. */ +static int rln_transmit __P((struct rln_softc *, struct mbuf *, + int, int)); +static struct mbuf * rlnget __P((struct rln_softc *, struct rln_mm_cmd *, + int)); + +/* Card protocol-level functions. */ +static int rln_getenaddr __P((struct rln_softc *, u_int8_t *)); +static int rln_getpromvers __P((struct rln_softc *, char *, int)); +static int rln_sendinit __P((struct rln_softc *)); +#if notyet +static int rln_roamconfig __P((struct rln_softc *)); +static int rln_roam __P((struct rln_softc *)); +static int rln_multicast __P((struct rln_softc *, int)); +static int rln_searchsync __P((struct rln_softc *)); +static int rln_iosetparam __P((struct rln_softc *, struct rln_param *)); +static int rln_lockprom __P((struct rln_softc *)); +static int rln_ito __P((struct rln_softc *)); +static int rln_standby __P((struct rln_softc *)); +#endif + +/* Back-end attach and configure. */ +void +rlnconfig(sc) + struct rln_softc * sc; +{ + struct ifnet * ifp = &sc->sc_arpcom.ac_if; + char promvers[7]; + int i; + + dprintf(" [attach %p]", sc); + + /* Use the flags supplied from config. */ + sc->sc_cardtype |= sc->sc_dev.dv_cfdata->cf_flags; + + /* Initialise values in the soft state. */ + sc->sc_pktseq = 0; /* rln_newseq() */ + sc->sc_txseq = 0; + + /* Initialise user-configurable params. */ + sc->sc_param.rp_roam_config = RLN_ROAM_NORMAL; + sc->sc_param.rp_security = RLN_SECURITY_DEFAULT; + sc->sc_param.rp_station_type = RLN_STATIONTYPE_ALTMASTER; + sc->sc_param.rp_domain = 0; + sc->sc_param.rp_channel = 1; + sc->sc_param.rp_subchannel = 1; + + bzero(sc->sc_param.rp_master, sizeof sc->sc_param.rp_master); + + /* Initialise the message mailboxes. */ + for (i = 0; i < RLN_NMBOX; i++) + sc->sc_mbox[i].mb_state = RLNMBOX_VOID; + + /* Keep the sys admin informed. */ + printf(", %s-piece", + (sc->sc_cardtype & RLN_CTYPE_ONE_PIECE) ? "one" : "two"); + if (sc->sc_cardtype & RLN_CTYPE_OEM) + printf(" oem"); + if (sc->sc_cardtype & RLN_CTYPE_UISA) + printf(" micro-isa"); + + /* Probe/reset the card. */ + if (rln_probe(sc)) + return; + + /* Read the card's PROM revision. */ + if (rln_getpromvers(sc, promvers, sizeof promvers)) { + printf(": could not read PROM version\n"); + return; + } + printf(", fw %.7s", promvers); + + /* Fetch the card's MAC address. */ + if (rln_getenaddr(sc, sc->sc_arpcom.ac_enaddr)) { + printf(": could not read MAC address\n"); + return; + } + printf(", addr %s", ether_sprintf(sc->sc_arpcom.ac_enaddr)); + + /* Attach as a network interface. */ + bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); + ifp->if_softc = sc; + ifp->if_start = rlnstart; + ifp->if_ioctl = rlnioctl; + ifp->if_watchdog = rlnwatchdog; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS; + if_attach(ifp); + ether_ifattach(ifp); +#if NBPFILTER > 0 + bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof (struct ether_header)); +#endif +} + +/* Bring device up. */ +static void +rlninit(sc) + struct rln_softc * sc; +{ + /* LLDInit() */ + struct ifnet * ifp = &sc->sc_arpcom.ac_if; + int s; + extern int cold; + + dprintf(" [init]"); + + sc->sc_intsel = 0; + sc->sc_status = 0; + sc->sc_control = 0; + ifp->if_flags &= ~IFF_RUNNING; + ifp->if_flags &= ~IFF_OACTIVE; + + /* Do a hard reset. */ + if (rln_reset(sc)) { + printf("%s: could not reset card\n", sc->sc_dev.dv_xname); + goto fail; + } + sc->sc_state = 0; /* Also clears RLN_STATE_NEEDINIT. */ + + /* Use this host's name as a master name. */ + if (!cold && sc->sc_param.rp_master[0] == '\0') { + bcopy(hostname, sc->sc_param.rp_master, + min(hostnamelen, sizeof sc->sc_param.rp_master)); + } + + rln_enable(sc, 1); + + /* Initialise operational params. */ + if (rln_sendinit(sc)) { + printf("%s: could not set card parameters\n", + sc->sc_dev.dv_xname); + goto fail; + } +#if 0 + rln_roamconfig(sc); + /* rln_lockprom(sc); */ /* XXX error? */ + + /* SendSetITO() */ + + rln_multicast(sc, 1); + rln_roam(sc); + + /* Synchronise with something. */ + rln_searchsync(sc); +#endif + s = splnet(); + ifp->if_flags |= IFF_RUNNING; + rlnstart(ifp); + splx(s); + + return; + + fail: + ifp->if_flags &= ~IFF_UP; + return; +} + +/* Start outputting on interface. This is always called at splnet(). */ +static void +rlnstart(ifp) + struct ifnet * ifp; +{ + struct rln_softc * sc = (struct rln_softc *)ifp->if_softc; + struct mbuf * m0; + int len, pad, ret; + + dprintf(" start["); + + if (sc->sc_state & RLN_STATE_NEEDINIT) + rlninit(sc); + + /* Don't transmit if interface is busy or not running. */ + if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) { + dprintf(" %s] ", (ifp->if_flags & IFF_OACTIVE) ? + "busy" : "stopped"); + return; + } + + /* Don't transmit if we are not synchronised. */ + if ((sc->sc_state & RLN_STATE_SYNC) == 0) { + dprintf(" nosync]"); + return; + } + + startagain: + IF_DEQUEUE(&ifp->if_snd, m0); + + if (m0 == NULL) { + dprintf(" empty]"); + return; + } + +#if NBPFILTER > 0 + /* Tap packet stream here for BPF listeners. */ + if (ifp->if_bpf) + bpf_mtap(ifp->if_bpf, m0); +#endif + + /* We need to use m->m_pkthdr.len, so require the header. */ + if ((m0->m_flags & M_PKTHDR) == 0) { + printf("%s: no mbuf header\n", sc->sc_dev.dv_xname); + goto oerror; + } + + len = m0->m_pkthdr.len; + +#define PACKETMIN (sizeof (struct ether_header) + ETHERMIN) +#define PACKETMAX (sizeof (struct ether_header) + ETHERMTU + 4) + + /* Packet size has to be an even number between 60 and 1518 octets. */ + pad = len & 1; + if (len + pad < PACKETMIN) + pad = PACKETMIN - len; + + if (len + pad > PACKETMAX) { + printf("%s: packet too big (%d > %d)\n", + sc->sc_dev.dv_xname, len + pad, + PACKETMAX); + ++ifp->if_oerrors; + m_freem(m0); + goto startagain; + } + + ret = rln_transmit(sc, m0, len, pad); + if (ret) + goto oerror; + + ifp->if_flags |= IFF_OACTIVE; + m_freem(m0); + + dprintf(" sent]"); + return; + +oerror: + ++ifp->if_oerrors; + m_freem(m0); + rln_need_reset(sc); + return; +} + +/* Transmit one packet. */ +static int +rln_transmit(sc, m0, len, pad) + struct rln_softc * sc; + struct mbuf * m0; + int len; + int pad; +{ + struct mbuf * m; + int zfirst; + int actlen; + int tlen = len + pad; + struct rln_msg_tx_state state; + static u_int8_t zeroes[60]; + struct rln_mm_sendpacket cmd = { RLN_MM_SENDPACKET }; + + /* Does the packet start with a zero bit? */ + zfirst = ((*mtod(m0, u_int8_t *) & 1) == 0); + + cmd.mode = + RLN_MM_SENDPACKET_MODE_BIT7 | + (zfirst ? RLN_MM_SENDPACKET_MODE_ZFIRST : 0) | + (0 ? RLN_MM_SENDPACKET_MODE_QFSK : 0), /* sc->qfsk? */ + cmd.power = 0x70; /* 0x70 or 0xf0 */ + cmd.length_lo = htons(4 + tlen) & 0xff; + cmd.length_hi = (htons(4 + tlen) >> 8) & 0xff; + cmd.xxx1 = 0; + cmd.xxx2 = 0; + cmd.xxx3 = 0; + + /* A unique packet-level sequence number. XXX related to sc_seq? */ + cmd.sequence = sc->sc_txseq; + sc->sc_txseq++; + if (sc->sc_txseq > RLN_MAXSEQ) + sc->sc_txseq = 0; + + dprintf(" T[%d+%d", len, pad); + + if (rln_msg_tx_start(sc, &cmd, sizeof cmd + tlen, &state)) + goto error; + + cmd.mm_cmd.cmd_seq = rln_newseq(sc); + +#ifdef RLNDUMP + printf("%s: send %c%d seq %d data ", sc->sc_dev.dv_xname, + cmd.mm_cmd.cmd_letter, cmd.mm_cmd.cmd_fn, cmd.mm_cmd.cmd_seq); + RLNDUMPHEX(&cmd, sizeof cmd); + printf(":"); +#endif + rln_msg_tx_data(sc, &cmd, sizeof cmd, &state); + + actlen = 0; + for (m = m0; m; m = m->m_next) { + if (m->m_len) { +#ifdef RLNDUMP + RLNDUMPHEX(mtod(m, void *), m->m_len); + printf("|"); +#endif + rln_msg_tx_data(sc, mtod(m, void *), m->m_len, &state); + } + actlen += m->m_len; + } +#ifdef DIAGNOSTIC + if (actlen != len) + panic("rln_transmit: len %d != %d", actlen, len); + if (pad > sizeof zeroes) + panic("rln_transmit: pad %d > %d", pad, sizeof zeroes); +#endif + if (pad) { +#ifdef RLNDUMP + RLNDUMPHEX(zeroes, pad); +#endif + rln_msg_tx_data(sc, zeroes, pad, &state); + } + +#ifdef RLNDUMP + printf("\n"); +#endif + if (rln_msg_tx_end(sc, &state)) + goto error; + return (0); + + error: + dprintf(" error]"); + return (-1); +} + +/* (Supposedly) called when interrupts are suspiciously absent. */ +static void +rlnwatchdog(ifp) + struct ifnet * ifp; +{ + struct rln_softc * sc = (struct rln_softc *)ifp->if_softc; + + log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname); + ++sc->sc_arpcom.ac_if.if_oerrors; + rlninit(sc); + rln_enable(sc, 1); +} + +/* Handle single card interrupt. */ +int +rlnintr(arg) + void * arg; +{ + struct rln_softc * sc = (struct rln_softc *)arg; + extern int cold; + + dprintf("!"); + + /* Tell card not to interrupt any more. */ + rln_enable(sc, 0); + + if (cold) + /* During autoconfig - must handle interrupts now. */ + rlnsoftintr(sc); + else + /* Handle later. */ + timeout(rlnsoftintr, sc, 1); + + return (1); +} + +/* Process earlier card interrupt at splnetintr. */ +static void +rlnsoftintr(arg) + void * arg; +{ + struct rln_softc *sc = (struct rln_softc *)arg; + struct ifnet *ifp = &sc->sc_arpcom.ac_if; + int len; + u_int8_t w; + struct rln_mm_cmd hdr; + + dprintf(" si("); + + again: + /* Save wakeup state. */ + w = rln_wakeup(sc, RLN_WAKEUP_SET); + + if ((len = rln_rx_request(sc, 300)) < 0) { + /* Error in transfer. */ + rln_need_reset(sc); + rln_rx_end(sc); + } else if (len < sizeof hdr) { + /* Short message. */ + rln_rx_end(sc); + printf("%s: short msg (%d)\n", sc->sc_dev.dv_xname, len); + ifp->if_ierrors++; + } else { + /* Valid message: read header and process. */ + rln_rx_data(sc, &hdr, sizeof hdr); + rlnread(sc, &hdr, len); + } + + /* Ensure that wakeup state is unchanged if transmitting. */ + if (ifp->if_flags & IFF_OACTIVE) + w |= RLN_WAKEUP_NOCHANGE; + rln_wakeup(sc, w); + + /* Check for more interrupts. */ + if (rln_status_rx_ready(sc)) { + if (rln_status_rx_read(sc) == RLN_STATUS_RX_ERROR) { +#ifdef DIAGNOSTIC + printf("%s: protocol error\n", sc->sc_dev.dv_xname); +#endif + DELAY(100 * 1000); /* XXX */ + rln_clear_nak(sc); + } else { +#ifdef DIAGNOSTIC + printf("%s: intr piggyback\n", sc->sc_dev.dv_xname); +#endif + goto again; + } + } + + /* Some cards need this? */ + rln_eoi(sc); + + /* Re-enable card. */ + rln_enable(sc, 1); + + dprintf(")"); +} + +/* Read and process a message from the card. */ +void +rlnread(sc, hdr, len) + struct rln_softc *sc; + struct rln_mm_cmd *hdr; + int len; +{ + struct ifnet *ifp = &sc->sc_arpcom.ac_if; + struct mbuf *m; + struct ether_header *eh; + u_int8_t data[1538]; + u_int8_t *buf; + size_t buflen; + struct rln_pdata pd = RLN_PDATA_INIT; + struct rln_mm_synchronised * syncp = (struct rln_mm_synchronised *)data; + int s; + + dprintf(" [read]"); + + /* Were we waiting for this message? */ + if (rln_mbox_lock(sc, hdr->cmd_seq, (void **)&buf, &buflen) == 0) { +#ifdef DIAGNOSTIC + if (buflen < sizeof *hdr) + panic("rlnread buflen"); +#endif + bcopy(hdr, buf, sizeof *hdr); + buf += sizeof *hdr; + len -= sizeof *hdr; + buflen -= sizeof *hdr; + if (len) { + if (len == buflen) /* Expected size */ + rln_rx_pdata(sc, buf, len, &pd); + else if (len < buflen) { /* Underfill */ +#ifdef DIAGNOSTIC + printf("%s: underfill %d<%d, cmd %c%d\n", + sc->sc_dev.dv_xname, + len, buflen, + hdr->cmd_letter, hdr->cmd_fn); +#endif + rln_rx_pdata(sc, buf, len, &pd); + } else { /* Overflow */ +#ifdef DIAGNOSTIC + printf("%s: overflow %d>%d, cmd %c%d\n", + sc->sc_dev.dv_xname, + len, buflen, + hdr->cmd_letter, hdr->cmd_fn); +#endif + rln_rx_pdata(sc, buf, buflen, &pd); + /* Drain the rest somewhere. */ + rln_rx_pdata(sc, data, len - buflen, &pd); + } + } + rln_rx_end(sc); + + /* This message can now be handled by the waiter. */ + rln_mbox_unlock(sc, hdr->cmd_seq, len + sizeof *hdr); + return; + } + + /* Otherwise, handle the message, right here, right now. */ + + /* Check if we can cope with the size of this message. */ + if (len > sizeof data) { + printf("%s: msg too big (%d)\n", sc->sc_dev.dv_xname, len); + ifp->if_ierrors++; + rln_rx_end(sc); + /* rln_need_reset(sc); */ + return; + } + + /* Check for error results. */ + if (hdr->cmd_error & 0x80) { + printf("%s: command error 0x%02x command %c%d len=%d\n", + sc->sc_dev.dv_xname, + hdr->cmd_error & ~0x80, + hdr->cmd_letter, hdr->cmd_fn, + len); + ifp->if_ierrors++; + rln_rx_end(sc); + rln_need_reset(sc); + return; + } + + /* + * "b1": Receiving a packet is a special case. + * We wish to read the data with pio straight into an + * mbuf to avoid a memory-memory copy. + */ + if (hdr->cmd_letter == 'b' && hdr->cmd_fn == 1) { + m = rlnget(sc, hdr, len); + rln_rx_end(sc); + if (m == NULL) + return; + ifp->if_ipackets++; +#ifdef DIAGNOSTIC + if (bcmp(mtod(m, u_int8_t *), "prox", 4) == 0) { + printf("%s: proxim special packet received\n", + sc->sc_dev.dv_xname); + } +#endif + /* XXX Jean's driver dealt with RFC893 trailers here */ + eh = mtod(m, struct ether_header *); +#if NBPFILTER > 0 + if (ifp->if_bpf) + bpf_mtap(ifp->if_bpf, m); +#endif + m_adj(m, sizeof (struct ether_header)); + ether_input(ifp, eh, m); + return; + } + + + /* Otherwise we read the packet into a buffer on the stack. */ + bcopy(hdr, data, sizeof *hdr); + if (len > sizeof *hdr) + rln_rx_pdata(sc, data + sizeof *hdr, len - sizeof *hdr, &pd); + rln_rx_end(sc); + +#ifdef RLNDUMP + printf("%s: recv %c%d seq %d data ", sc->sc_dev.dv_xname, + hdr->cmd_letter, hdr->cmd_fn, hdr->cmd_seq); + RLNDUMPHEX(hdr, sizeof hdr); + printf(":"); + RLNDUMPHEX(data + sizeof hdr, len - sizeof hdr); + printf("\n"); +#endif + + switch (RLN_MM_CMD(hdr->cmd_letter, hdr->cmd_fn)) { + case RLN_MM_CMD('b', 0): /* b0: Transmit done. */ +#ifdef DIAGNOSTIC + if (len != 7) + printf("%s: 'b0' len %d != 7\n", + sc->sc_dev.dv_xname, len); +#endif + ifp->if_flags &= ~IFF_OACTIVE; + ifp->if_opackets++; + s = splnet(); + rlnstart(ifp); + splx(s); + break; + + case RLN_MM_CMD('a', 20): /* a20: Card fault. */ + printf("%s: hardware fault\n", sc->sc_dev.dv_xname); + break; + + case RLN_MM_CMD('a', 4): /* a4: Sync'd. */ + if (bcmp(syncp->enaddr, sc->sc_arpcom.ac_enaddr, + ETHER_ADDR_LEN) == 0) { + /* Sync'd to own enaddr. */ + /* + * From http://www.proxim.com/support/faq/7400.shtml + * 3. RLNSETUP reports that I'm synchronized to my own MAC address. What + * does that mean? + * You are the acting Master for this network. Either you are + * configured as the Master or as an Alternate Master. If you are an + * Alternate Master, you may be out of range or on a different Domain + * and Security ID from the true Master. + */ + + printf("%s: nothing to sync to; now master ", + sc->sc_dev.dv_xname); + } + else + printf("%s: synchronised to ", sc->sc_dev.dv_xname); + printf("%.11s (%s) channel %d/%d\n", + syncp->mastername, + ether_sprintf(syncp->enaddr), + syncp->channel, + syncp->subchannel); + + /* Record the new circumstances. */ + sc->sc_param.rp_channel = syncp->channel; + sc->sc_param.rp_subchannel = syncp->subchannel; + sc->sc_state |= RLN_STATE_SYNC; + + /* Resume sending. */ + s = splnet(); + rlnstart(ifp); + splx(s); + break; + + case RLN_MM_CMD('a', 5): /* a4: Lost sync. */ + printf("%s: lost sync\n", sc->sc_dev.dv_xname); + sc->sc_state &= ~RLN_STATE_SYNC; + break; + + case RLN_MM_CMD('a', 18): /* a18: Roaming. */ + printf("%s: roaming\n", sc->sc_dev.dv_xname); + break; + default: +#ifdef DIAGNOSTIC + printf("%s: msg `%c%d' seq %d data {", + sc->sc_dev.dv_xname, + hdr->cmd_letter, hdr->cmd_fn, hdr->cmd_seq); + RLNDUMPHEX(hdr, sizeof hdr); + printf(":"); + RLNDUMPHEX(data, len); + printf("}\n"); +#endif + break; + } + +} + +/* Extract a received network packet from the card. */ +static struct mbuf * +rlnget(sc, hdr, totlen) + struct rln_softc *sc; + struct rln_mm_cmd *hdr; + int totlen; +{ + struct ifnet *ifp = &sc->sc_arpcom.ac_if; + int len; + struct mbuf *m, **mp, *top; + struct rln_pdata pd = RLN_PDATA_INIT; + u_int8_t hwhdr[20]; + + dprintf(" [get]"); + +#ifdef RLNDUMP + printf("%s: recv %c%d seq %d data ", sc->sc_dev.dv_xname, + hdr->cmd_letter, hdr->cmd_fn, hdr->cmd_seq); + RLNDUMPHEX(hdr, sizeof hdr); + printf(":"); +#endif + + totlen -= sizeof *hdr; +#ifdef DIAGNOSTIC + if (totlen <= 0) { + printf("%s: empty packet", sc->sc_dev.dv_xname); + goto drop; + } +#endif + + totlen -= sizeof hwhdr; + /* Skip the hardware header. */ + rln_rx_pdata(sc, hwhdr, sizeof hwhdr, &pd); +#ifdef RLNDUMP + RLNDUMPHEX(hwhdr, sizeof hwhdr); + printf("/"); +#endif + /* (Most of the following code fleeced from elink3.c.) */ + + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == NULL) + goto drop; + m->m_pkthdr.rcvif = ifp; + m->m_pkthdr.len = totlen; + len = MHLEN; + top = 0; + mp = ⊤ + + while (totlen > 0) { + if (top) { + MGET(m, M_DONTWAIT, MT_DATA); + if (!m) { + m_freem(top); + goto drop; + } + len = MLEN; + } + if (top && totlen >= MINCLSIZE) { + MCLGET(m, M_DONTWAIT); + if (m->m_flags & M_EXT) + len = MCLBYTES; + } + len = min(totlen, len); + rln_rx_pdata(sc, mtod(m, u_int8_t *), len, &pd); +#ifdef RLNDUMP + RLNDUMPHEX(mtod(m, u_int8_t *), len); + if (totlen != len) + printf("|"); +#endif + m->m_len = len; + totlen -= len; + *mp = m; + mp = &m->m_next; + } +#ifdef RLNDUMP + printf("\n"); +#endif + return m; + +drop: +#ifdef RLNDUMP + printf(": drop\n"); +#endif + ifp->if_iqdrops++; + return NULL; +} + +/* Interface control. */ +static int +rlnioctl(ifp, cmd, data) + struct ifnet *ifp; + u_long cmd; + caddr_t data; +{ + struct rln_softc *sc = ifp->if_softc; + struct ifaddr *ifa = (struct ifaddr *)data; + int s, error; + int need_init; + + s = splnet(); + if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) != 0) { + splx(s); + return error; + } + + switch (cmd) { + case SIOCSIFADDR: + /* Set address. */ + ifp->if_flags |= IFF_UP; + + switch (ifa->ifa_addr->sa_family) { +#ifdef INET + case AF_INET: + rlninit(sc); + arp_ifinit(&sc->sc_arpcom, ifa); + break; +#endif + default: + rlninit(sc); + break; + } + break; + + case SIOCSIFFLAGS: + need_init = 0; + + if ((ifp->if_flags & IFF_UP) == 0 && + (ifp->if_flags & IFF_RUNNING) != 0) { + /* Was running, want down: stop. */ + rlnstop(sc); + } else if ((ifp->if_flags & IFF_UP) != 0 && + (ifp->if_flags & IFF_RUNNING) == 0) { + /* Was not running, want up: start. */ + need_init = 1; + } + + if (ifp->if_flags & IFF_RUNNING) { + if ((ifp->if_flags & IFF_PROMISC) && + (sc->sc_state & RLN_STATE_PROMISC) == 0) { + sc->sc_state |= RLN_STATE_PROMISC; + need_init = 1; + } + else if ((ifp->if_flags & IFF_PROMISC) == 0 && + (sc->sc_state & RLN_STATE_PROMISC)) { + sc->sc_state &= ~RLN_STATE_PROMISC; + need_init = 1; + } + } + + /* XXX Deal with other flag changes? */ + + if (need_init) + rlninit(sc); + + break; + + case SIOCADDMULTI: + case SIOCDELMULTI: + error = EOPNOTSUPP; + break; + +#if notyet + case RLNIOSPARAM: + error = rln_iosetparam(sc, (struct rln_param *)&data); + break; + + case RLNIOGPARAM: + bcopy(&sc->sc_param, (struct rln_param *)&data, + sizeof sc->sc_param); + break; +#endif + + default: + error = EINVAL; + break; + } + + splx(s); + return (error); +} + +/* Stop output from the card. */ +static void +rlnstop(sc) + struct rln_softc *sc; +{ + struct ifnet *ifp = &sc->sc_arpcom.ac_if; + + dprintf(" [stop]"); + /* XXX Should kill interrupts? */ + /* rln_enable(sc, 0); */ + ifp->if_flags &= ~IFF_RUNNING; +} + +/* Test for existence of card. */ +static int +rln_probe(sc) + struct rln_softc *sc; +{ + + dprintf(" [probe]"); + /* If we can reset it, it's there. */ + return (rln_reset(sc)); +} + +/* Get MAC address from card. */ +static int +rln_getenaddr(sc, enaddr) + struct rln_softc *sc; + u_int8_t * enaddr; +{ + struct rln_mm_cmd query = RLN_MM_GETENADDR; + struct rln_mm_gotenaddr response = { RLN_MM_GETENADDR }; + + if (rln_msg_txrx(sc, &query, sizeof query, + &response, sizeof response)) + return (-1); + bcopy(response.enaddr, enaddr, sizeof response.enaddr); + return (0); +}; + +/* Get firmware version string from card. */ +static int +rln_getpromvers(sc, ver, verlen) + struct rln_softc *sc; + char *ver; + int verlen; +{ + struct rln_mm_cmd query = RLN_MM_GETPROMVERSION; + struct rln_mm_gotpromversion response = { RLN_MM_GOTPROMVERSION }; + int i; + +#ifdef DIAGNOSTIC + if (verlen != sizeof response.version) + panic("rln_getpromvers"); +#endif + + if (rln_msg_txrx(sc, &query, sizeof query, + &response, sizeof response)) + return (-1); + bcopy(response.version, ver, verlen); + /* Nul trailing spaces. */ + for (i = verlen - 1; i >= 0 && ver[i] <= ' '; i--) + ver[i] = '\0'; + return (0); +}; + +/* Set default operational parameters on card. */ +static int +rln_sendinit(sc) + struct rln_softc *sc; +{ + struct rln_mm_init init = { RLN_MM_INIT }; + struct rln_mm_initted iresponse; +#if 0 + struct rln_mm_setmagic magic = { RLN_MM_SETMAGIC }; + struct rln_mm_disablehopping hop = { RLN_MM_DISABLEHOPPING }; + struct rln_mm_cmd response; +#endif + + bzero((char*)&init + sizeof init.mm_cmd, + sizeof init - sizeof init.mm_cmd); + + dprintf(" [setting parameters]"); + init.opmode = (sc->sc_state & RLN_STATE_PROMISC ? + RLN_MM_INIT_OPMODE_PROMISC : RLN_MM_INIT_OPMODE_NORMAL); + init.stationtype = sc->sc_param.rp_station_type; + + /* Spread-spectrum frequency hopping. */ + init.hop_period = 1; + init.bfreq = 2; + init.sfreq = 7; + + /* Choose channel. */ + init.channel = sc->sc_param.rp_channel; + init.subchannel = sc->sc_param.rp_subchannel; + init.domain = sc->sc_param.rp_domain; + + /* Name of this station when acting as master. */ + bcopy(sc->sc_param.rp_master, init.mastername, sizeof init.mastername); + + /* Security params. */ + init.sec1 = (sc->sc_param.rp_security & 0x0000ff) >> 0; + init.sec2 = (sc->sc_param.rp_security & 0x00ff00) >> 8; + init.sec3 = (sc->sc_param.rp_security & 0xff0000) >> 16; + + init.sync_to = 1; + bzero(init.syncname, sizeof init.syncname); + + if (rln_msg_txrx(sc, &init, sizeof init, + &iresponse, sizeof iresponse)) + return (-1); +#if 0 + dprintf(" [setting magic]"); + magic.fairness_slot = 3; /* lite: 1, norm: 3, off: -1 */ + magic.deferral_slot = 3; /* lite: 0, norm: 3, off: -1 */ + magic.regular_mac_retry = 7; + magic.frag_mac_retry = 10; + magic.regular_mac_qfsk = 2; + magic.frag_mac_qfsk = 5; + magic.xxx1 = 0xff; + magic.xxx2 = 0xff; + magic.xxx3 = 0xff; + magic.xxx4 = 0x00; + if (rln_msg_txrx(sc, &magic, sizeof magic, + &response, sizeof response)) + return (-1); + + dprintf(" [disabling freq hopping]"); + hop.hopflag = RLN_MM_DISABLEHOPPING_HOPFLAG_DISABLE; + if (rln_msg_txrx(sc, &hop, sizeof hop, + &response, sizeof response)) + return (-1); + +#endif + return (0); +} + +#if notyet +/* Configure the way the card leaves a basestation. */ +static int +rln_roamconfig(sc) + struct rln_softc *sc; +{ + struct rln_mm_setroaming roam = { RLN_MM_SETROAMING }; + struct rln_mm_cmd response; + static int retry[3] = { 6, 6, 4 }; + static int rssi[3] = { 5, 15, 5 }; + + dprintf(" [roamconfig]"); +#ifdef DIAGNOSTIC + if (sc->sc_param.rp_roam_config > 2) + panic("roamconfig"); +#endif + roam.sync_alarm = 0; + roam.retry_thresh = retry[sc->sc_param.rp_roam_config]; + roam.rssi_threshold = rssi[sc->sc_param.rp_roam_config]; + roam.xxx1 = 0x5a; + roam.sync_rssi_threshold = 0; + roam.xxx2 = 0x5a; + roam.missed_sync = 0x4; + if (rln_msg_txrx(sc, &roam, sizeof roam, + &response, sizeof response)) + return (-1); + + return (0); +} + +/* Enable roaming. */ +static int +rln_roam(sc) + struct rln_softc *sc; +{ + struct rln_mm_cmd roam = RLN_MM_ROAM; + struct rln_mm_cmd response; + + return (rln_msg_txrx(sc, &roam, sizeof roam, + &response, sizeof response)); +} + +/* Enable multicast capability. */ +static int +rln_multicast(sc, enable) + struct rln_softc *sc; + int enable; +{ + struct ifnet *ifp = &sc->sc_arpcom.ac_if; + struct rln_mm_multicast mcast = { RLN_MM_MULTICAST }; + struct rln_mm_cmd response; + int ret; + + mcast.enable = enable; + + ret = rln_msg_txrx(sc, &mcast, sizeof mcast, + &response, sizeof response); + if (ret == 0) { + if (enable) + ifp->if_flags |= IFF_MULTICAST; + else + ifp->if_flags &= ~IFF_MULTICAST; + } + return (ret); +} + +/* Search for and sync with any master. */ +static int +rln_searchsync(sc) + struct rln_softc *sc; +{ + struct rln_mm_search search = { RLN_MM_SEARCH }; + struct rln_mm_searching response; + + bzero(search.xxx1, sizeof search.xxx1); + search.domain = sc->sc_param.rp_domain; + search.roaming = 1; + search.xxx3 = 0; + search.xxx4 = 1; + search.xxx5 = 0; + bzero(search.xxx6, sizeof search.xxx6); + + return (rln_msg_txrx(sc, &search, sizeof search, + &response, sizeof response)); +} + +/* Set values from an external parameter block. */ +static int +rln_iosetparam(sc, param) + struct rln_softc *sc; + struct rln_param *param; +{ + int error = 0; + + if (param->rp_roam_config > 2) + error = EINVAL; + if (param->rp_security > 0x00ffffff) + error = EINVAL; + if (param->rp_station_type > 2) + error = EINVAL; + if (param->rp_channel > 15) + error = EINVAL; + if (param->rp_subchannel > 15) + error = EINVAL; + if (error == 0) { + /* Apply immediately. */ + bcopy(param, &sc->sc_param, sizeof *param); + if (rln_sendinit(sc)) + error = EIO; + } + return (error); +} + +/* Protect the eeprom from storing a security ID(?) */ +static int +rln_lockprom(sc) + struct rln_softc *sc; +{ + struct rln_mm_cmd lock = RLN_MM_EEPROM_PROTECT; + struct rln_mm_cmd response; + + /* XXX Always yields an error? */ + return (rln_msg_txrx(sc, &lock, sizeof lock, + &response, sizeof response)); +} + +/* Set the h/w Inactivity Time Out timer on the card. */ +static int +rln_ito(sc) + struct rln_softc * sc; +{ + struct rln_mm_setito ito = { RLN_MM_MULTICAST }; + struct rln_mm_cmd response; + + ito.xxx = 3; + ito.timeout = LLDInactivityTimeOut /* enabler, 0 or 1 */; + ito.bd_wakeup = LLDBDWakeup /* 0 */; + ito.pm_sync = LLDPMSync /* 0 */; + ito.sniff_time = ito.timeout ? LLDSniffTime /* 0 */ : 0; + + if (rln_msg_txrx(sc, &ito, sizeof ito, + &response, sizeof response)) + return (-1); +} + +/* Put the card into standby mode. */ +static int +rln_standby(sc) + struct rln_softc * sc; +{ + struct rln_mm_standby standby = { RLN_MM_STANDBY }; + + standby.xxx = 0; + if (rln_msg_txrx(sc, &ito, sizeof ito, NULL, 0)) + return (-1); +} +#endif diff --git a/sys/dev/ic/rln.h b/sys/dev/ic/rln.h new file mode 100644 index 00000000000..fa4b7b2e799 --- /dev/null +++ b/sys/dev/ic/rln.h @@ -0,0 +1,39 @@ +/* $OpenBSD: rln.h,v 1.1 1999/07/30 13:43:36 d Exp $ */ +/* + * David Leonard , 1999. Public domain. + * + * Proxim RangeLAN2 parameters. + */ + +/* + * Eventually, there should be a way of getting and setting these + * from user space. Ideally, via ioctl(). + */ + +/* User-configurable station parameters. */ +struct rln_param { + u_int32_t rp_security; /* Security ID */ +#define RLN_SECURITY_DEFAULT 0x0010203 + u_int8_t rp_station_type; /* Station type */ +#define RLN_STATIONTYPE_SLAVE 0 +#define RLN_STATIONTYPE_ALTMASTER 1 +#define RLN_STATIONTYPE_MASTER 2 + u_int8_t rp_domain; /* Network domain */ + u_int8_t rp_channel; /* Phys channel when master */ + u_int8_t rp_subchannel; /* Logical master subchannel */ + char rp_master[11]; /* Name when master */ + u_int8_t rp_mac_optimize; +#define RLN_MAC_OPTIM_LIGHT 0 +#define RLN_MAC_OPTIM_NORMAL 1 + u_int8_t rp_roam_config; /* Roaming speed */ +#define RLN_ROAM_SLOW 0 +#define RLN_ROAM_NORMAL 1 +#define RLN_ROAM_FAST 2 + u_int8_t rp_peer_to_peer; /* Ability to talk to peers */ +}; + +#ifdef notyet +#define RLNIOSPARAM _IOW('2', 1, struct rln_param) /* set params */ +#define RLNIOGPARAM _IOR('2', 2, struct rln_param) /* get params */ +#endif + diff --git a/sys/dev/ic/rlncmd.h b/sys/dev/ic/rlncmd.h new file mode 100644 index 00000000000..efaed3dcde1 --- /dev/null +++ b/sys/dev/ic/rlncmd.h @@ -0,0 +1,247 @@ +/* $OpenBSD: rlncmd.h,v 1.1 1999/07/30 13:43:36 d Exp $ */ +/* + * David Leonard , 1999. Public Domain. + * + * RangeLAN2 host-to-card message protocol. + */ + +/* Micro-message command header. */ +struct rln_mm_cmd { + u_int8_t cmd_letter; /* Command letter */ + u_int8_t cmd_seq; /* Incremented on each command */ +#define RLN_MAXSEQ 0x7c + u_int8_t cmd_fn; /* Function number */ + u_int8_t cmd_error; /* Reserved */ +}; +#define RLN_MM_CMD(l,n) ((((unsigned int)l)<<8) | ((unsigned int)n)) +#define RLN_MM_CMD_LETTER(cmd) ((unsigned char)(((cmd) & 0xff00)>>8)) +#define RLN_MM_CMD_FUNCTION(cmd) ((unsigned char)((cmd) & 0xff)) +#define RLN_CMDCODE(letter, num) ((((letter) & 0xff) << 8) | ((num) & 0xff)) + +/* Initialise card, and set operational parameters. */ +struct rln_mm_init { + struct rln_mm_cmd mm_cmd; +#define RLN_MM_INIT { 'A', 0, 0, 0 } + u_int8_t enaddr[6]; + u_int8_t opmode; +#define RLN_MM_INIT_OPMODE_NORMAL 0 +#define RLN_MM_INIT_OPMODE_PROMISC 1 +#define RLN_MM_INIT_OPMODE_PROTOCOL 2 + u_int8_t stationtype; /* RLN_STATIONTYPE_... */ + u_int8_t hop_period; + u_int8_t bfreq; + u_int8_t sfreq; + u_char channel : 4; /* lower bits */ + u_char subchannel : 4; /* upper bits */ + char mastername[11]; + u_char sec1 : 4; /* default 3 */ + u_char domain : 4; /* default 0 */ + u_int8_t sec2; /* default 2 */ + u_int8_t sec3; /* default 1 */ + u_int8_t sync_to; /* 1 if roaming */ + u_int8_t xxx_pad; /* zero */ + char syncname[11]; +}; + +/* Result of initialisation. */ +struct rln_mm_initted { + struct rln_mm_cmd mm_cmd; +#define RLN_MM_INITTED { 'a', 0, 0, 0 } + u_int8_t xxx; +}; + +/* Start searching for other masters. */ +struct rln_mm_search { + struct rln_mm_cmd mm_cmd; +#define RLN_MM_SEARCH { 'A', 0, 1, 0 } + u_int8_t xxx1[23]; + u_char xxx2 : 4; + u_char domain : 4; + u_int8_t roaming; + u_int8_t xxx3; /* default 0 */ + u_int8_t xxx4; /* default 1 */ + u_int8_t xxx5; /* default 0 */ + u_int8_t xxx6[11]; +}; + +/* Notification that searching has started. */ +struct rln_mm_searching { + struct rln_mm_cmd mm_cmd; +#define RLN_MM_SEARCHING { 'a', 0, 1, 0 } + u_int8_t xxx; +}; + +/* Terminate search. */ +#define RLN_MM_ABORTSEARCH { 'A', 0, 3, 0 } + +/* Station synchronised to a master. */ +struct rln_mm_synchronised { + struct rln_mm_cmd mm_cmd; +#define RLN_MM_SYNCHRONISED { 'a', 0, 4, 0 } + u_char channel : 4; /* lower bits */ + u_char subchannel : 4; /* upper bits */ + char mastername[11]; + u_int8_t enaddr[6]; +}; + +/* Station lost synchronisation with a master. */ +#define RLN_MM_UNSYNCHRONISED { 'a', 0, 5, 0 } + +/* Send card to sleep. (See rln_wakeup().) */ +struct rln_mm_standby { + struct rln_mm_cmd mm_cmd; +#define RLN_MM_STANDBY { 'A', 0, 6, 0 } + u_int8_t xxx; /* default 0 */ +}; + +/* Set ITO (inactivity timeout timer). */ +struct rln_mm_setito { + struct rln_mm_cmd mm_cmd; +#define RLN_MM_SETITO { 'A', 0, 7, 0 } + u_int8_t xxx; /* default 3 */ + u_int8_t timeout; + u_char bd_wakeup : 1; + u_char pm_sync : 7; + u_int8_t sniff_time; +}; + +/* ITO acknowledgment */ +#define RLN_MM_GOTITO { 'a', 0, 7, 0 } + +/* Send keepalive protocol message (?). */ +#define RLN_MM_SENDKEEPALIVE { 'A', 0, 8, 0 } + +/* Set multicast mode. */ +struct rln_mm_multicast { + struct rln_mm_cmd mm_cmd; +#define RLN_MM_MULTICAST { 'A', 0, 9, 0 } + u_int8_t enable; +}; + +/* Ack multicast mode change. */ +#define RLN_MM_MULTICASTING { 'a', 0, 9, 0 } + +/* Request statistics. */ +#define RLN_MM_GETSTATS { 'A', 0, 11, 0 } + +/* Statistics results. */ +#define RLN_MM_GOTSTATS { 'a', 0, 11, 0 } + +/* Set security ID used in channel. */ +struct rln_mm_setsecurity { + struct rln_mm_cmd mm_cmd; +#define RLN_MM_SETSECURITY { 'A', 0, 12, 0 } + u_int8_t sec1; + u_int8_t sec2; + u_int8_t sec3; +}; + +/* Ack set security ID. */ +#define RLN_MM_GOTSECURITY { 'a', 0, 12, 0 } + +/* Request firmware version. */ +#define RLN_MM_GETPROMVERSION { 'A', 0, 13, 0 } + +/* Reply with firmware version. */ +struct rln_mm_gotpromversion { + struct rln_mm_cmd mm_cmd; +#define RLN_MM_GOTPROMVERSION { 'a', 0, 13, 0 } + u_int8_t xxx; /* sizeof version? */ + char version[7]; +}; + +/* Request station's MAC address (same as ethernet). */ +#define RLN_MM_GETENADDR { 'A', 0, 14, 0 } + +/* Reply with station's MAC address. */ +struct rln_mm_gotenaddr { + struct rln_mm_cmd mm_cmd; +#define RLN_MM_GOTENADDR { 'a', 0, 14, 0 } + u_int8_t xxx; + u_int8_t enaddr[6]; +}; + +/* Tune various channel parameters. */ +struct rln_mm_setmagic { + struct rln_mm_cmd mm_cmd; +#define RLN_MM_SETMAGIC { 'A', 0, 16, 0 } + u_char fairness_slot : 3; + u_char deferral_slot : 5; + u_int8_t regular_mac_retry; /* default 0x07 */ + u_int8_t frag_mac_retry; /* default 0x0a */ + u_int8_t regular_mac_qfsk; /* default 0x02 */ + u_int8_t frag_mac_qfsk; /* default 0x05 */ + u_int8_t xxx1; /* default 0xff */ + u_int8_t xxx2; /* default 0xff */ + u_int8_t xxx3; /* default 0xff */ + u_int8_t xxx4; /* zero */ +}; + +/* Ack channel tuning. */ +#define RLN_MM_GOTMAGIC { 'a', 0, 16, 0 } + +/* Set roaming parameters - used when multiple masters available. */ +struct rln_mm_setroaming { + struct rln_mm_cmd mm_cmd; +#define RLN_MM_SETROAMING { 'A', 0, 17, 0 } + u_int8_t sync_alarm; + u_int8_t retry_thresh; + u_int8_t rssi_threshold; + u_int8_t xxx1; /* default 0x5a */ + u_int8_t sync_rssi_threshold; + u_int8_t xxx2; /* default 0xa5 */ + u_int8_t missed_sync; +}; + +/* Ack roaming parameter change. */ +#define RLN_MM_GOTROAMING { 'a', 0, 17, 0 } + +#define RLN_MM_ROAMING { 'a', 0, 18, 0 } +#define RLN_MM_ROAM { 'A', 0, 19, 0 } + +/* Hardware fault notification. (Usually the antenna.) */ +#define RLN_MM_FAULT { 'a', 0, 20, 0 } + +#define RLN_MM_EEPROM_PROTECT { 'A', 0, 23, 0 } +#define RLN_MM_EEPROM_PROTECTED { 'a', 0, 23, 0 } +#define RLN_MM_EEPROM_UNPROTECT { 'A', 0, 24, 0 } +#define RLN_MM_EEPROM_UNPROTECTED { 'a', 0, 24, 0 } + +/* Receive hop statistics. */ +#define RLN_MM_HOP_STATISTICS { 'a', 0, 35, 0 } + +/* Transmit a frame on the channel. */ +struct rln_mm_sendpacket { + struct rln_mm_cmd mm_cmd; +#define RLN_MM_SENDPACKET { 'B', 0, 0, 0 } + u_int8_t mode; +#define RLN_MM_SENDPACKET_MODE_BIT7 0x80 +#define RLN_MM_SENDPACKET_MODE_ZFIRST 0x20 +#define RLN_MM_SENDPACKET_MODE_QFSK 0x03 + u_int8_t power; /* default 0x70 */ + u_int8_t length_lo; + u_int8_t length_hi; + u_int8_t xxx1; /* default 0 */ + u_int8_t xxx2; /* default 0 */ + u_int8_t sequence; /* must increment */ + u_int8_t xxx3; /* default 0 */ +}; + +/* Ack packet transmission. */ +#define RLN_MM_SENTPACKET { 'b', 0, 0, 0 } + +/* Notification of frame received from channel. */ +struct rln_mm_recvpacket { + struct rln_mm_cmd mm_cmd; +#define RLN_MM_RECVPACKET { 'b', 0, 1, 0 } + u_int8_t xxx[8]; +}; + +/* Disable hopping. (?) */ +struct rln_mm_disablehopping { + struct rln_mm_cmd mm_cmd; +#define RLN_MM_DISABLEHOPPING { 'C', 0, 9, 0 } + u_int8_t hopflag; +#define RLN_MM_DISABLEHOPPING_HOPFLAG_DISABLE 0x52 +}; + diff --git a/sys/dev/ic/rlnreg.h b/sys/dev/ic/rlnreg.h new file mode 100644 index 00000000000..0677837aa8c --- /dev/null +++ b/sys/dev/ic/rlnreg.h @@ -0,0 +1,250 @@ +/* $OpenBSD: rlnreg.h,v 1.1 1999/07/30 13:43:36 d Exp $ */ +/* + * David Leonard , 1999. Public Domain. + * + * RangeLAN2 registers + */ + +/* + * The RangeLAN2 cards provide four control registers for transferring + * messaged between the host and the card using programmed i/o. + * + * A transfer protocol is followed when sending asynchronous messages to, + * and receiving messages from, the card. + * + * DATA + * 7 6 5 4 3 2 1 0 + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * | data | + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * + * STATUS + * 7 6 5 4 3 2 1 0 + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * |WAKEUP | tx message state |CLRNAK | rx message state | + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * + * CONTROL + * 7 6 5 4 3 2 1 0 + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * | | | 16BIT | RESET | | | TXINT | RXINT | + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * + * INTSEL + * 7 6 5 4 3 2 1 0 + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * | | | |ENABLE | interrupt line | + * +-------+-------+-------+-------+-------+-------+-------+-------+ + */ + +/* Register offsets. */ +#define RLN_REG_DATA 0 +#define RLN_REG_STATUS 2 +#define RLN_REG_CONTROL 4 +#define RLN_REG_EOI 5 +#define RLN_REG_INTSEL 6 +#define RLN_NPORTS 8 + +/* + * A short delay is needed (16ms?) after register writes on some cards. + * XXX This is done by performing an innocent and harmless bus read. (i386) + * This is what Proxim's driver does, anyway. + */ +#define _rln_regacc_delay() \ + bus_space_read_1(I386_BUS_SPACE_IO, 0, 0x61) + +static void _rln_register_write_1 __P((struct rln_softc *, u_int8_t, + u_int8_t)); +static u_int8_t _rln_register_read_1 __P((struct rln_softc *, u_int8_t)); +static int rln_status_rx_ready __P((struct rln_softc *)); + +/* Write to a register. */ +static inline void +_rln_register_write_1(sc, regoff, value) + struct rln_softc *sc; + u_int8_t regoff; + u_int8_t value; +{ + +#ifdef RLNDEBUG_REG + printf(" %c<%02x", "DDS3CEI7"[regoff], value); +#endif + bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, (regoff), (value)); + _rln_regacc_delay(); +} + +/* Read from a register. */ +static inline u_int8_t +_rln_register_read_1(sc, regoff) + struct rln_softc *sc; + u_int8_t regoff; +{ + u_int8_t ret; + + ret = bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, (regoff)); +#ifdef RLNDEBUG_REG + if (ret != (sc)->dbg_oreg[regoff]) { + /* avoid spewing out too much debug info */ + printf(" %c>%02x", "DDS3CEI7"[regoff], ret); + (sc)->dbg_oreg[regoff] = ret; + } +#endif + return (ret); +} + +/* 8-bit data register access. */ +#define rln_data_write_1(sc, value) \ + _rln_register_write_1(sc, RLN_REG_DATA, (value)) +#define rln_data_read_1(sc) \ + _rln_register_read_1(sc, RLN_REG_DATA) +#define rln_data_write_multi_1(sc, buf, len) \ + bus_space_write_multi_1((sc)->sc_iot, (sc)->sc_ioh, \ + RLN_REG_DATA, (buf), (len)) +#define rln_data_read_multi_1(sc, buf, len) \ + bus_space_read_multi_1((sc)->sc_iot, (sc)->sc_ioh, \ + RLN_REG_DATA, (buf), (len)) + +/* 16-bit data register access. */ +#define rln_data_write_2(sc, value) \ + bus_space_write_2((sc)->sc_iot, (sc)->sc_ioh, \ + RLN_REG_DATA, (value)) +#define rln_data_read_2(sc) \ + bus_space_read_2((sc)->sc_iot, (sc)->sc_ioh, \ + RLN_REG_DATA) +#define rln_data_write_multi_2(sc, buf, len) \ + bus_space_write_multi_2((sc)->sc_iot, (sc)->sc_ioh, \ + RLN_REG_DATA, (buf), (len)) +#define rln_data_read_multi_2(sc, buf, len) \ + bus_space_read_multi_2((sc)->sc_iot, (sc)->sc_ioh, \ + RLN_REG_DATA, (buf), (len)) + +/* Status register. */ +#define RLN_STATUS_CLRNAK 0x08 +#define RLN_STATUS_WAKEUP 0x80 + +#define RLN_STATUS_TX_IDLE 0x00 +#define RLN_STATUS_TX_HILEN_AVAIL 0x01 +#define RLN_STATUS_TX_HILEN_ACCEPT 0x02 +#define RLN_STATUS_TX_XFR_COMPLETE 0x03 +#define RLN_STATUS_TX_XFR 0x04 +#define RLN_STATUS_TX_ERROR 0x05 +#define RLN_STATUS_TX_LOLEN_AVAIL 0x06 +#define RLN_STATUS_TX_LOLEN_ACCEPT 0x07 +#define RLN_STATUS_TX_MASK 0x0f + +#define RLN_STATUS_RX_IDLE 0x00 +#define RLN_STATUS_RX_HILEN_AVAIL 0x10 +#define RLN_STATUS_RX_HILEN_ACCEPT 0x20 +#define RLN_STATUS_RX_XFR_COMPLETE 0x30 +#define RLN_STATUS_RX_XFR 0x40 +#define RLN_STATUS_RX_ERROR 0x50 +#define RLN_STATUS_RX_LOLEN_AVAIL 0x60 +#define RLN_STATUS_RX_LOLEN_ACCEPT 0x70 +#define RLN_STATUS_RX_MASK 0x70 + +#define rln_status_write(sc, value) \ + _rln_register_write_1(sc, RLN_REG_STATUS, (value)) +#define rln_status_set(sc, bits) \ + rln_status_write(sc, (sc)->sc_status |= (bits)) +#define rln_status_clear(sc, bits) \ + rln_status_write(sc, (sc)->sc_status &= ~(bits)) +#define _rln_status_setmask(sc, mask, bits) \ +do { \ + int _s; \ + \ + _s = splhigh(); \ + (sc)->sc_status = ((sc)->sc_status & (mask)) | (bits); \ + rln_status_write(sc, (sc)->sc_status); \ + splx(_s); \ +} while (0); +#define rln_status_rx_write(sc, state) \ + _rln_status_setmask((sc), ~RLN_STATUS_RX_MASK, state) +#define rln_status_tx_write(sc, state) \ + _rln_status_setmask((sc), ~RLN_STATUS_TX_MASK, state) +#define rln_status_read(sc) \ + _rln_register_read_1(sc, RLN_REG_STATUS) +#define rln_status_rx_read(sc) \ + (rln_status_read(sc) & ~RLN_STATUS_TX_MASK) +#define rln_status_tx_read(sc) \ + (rln_status_read(sc) & ~RLN_STATUS_RX_MASK) + +static inline int +rln_status_rx_ready(sc) + struct rln_softc *sc; +{ + u_int8_t status; + + status = rln_status_rx_read(sc); + return (status == RLN_STATUS_RX_LOLEN_AVAIL || + status == RLN_STATUS_RX_HILEN_AVAIL || + status == RLN_STATUS_RX_ERROR); +} + +#define rln_status_tx_int(sc) do { \ + int _s = splhigh(); \ + \ + rln_control_clear(sc, RLN_CONTROL_TXINT); \ + rln_control_set(sc, RLN_CONTROL_TXINT); \ + splx(_s); \ +} while (0) +#define rln_status_rx_int(sc) do { \ + int _s = splhigh(); \ + \ + rln_control_clear(sc, RLN_CONTROL_RXINT); \ + rln_control_set(sc, RLN_CONTROL_RXINT); \ + splx(_s); \ +} while (0) + +/* Control register. */ +#define RLN_CONTROL_RXINT 0x01 +#define RLN_CONTROL_TXINT 0x02 +#define RLN_CONTROL_BIT2 0x04 +#define RLN_CONTROL_BIT3 0x08 +#define RLN_CONTROL_RESET 0x10 +#define RLN_CONTROL_16BIT 0x20 +#define RLN_CONTROL_MASK 0x3f + +#define rln_control_write(sc, value) \ + _rln_register_write_1(sc, RLN_REG_CONTROL, \ + (sc)->sc_control = (value)) +#define rln_control_read(sc) \ + _rln_register_read_1(sc, RLN_REG_CONTROL) +#define rln_control_set(sc, bits) \ + rln_control_write(sc, (sc)->sc_control | (bits)) +#define rln_control_clear(sc, bits) \ + rln_control_write(sc, (sc)->sc_control & ~(bits)) +#define rln_control_outofstandby(sc) do { \ + rln_control_write(sc, (sc)->sc_control | RLN_CONTROL_RESET);\ + DELAY(30000); \ + rln_control_write(sc, (sc)->sc_control); \ +} while (0) + +/* Interrupt selection register. */ +#define RLN_INTSEL_IRQMASK 0x07 +#define RLN_INTSEL_ENABLE 0x10 +#define RLN_INTSEL_BIT7 0x80 + +#define rln_intsel_disable(sc) do { \ + int _s; \ + \ + _s = splhigh(); \ + _rln_register_write_1(sc, RLN_REG_INTSEL, \ + (sc)->sc_intsel &= ~RLN_INTSEL_ENABLE); \ + splx(_s); \ +} while (0) +#define rln_intsel_enable(sc) do { \ + int _s; \ + \ + _s = splhigh(); \ + _rln_register_write_1(sc, RLN_REG_INTSEL, \ + (sc)->sc_intsel |= RLN_INTSEL_ENABLE); \ + splx(_s); \ +} while (0) +#define rln_intsel_write(sc, value) \ + _rln_register_write_1(sc, RLN_REG_INTSEL, \ + (sc)->sc_intsel |= (value)) + +/* End of interrupt signal, used on some newer cards. */ +#define rln_eoi(sc) \ + (void) _rln_register_read_1(sc, RLN_REG_EOI) + diff --git a/sys/dev/ic/rlnsubr.c b/sys/dev/ic/rlnsubr.c new file mode 100644 index 00000000000..db6dcae5b91 --- /dev/null +++ b/sys/dev/ic/rlnsubr.c @@ -0,0 +1,934 @@ +/* $OpenBSD: rlnsubr.c,v 1.1 1999/07/30 13:43:36 d Exp $ */ +/* + * David Leonard , 1999. Public Domain. + * + * Low level card protocol access to the Proxim RangeLAN2 wireless + * network adaptor. + * + * Information and ideas gleaned from + * - disassembly of Dave Koberstein's Linux driver + * (which is built with Proxim source), + * - Yoichi Shinoda's BSDI driver, and + * - Geoff Voelker's Linux port of the same. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef INET +#include +#include +#endif + +#include +#include + +#include +#include +#include +#include + +static int rln_tx_request __P((struct rln_softc *, u_int16_t)); +static int rln_tx_end __P((struct rln_softc *)); + +/* + * Disables or enables interrupts from the card. Returns the old + * interrupt-enable state. + */ +int +rln_enable(sc, enable) + struct rln_softc * sc; + int enable; +{ + int s; + int was_enabled; + + s = splhigh(); + was_enabled = (sc->sc_intsel & RLN_INTSEL_ENABLE) ? 1 : 0; + if (enable != was_enabled) { + if (enable) + sc->sc_intsel |= RLN_INTSEL_ENABLE; + else + sc->sc_intsel &=~RLN_INTSEL_ENABLE; + _rln_register_write_1(sc, RLN_REG_INTSEL, sc->sc_intsel); + } + splx(s); + return (was_enabled); +} + +/* + * Perform a hard reset of the card. Determines bus width (8 or + * 16 bit), if sc->sc_width is unset. Returns 0 on success. + * Note: takes about 200ms at splhigh, meaning this is an expensive call, + * but normal (error-free) operation of the card will not need more than + * two resets - one at probe time, and the other when the interface is + * brought up. + */ +int +rln_reset(sc) + struct rln_softc * sc; +{ + int s; + int i; + int status; + u_int8_t op = 0x00; + + s = splhigh(); + dprintf(" R["); + if (sc->sc_cardtype & (RLN_CTYPE_UISA | RLN_CTYPE_ONE_PIECE)) + op = 0x04; + if (rln_status_read(sc) & RLN_STATUS_WAKEUP) { + rln_control_write(sc, op); + rln_control_write(sc, op | RLN_CONTROL_RESET); + dprintf(" 7ms"); + DELAY(7000); + rln_control_write(sc, op); + dprintf(" 7ms"); + DELAY(7000); + } + rln_control_write(sc, op); + rln_control_write(sc, op); + rln_control_write(sc, op | RLN_CONTROL_BIT3); + dprintf(" 67ms"); + DELAY(67000); + rln_status_write(sc, 0x00); + if (sc->sc_cardtype & (RLN_CTYPE_UISA | RLN_CTYPE_ONE_PIECE)) + rln_control_write(sc, 0x38); + /* RLN_CONTROL_BIT3 | RLN_CONTROL_RESET | RLN_CONTROL_16BIT */ + else + rln_control_write(sc, 0x2c); + /* RLN_CONTROL_BIT3 | RLN_CONTROL_BIT2 | RLN_CONTROL_16BIT */ + dprintf(" 67ms"); + DELAY(67000); + rln_data_write_2(sc, 0xaa55); + rln_status_write(sc, 0x5a); + splx(s); + for (i = 0; i < 200 *5; i++) { /* Proxim says 200. */ + if ((status = rln_status_read(sc)) == 0x5a) + break; + DELAY(1000); + } + dprintf(" (%dms)", i); + s = splhigh(); + if (status != 0x5a) { + splx(s); + /* Only winge if bus width not yet probed */ + if (sc->sc_width != 0) + printf("%s: reset timeout\n", sc->sc_dev.dv_xname); + dprintf("]=-1"); + return (-1); + } + if (sc->sc_width == 8) { + if (sc->sc_cardtype & (RLN_CTYPE_UISA | RLN_CTYPE_ONE_PIECE)) + rln_control_write(sc, RLN_CONTROL_BIT3); + else + rln_control_write(sc, RLN_CONTROL_BIT3 | + RLN_CONTROL_BIT2); + rln_data_write_1(sc, 0x20); + } else if (sc->sc_width == 16) { + rln_data_write_2(sc, 0x0000); + } else { + if (rln_data_read_2(sc) == 0x55aa) { + rln_data_write_2(sc, 0x0000); + sc->sc_width = 16; + } else { + if (sc->sc_cardtype & (RLN_CTYPE_UISA | + RLN_CTYPE_ONE_PIECE)) + rln_control_write(sc, RLN_CONTROL_BIT3); + else + rln_control_write(sc, RLN_CONTROL_BIT3 | + RLN_CONTROL_BIT2); + rln_data_write_1(sc, 0x20); + sc->sc_width = 8; + } + /* printf("%s: %d bit bus\n", sc->sc_dev.dv_xname, + sc->sc_width); */ + } + rln_status_write(sc, 0x00); + sc->sc_intsel = 0; + rln_intsel_write(sc, sc->sc_irq); + splx(s); + dprintf("]"); + return (0); +} + +/* + * Sets the new 'wakeup' state. Returns the old wakeup state. + * The special state value RLN_WAKEUP_SET should be used to wake the + * card up. The card can be partially put to sleep (presumably to save + * power) by sending it the 'Standby' command. + */ +u_int8_t +rln_wakeup(sc, wnew) + struct rln_softc * sc; + u_int8_t wnew; +{ + u_int8_t wold, s; + int i; + + /* Save what the last-written values were. */ + wold = (sc->sc_status & RLN_STATUS_WAKEUP) | + (sc->sc_control & RLN_CONTROL_RESET); + + if (wnew == RLN_WAKEUP_SET) { + /* SetWakeupBit() */ + dprintf(" Ws["); + rln_status_set(sc, RLN_STATUS_WAKEUP); + if (0/*LLDInactivityTimeOut && + (sc->sc_cardtype & RLN_CTYPE_OEM)*/) { + dprintf (" 167ms"); + DELAY(167000); + } else { + dprintf (" .1ms"); + DELAY(100); + } + s = rln_status_read(sc); + rln_control_set(sc, RLN_CONTROL_RESET); + if ((s & RLN_STATUS_WAKEUP) != 0) + for (i = 0; i < 9; i++) { + dprintf(" 2ms"); + DELAY(2000); + rln_status_set(sc, RLN_STATUS_WAKEUP); + } + dprintf("]"); + } else { + /* ClearWakeupBit() */ + dprintf(" Wc["); + if ((wnew & RLN_STATUS_WAKEUP) == 0) + rln_status_clear(sc, RLN_STATUS_WAKEUP); + if ((wnew & RLN_CONTROL_RESET) == 0) + rln_control_clear(sc, RLN_CONTROL_RESET); + dprintf("]"); + } + return (wold); +} + +/* + * Performs the first (request) stage of transmitting a command message + * to the card. 'len' is the expected length of the message is needed. + * Returns: 0 on success + * 1 on timeout + * 2 on NAK (card busy, and will need a rln_clear_nak() after 100ms) + */ +static int +rln_tx_request(sc, len) + struct rln_softc * sc; + u_int16_t len; +{ + /* TxRequest() */ + int s; + int i; + u_int8_t status; + + /* u_int8_t w; */ + /* w = rln_wakeup(sc, RLN_WAKEUP_SET); */ + + dprintf(" Tr["); + if (sc->sc_width == 16) { + rln_status_tx_write(sc, RLN_STATUS_TX_HILEN_AVAIL); + rln_data_write_2(sc, len); + rln_status_tx_int(sc); + + s = spl0(); + for (i = 0; i < 600; i++) { + status = rln_status_tx_read(sc); + if (status == RLN_STATUS_TX_HILEN_ACCEPT || + status == RLN_STATUS_TX_ERROR) + break; + DELAY(1000); + } + splx(s); + dprintf(" %dms", i); + if (status == RLN_STATUS_TX_HILEN_ACCEPT) + goto success; + if (status == RLN_STATUS_TX_ERROR) + goto error; + } else if (sc->sc_width == 8) { + rln_status_tx_write(sc, RLN_STATUS_TX_LOLEN_AVAIL); + rln_data_write_1(sc, len & 0xff); + rln_status_tx_int(sc); + s = spl0(); + for (i = 0; i < 6800; i++) { + status = rln_status_tx_read(sc); + if (status == RLN_STATUS_TX_LOLEN_ACCEPT) + break; + DELAY(1000); + } + splx(s); + dprintf(" %dms", i); + if (status == RLN_STATUS_TX_LOLEN_ACCEPT) { + rln_data_write_1(sc, (len >> 8) & 0xff); + rln_status_tx_write(sc, RLN_STATUS_TX_HILEN_AVAIL); + s = spl0(); + for (i = 0; i < 600; i++) { + status = rln_status_tx_read(sc); + if (status == RLN_STATUS_TX_HILEN_ACCEPT || + status == RLN_STATUS_TX_ERROR) + break; + DELAY(1000); + } + splx(s); + dprintf(" %dms", i); + if (status == RLN_STATUS_TX_HILEN_ACCEPT) + goto success; + if (status == RLN_STATUS_TX_ERROR) + goto error; + } + } +#ifdef DIAGNOSTIC + else + panic("rln: bus width"); +#endif + + printf("%s: tx_request timed out, status 0x%02x", + sc->sc_dev.dv_xname, status); + dprintf("]=(1)"); + return (1); + +error: + /* Will need to clear nak within 100 ms. */ + dprintf("]=2"); +#ifdef DIAGNOSTIC + printf("%s: tx protocol fault (nak)\n", sc->sc_dev.dv_xname); +#endif + return (2); + +success: + /* rln_wakeup(sc, w); */ + dprintf("]=0"); + return (0); +} + +/* + * Performs the third (and final) stage of transmitting a command + * message to the card. + * Returns: 0 on command success. + * non-zero on failure (card will need reset) + */ +static int +rln_tx_end(sc) + struct rln_softc * sc; +{ + /* EndOfTx() */ + int i; + int s; + u_int8_t status; + + dprintf(" Te["); + s = spl0(); + for (i = 0; i < 600; i++) { + status = rln_status_tx_read(sc); + if (status == RLN_STATUS_TX_XFR_COMPLETE) + break; + DELAY(1000); + } + splx(s); + if (status == RLN_STATUS_TX_XFR_COMPLETE) { + rln_status_tx_write(sc, RLN_STATUS_TX_IDLE); + dprintf("]=0"); + return (0); + } else { + printf("%s: tx cmd failed (%02x)\n", sc->sc_dev.dv_xname, + status); + rln_need_reset(sc); + dprintf("]=-1"); + return (-1); + } +} + +/* + * Performs first (request) stage of receiving a message from the card. + * Returns: 0 on failure, + * n>0 on success, where 'n' is the length of the message + */ + +int +rln_rx_request(sc, timeo) + struct rln_softc * sc; + int timeo; /* milliseconds */ +{ + /* RxRequest */ + int s; + int len = 0; + int i; + u_int8_t status; + u_int8_t hi, lo; + + dprintf(" Rr["); + status = rln_status_rx_read(sc); + + /* Short wait for states 1|5|6. */ + s = spl0(); + for (i = 0; i < timeo; i++) { + if (status == RLN_STATUS_RX_LOLEN_AVAIL || + status == RLN_STATUS_RX_HILEN_AVAIL || + status == RLN_STATUS_RX_ERROR) + break; + DELAY(1000); + status = rln_status_rx_read(sc); + } + splx(s); + dprintf(" (%dms)",i); + + if (sc->sc_width == 16) { + if (status != RLN_STATUS_RX_HILEN_AVAIL) + goto badstatus_quiet; + /* Read 2 octets. */ + len = rln_data_read_2(sc); + } else if (sc->sc_width == 8) { + if (status != RLN_STATUS_RX_LOLEN_AVAIL) + goto badstatus_quiet; + /* Read low octet. */ + lo = rln_data_read_1(sc); + rln_status_rx_write(sc, RLN_STATUS_RX_LOLEN_ACCEPT); + rln_status_rx_int(sc); + s = spl0(); + for (i = 0; i < 600; i++) { + status = rln_status_rx_read(sc); + if (status == RLN_STATUS_RX_HILEN_AVAIL) + break; + DELAY(1000); + } + splx(s); + if (status != RLN_STATUS_RX_HILEN_AVAIL) + goto badstatus; + /* Read high octet. */ + hi = rln_data_read_1(sc); + len = lo | (hi << 8); + } +#ifdef DIAGNOSTIC + else + panic("rln: bus width %d", sc->sc_width); +#endif + + dprintf(" len=%d]", len); + return (len); + +badstatus: + printf("%s: rx_request timed out, status %02x\n", + sc->sc_dev.dv_xname, status); +badstatus_quiet: + if (status == RLN_STATUS_RX_ERROR) + printf("%s: rx protocol error (nak)\n", sc->sc_dev.dv_xname); + dprintf("]"); + return (-1); +} + +/* Performs part of the second (transfer) stage of receiving a data message. */ +void +rln_rx_pdata(sc, buf, len, pd) + struct rln_softc * sc; + void * buf; + int len; + struct rln_pdata * pd; +{ + char * data = (char *)buf; + + if (pd->p_nremain) { + *data++ = pd->p_data; + if (--len == 0) + return; + } + + pd->p_nremain = 0; + + if (sc->sc_width == 16) { + /* Round down to the closest even multiple. */ + rln_data_read_multi_2(sc, data, len / 2); +#ifdef RLNDEBUG_REG + dprintf(" D>"); + dprinthex(data, len); +#endif + if (len & 1) { + /* Read the last octet plus a bit extra. */ + union { + u_int16_t w; + u_int8_t b[2]; + } u; + + u.w = rln_data_read_2(sc); + data[len - 1] = u.b[0]; + pd->p_data = u.b[1]; + pd->p_nremain = 1; +#ifdef RLNDEBUG_REG + dprintf(" D>{%02x%02x}", u.b[0], u.b[1]); +#endif + } + } else if (sc->sc_width == 8) { + rln_data_read_multi_1(sc, data, len); +#ifdef RLNDEBUG_REG + dprintf(" D>"); + dprinthex(data, len); +#endif + if (len & 1) { + /* Must read multiples of two. */ + pd->p_data = rln_data_read_1(sc); + pd->p_nremain = 1; +#ifdef RLNDEBUG_REG + dprintf(" D>{%02x}", pd->p_data); +#endif + } + } + +} + +int +rln_rx_data(sc, buf, len) + struct rln_softc * sc; + void * buf; + int len; +{ + /* RxData() */ + struct rln_pdata pd = { 0, 0 }; + int s; + int i; + u_int8_t status; + + dprintf(" Rd["); + rln_status_rx_write(sc, RLN_STATUS_RX_HILEN_ACCEPT); + rln_status_rx_int(sc); + s = spl0(); + for (i = 0; i < 600; i++) { + status = rln_status_rx_read(sc); + if (status == RLN_STATUS_RX_XFR) + break; + DELAY(1000); + } + splx(s); + if (status != RLN_STATUS_RX_XFR) { + dprintf("]=-1"); + return (-1); + } + + rln_rx_pdata(sc, buf, len, &pd); +#ifdef DIAGNOSTIC + /* We should have nothing left over. */ + if (pd.p_nremain || len & 1) + panic("rln_rx_data: leftover"); +#endif + + dprintf("]=0"); + return (0); +} + +void +rln_rx_end(sc) + struct rln_softc * sc; +{ + /* EndOfRx() */ + + dprintf(" Re["); + rln_status_rx_write(sc, RLN_STATUS_RX_XFR_COMPLETE); + rln_status_rx_int(sc); + /* rln_wakeup(sc, 0); */ + dprintf("]"); +} + +/* Clear a transmission NAK from the card. */ +void +rln_clear_nak(sc) + struct rln_softc * sc; +{ + /* ClearNAK() */ + + rln_status_tx_write(sc, RLN_STATUS_CLRNAK); + rln_status_tx_int(sc); +} + +/* + * Send a command message to the card. Returns; + * 2: NAK + * -1: failure + * 0: success + */ +int +rln_msg_tx_start(sc, buf, pktlen, state) + struct rln_softc * sc; + void * buf; + int pktlen; + struct rln_msg_tx_state * state; +{ + struct rln_mm_cmd * cmd = (struct rln_mm_cmd *)buf; + int ret; + + state->ien = rln_enable(sc, 0); + state->pd.p_nremain = 0; + + if (!(cmd->cmd_letter == 'A' && cmd->cmd_fn == 6)) /* Standby. */ + state->w = rln_wakeup(sc, RLN_WAKEUP_SET); + else + state->w = RLN_WAKEUP_NOCHANGE; + + ret = rln_tx_request(sc, pktlen); + if (ret == 2) { + rln_clear_nak(sc); + if (sc->sc_cardtype & RLN_CTYPE_OEM) + rln_need_reset(sc); + ret = 2; + } + else if (ret == 1) { + /* Timeout. */ + rln_status_tx_write(sc, RLN_STATUS_TX_XFR); + ret = -1; + } + return (ret); +} + +void +rln_msg_tx_data(sc, buf, len, state) + struct rln_softc * sc; + void * buf; + u_int16_t len; + struct rln_msg_tx_state * state; +{ + char * data = (char *)buf; + + if (sc->sc_width == 16 && state->pd.p_nremain) { + /* XXX htons() needed? */ + union { + u_int8_t b[2]; + u_int16_t w; + } u; + + u.b[0] = state->pd.p_data; + if (len) { + u.b[1] = *data++; + len--; + } else + u.b[1] = '\0'; +#ifdef RLNDEBUG_REG + dprintf(" D<%02x%02x", u.b[0], u.b[1]); +#endif + rln_data_write_2(sc, u.w); + state->pd.p_nremain = 0; + } + + if (len) { + if (sc->sc_width == 16) { + if (len >= 2) + rln_data_write_multi_2(sc, buf, len / 2); + if (len & 1) { + state->pd.p_nremain = 1; + state->pd.p_data = data[len - 1]; + } + } else if (sc->sc_width == 8) + rln_data_write_multi_1(sc, buf, len); +#ifdef DIAGNOSTIC + else + panic("rln_msg_tx_data width %d", sc->sc_width); +#endif +#ifdef RLNDEBUG_REG + dprintf(" D<"); + dprinthex(data, len); +#endif + } +} + + +int +rln_msg_tx_end(sc, state) + struct rln_softc * sc; + struct rln_msg_tx_state * state; +{ + int ret; + + /* Flush the tx buffer. */ + if (state->pd.p_nremain) + rln_msg_tx_data(sc, NULL, 0, state); + +#ifdef DIAGNOSTIC + if (state->pd.p_nremain) + panic("rln_msg_tx_end remain %d", state->pd.p_nremain); +#endif + ret = rln_tx_end(sc); + if (sc->sc_arpcom.ac_if.if_flags & IFF_OACTIVE) + state->w = RLN_WAKEUP_NOCHANGE; + rln_wakeup(sc, state->w); + rln_enable(sc, state->ien); + return (ret); +} + +/* Return the next unique sequence number to use for a transmitted command */ +u_int8_t +rln_newseq(sc) + struct rln_softc * sc; +{ + int s; + u_int8_t seq; + + s = splhigh(); + seq = sc->sc_pktseq++; + if (sc->sc_pktseq > RLN_MAXSEQ) + sc->sc_pktseq = 0; + splx(s); + return (seq); +} + +/* + * Transmit a command message to, and (optionally) receive a response + * message from the card. Each transmitted message has a sequence + * number, and corresponding reply messages have the same sequence + * number. We use the sequence numbers to index the mailboxes so + * that rlnsoftintr() can signal this routine when it has serviced + * and correctly received a response. + */ + +int +rln_msg_txrx(sc, tx, txlen, rx, rxlen) + struct rln_softc * sc; + void * tx; + int txlen; + void * rx; + int rxlen; +{ + struct rln_mm_cmd * txc = (struct rln_mm_cmd *)tx; + struct rln_mm_cmd * rxc = (struct rln_mm_cmd *)rx; + struct rln_msg_tx_state state; + int ien; + int ret; + +#ifdef DIAGNOSTIC + if (rx != NULL && rxlen < sizeof *rxc) + panic("rln_msg_txrx"); +#endif + + txc->cmd_seq = rln_newseq(sc); + +#ifdef RLNDUMP + printf("%s: send %c%d seq %d data ", sc->sc_dev.dv_xname, + txc->cmd_letter, txc->cmd_fn, txc->cmd_seq); + RLNDUMPHEX(txc, sizeof *txc); + printf(":"); + RLNDUMPHEX((char *)tx + sizeof *txc, txlen - sizeof *txc); + printf("\n"); +#endif + + if (rx != NULL) + if (rln_mbox_create(sc, txc->cmd_seq, rx, rxlen) < 0) + /* Mailbox collision. */ + return (-1); + + /* Start the transfer. */ + if ((ret = rln_msg_tx_start(sc, tx, txlen, &state))) { + if (rx != NULL) + rln_mbox_wait(sc, txc->cmd_seq, -1); + return (ret); + } + + /* Always send an even number of octets. */ + rln_msg_tx_data(sc, tx, (txlen + 1) & ~1, &state); + + /* End the transmission. */ + if ((ret = rln_msg_tx_end(sc, &state))) { + /* Destroy mailbox. */ + if (rx != NULL) + rln_mbox_wait(sc, txc->cmd_seq, -1); + return (ret); + } + + /* Don't wait for reply if there is nowhere to put it. */ + if (rx == NULL) + return (0); + + /* Enable interrupts if not already. */ + ien = rln_enable(sc, 1); + + /* Wait for the reply message. */ + if (rln_mbox_wait(sc, txc->cmd_seq, 2000) <= 0) { + printf("%s: lost message %c%d seq %d\n", sc->sc_dev.dv_xname, + txc->cmd_letter, txc->cmd_fn, txc->cmd_seq); + rln_enable(sc, ien); + return (-1); + } + rln_enable(sc, ien); + +#ifdef RLNDUMP + printf("%s: recv %c%d seq %d data ", sc->sc_dev.dv_xname, + rxc->cmd_letter, rxc->cmd_fn, rxc->cmd_seq); + RLNDUMPHEX(rxc, sizeof *rxc); + printf(":"); + RLNDUMPHEX(((char *)rx) + sizeof *rxc, rxlen - sizeof *rxc); + printf("\n"); +#endif + + /* Check for errors in the received message. */ + if (rxc->cmd_error & 0x80) { + printf("%s: command error 0x%02x command %c%d\n", + sc->sc_dev.dv_xname, + rxc->cmd_error & ~0x80, + rxc->cmd_letter, rxc->cmd_fn); + return (-1); + } + + return (0); +} + +/* + * Mailboxes provide a simple way to tell the interrupt + * service routine that someone is expecting a reply message. + * Mailboxes are identified by the message sequence number + * and also hold a pointer to storage supplied by the waiter. + * The interrupt service routine signals the mailbox when it + * gets the reply message. + */ + +/* Create a mailbox for filling. */ +int +rln_mbox_create(sc, seq, buf, len) + struct rln_softc * sc; + u_int8_t seq; + void * buf; + size_t len; +{ + int s; + struct rln_mbox * mb = &sc->sc_mbox[seq]; + + dprintf(" RLN_NMBOX) + panic("mbox create"); +#endif + + s = splhigh(); + if (mb->mb_state != RLNMBOX_VOID) { +#ifdef DIAGNOSTIC + printf("mbox collision"); +#endif + splx(s); + return (-1); + } + mb->mb_buf = buf; + mb->mb_len = len; + mb->mb_actlen = 0; + mb->mb_state = RLNMBOX_EMPTY; + dprintf(" empty>"); + splx(s); + return (0); +} + + +/* Wait for a mailbox to be filled. */ +int +rln_mbox_wait(sc, seq, timeo) + struct rln_softc * sc; + u_int8_t seq; + int timeo; +{ + int i; + int s; + int ret; + volatile struct rln_mbox * mb = &sc->sc_mbox[seq]; + extern int cold; + + dprintf(" RLN_NMBOX) + panic("mbox wait"); +#endif + if (cold) { + /* Autoconfiguration - spin at spl0. */ + s = spl0(); + i = 0; + while (mb->mb_state == RLNMBOX_EMPTY && i < timeo) { + DELAY(1000); + i++; + } + if (i) + dprintf(" %dms", i); + while (mb->mb_state == RLNMBOX_FILLING) + ; + splx(s); + } else { + tsleep((void *)mb, PRIBIO, "rlnmbox", hz * timeo / 1000); + if (mb->mb_state == RLNMBOX_FILLING) { + /* Must wait until filled. */ + s = spl0(); + while (mb->mb_state == RLNMBOX_FILLING) + ; + splx(s); + } + } + + s = splhigh(); +#ifdef DIAGNOSTIC + if (mb->mb_state != RLNMBOX_EMPTY && mb->mb_state != RLNMBOX_FILLED) + panic("mbox wait %d", mb->mb_state); +#endif + ret = mb->mb_actlen; + mb->mb_state = RLNMBOX_VOID; + dprintf(" void>=%d", ret); + splx(s); + return (ret); +} + +/* Lock a mailbox for filling. */ +int +rln_mbox_lock(sc, seq, bufp, lenp) + struct rln_softc * sc; + u_int8_t seq; + void ** bufp; + size_t * lenp; +{ + int s; + struct rln_mbox * mb = &sc->sc_mbox[seq]; + + dprintf(" RLN_NMBOX) + panic("mbox lock"); +#endif + if (mb->mb_state != RLNMBOX_EMPTY) { + splx(s); + dprintf(" ?>"); + return (-1); + } + + mb->mb_state = RLNMBOX_FILLING; + dprintf(" filling>"); + *bufp = mb->mb_buf; + *lenp = mb->mb_len; + + splx(s); + return (0); +} + +/* Unlock a mailbox and inform the waiter of the actual number of octets. */ +void +rln_mbox_unlock(sc, seq, actlen) + struct rln_softc * sc; + u_int8_t seq; + size_t actlen; +{ + int s; + struct rln_mbox * mb = &sc->sc_mbox[seq]; + + dprintf(" RLN_NMBOX) + panic("mbox unlock seq"); + if (mb->mb_state != RLNMBOX_FILLING) + panic("mbox unlock"); +#endif + mb->mb_state = RLNMBOX_FILLED; + dprintf(" filled>"); + mb->mb_actlen = actlen; + wakeup(mb); + splx(s); +} + diff --git a/sys/dev/ic/rlnvar.h b/sys/dev/ic/rlnvar.h new file mode 100644 index 00000000000..2e9dae49329 --- /dev/null +++ b/sys/dev/ic/rlnvar.h @@ -0,0 +1,141 @@ +/* $OpenBSD: rlnvar.h,v 1.1 1999/07/30 13:43:36 d Exp $ */ +/* + * David Leonard , 1999. Public domain. + * + * Proxim RangeLAN2 soft state copy. + */ + +/* + * Mailboxes are used to communicate card-initiated messages + * from the interrupt handler to other kernel threads. + */ +struct rln_mbox { + void * mb_buf; /* Message buffer */ + size_t mb_len; /* Message buffer size */ + size_t mb_actlen; /* Actual message size */ + u_int8_t mb_state; /* Mailbox state */ +#define RLNMBOX_VOID 0 +#define RLNMBOX_EMPTY 1 +#define RLNMBOX_FILLING 2 +#define RLNMBOX_FILLED 3 +}; + +#define RLN_NMBOX 0x7c /* Same as max msg seq number */ + +/* Soft state */ +struct rln_softc { + struct device sc_dev; + void *sc_ih; /* Interrupt handler */ + struct arpcom sc_arpcom; /* Ethernet common part */ + bus_space_tag_t sc_iot; /* Bus cookie */ + bus_space_handle_t sc_ioh; /* Bus i/o handle */ + + u_int8_t sc_width; /* Bus transfer width */ + u_int8_t sc_irq; /* IRQ for card */ + + u_int16_t sc_cardtype; /* Set from config flags */ +#define RLN_CTYPE_OEM 0x01 +#define RLN_CTYPE_UISA 0x02 +#define RLN_CTYPE_ONE_PIECE 0x04 + + u_int8_t sc_intsel; /* Copy of INTSEL */ + u_int8_t sc_status; /* Copy of STATUS */ + u_int8_t sc_control; /* Copy of CONTROL */ +#ifdef RLNDEBUG_REG + u_int8_t dbg_oreg[8]; /* Last reg value written */ +#endif + + u_int8_t sc_pktseq; /* Card message seq no */ + u_int8_t sc_txseq; /* Tx packet seq no */ + + u_int16_t sc_state; /* Soft state. */ +#define RLN_STATE_SYNC 0x0001 /* Card is synchronised */ +#define RLN_STATE_NEEDINIT 0x0002 /* Card needs reset+init */ +#define RLN_STATE_PROMISC 0x0004 /* Receive all packets */ + + struct rln_mbox sc_mbox[0x80]; /* Per-message mailboxes */ + struct rln_param sc_param; /* User controlled parameters */ +}; + +#define rln_need_reset(sc) \ + (sc)->sc_state |= RLN_STATE_NEEDINIT + +/* Structure used to hold partial read state for rln_rx_pdata() */ +struct rln_pdata { + u_int8_t p_data; /* extra data read but not consumed */ + int p_nremain; /* size of unconsumed data */ +}; +#define RLN_PDATA_INIT {0,0} + +/* Structure used to hold partial transmit state for rln_msg_tx_*() */ +struct rln_msg_tx_state { + int ien; /* saved interrupt state */ + u_int8_t w; /* saved wakup state */ + struct rln_pdata pd; /* saved partial write state */ +}; + +struct rln_mm_cmd; /* fwd decl */ + +#define RLN_WAKEUP_SET 0xff +#define RLN_WAKEUP_NOCHANGE (0x80|0x10) + +void rlnconfig __P((struct rln_softc *)); +int rlnintr __P((void *)); +void rlnread __P((struct rln_softc *, struct rln_mm_cmd *, int)); +int rln_enable __P((struct rln_softc *, int)); +int rln_reset __P((struct rln_softc *)); +u_int8_t rln_wakeup __P((struct rln_softc *, u_int8_t)); +int rln_rx_request __P((struct rln_softc *, int)); +int rln_rx_data __P((struct rln_softc *, void *, int)); +void rln_rx_pdata __P((struct rln_softc *, void *, int, + struct rln_pdata *)); +void rln_rx_end __P((struct rln_softc *)); +void rln_clear_nak __P((struct rln_softc *)); +u_int8_t rln_newseq __P((struct rln_softc *)); + +void rln_msg_tx_data __P((struct rln_softc *, void *, u_int16_t, + struct rln_msg_tx_state *)); +int rln_msg_tx_start __P((struct rln_softc *, void *, int, + struct rln_msg_tx_state *)); +int rln_msg_tx_end __P((struct rln_softc *, + struct rln_msg_tx_state *)); +int rln_msg_txrx __P((struct rln_softc *, void *, int, + void *, int)); + +int rln_mbox_create __P((struct rln_softc *, u_int8_t, void *, + size_t)); +int rln_mbox_wait __P((struct rln_softc *, u_int8_t, int)); +int rln_mbox_lock __P((struct rln_softc *, u_int8_t, void **, + size_t*)); +void rln_mbox_unlock __P((struct rln_softc *, u_int8_t, size_t)); + +/* debug all card operations */ +#ifdef RLNDEBUG +#define dprintf(fmt, args...) printf(fmt , ## args) + /* log(LOG_DEBUG, fmt , ## args) */ +#define dprinthex(buf, len) do { \ + unsigned char *_b = (unsigned char*)(buf); \ + int _i, _l=(len); \ + printf("{"); \ + for(_i = 0; _i < _l; _i++) { \ + printf("%02x", _b[_i]); \ + if (_i % 4 == 3 && _i != _l - 1) \ + printf(","); \ + } \ + printf("}"); \ +} while (0) +#else +#define dprintf(fmt, args...) /* nothing */ +#define dprinthex(buf, len) /* nothing */ +#endif + +/* debug messages to/from card. prints 4-octet groups separated by commas */ +#define RLNDUMP +#define RLNDUMPHEX(buf, buflen) do { \ + int _i; \ + for (_i = 0; _i < (buflen); _i++) { \ + printf("%02x", ((unsigned char *)(buf))[_i]); \ + if (_i != (buflen) - 1 && _i % 4 == 3) \ + printf(","); \ + } \ +} while (0) diff --git a/sys/dev/pcmcia/files.pcmcia b/sys/dev/pcmcia/files.pcmcia index 7abe13d58d7..dfe02667473 100644 --- a/sys/dev/pcmcia/files.pcmcia +++ b/sys/dev/pcmcia/files.pcmcia @@ -1,4 +1,4 @@ -# $OpenBSD: files.pcmcia,v 1.22 1999/07/25 20:04:44 deraadt Exp $ +# $OpenBSD: files.pcmcia,v 1.23 1999/07/30 13:43:37 d Exp $ # $NetBSD: files.pcmcia,v 1.9 1998/06/21 18:45:41 christos Exp $ # # Config.new file and device description for machine-independent PCMCIA code. @@ -52,7 +52,7 @@ file dev/pcmcia/if_xe.c xe_pcmcia # Proxim RangeLAN2 PC-Card attach rln at pcmcia with rln_pcmcia -file dev/pcmcia/if_rl2_pcmcia.c rln_pcmcia +file dev/pcmcia/if_rln_pcmcia.c rln_pcmcia # PCMCIA multi-port serial cards #device pcmcom {[slave = -1]} diff --git a/sys/dev/pcmcia/if_rl2_pcmcia.c b/sys/dev/pcmcia/if_rl2_pcmcia.c deleted file mode 100644 index 00a2e334427..00000000000 --- a/sys/dev/pcmcia/if_rl2_pcmcia.c +++ /dev/null @@ -1,300 +0,0 @@ -/* $OpenBSD: if_rl2_pcmcia.c,v 1.4 1999/07/14 07:22:14 d Exp $ */ -/* - * David Leonard , 1999. Public domain. - * - * Proxim RangeLAN2 PC-Card and compatibles - */ - -#include -#include -#include -#include -#include - -#include - -#ifdef INET -#include -#include -#endif - -#include -#include - -#include -#include -#include - -#include -#include -#include - -struct rl2_pcmcia_softc { - struct rl2_softc sc_rl2; /* real "rl2" softc */ - - struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o information */ - int sc_io_window; /* i/o window for the card */ - struct pcmcia_function *sc_pf; /* our PCMCIA function */ - void *sc_ih; /* our interrupt handle */ -}; - -static int rl2_pcmcia_match __P((struct device *, void *, void *)); -static struct rl2_pcmcia_product * rl2_pcmcia_product_lookup __P(( - struct pcmcia_attach_args *)); -static void rl2_pcmcia_attach __P((struct device *, struct device *, void *)); -static int rl2intr_pcmcia __P((void *arg)); - -#ifdef notyet -static int rl2_pcmcia_enable __P((struct rl2_softc *)); -static void rl2_pcmcia_disable __P((struct rl2_softc *)); -#endif - -struct cfattach rln_pcmcia_ca = { - sizeof(struct rl2_pcmcia_softc), rl2_pcmcia_match, rl2_pcmcia_attach -}; - -#define PCMCIA_CIS_RANGELAN2_7200 { "PROXIM", "LAN CARD", "RANGELAN2", NULL } -#define PCMCIA_CIS_RANGELAN2_7400 { "PROXIM", "LAN PC CARD", "RANGELAN2", NULL } -#define PCMCIA_CIS_SYMPHONY { "PROXIM", "LAN PC CARD", "SYMPHONY", NULL } - -static struct rl2_pcmcia_product { - u_int32_t manufacturer; - u_int32_t product; - const char *name; - u_int8_t flags; -} rl2_pcmcia_products[] = { - { 0x0126, /* Digital */ - 0x1058, /* RoamAbout 2400 FH */ - "Digital RoamAbout 2400 FH", - 0 }, - { 0x8a01, /* AMP */ - 0x0066, /* Wireless */ - "AMP Wireless", - 0 }, - { 0, - 0, - "unknown RangeLAN2 wireless network card", - 0 }, -}; - -/* Match the product and manufacturer codes with known card types */ -static struct rl2_pcmcia_product * -rl2_pcmcia_product_lookup(pa) - struct pcmcia_attach_args *pa; -{ - struct rl2_pcmcia_product *rpp; - - for (rpp = rl2_pcmcia_products; rpp->manufacturer && rpp->product; - rpp++) - if (pa->manufacturer == rpp->manufacturer && - pa->product == rpp->product) - break; - return (rpp); -} - -/* Match card CIS info string with RangeLAN2 cards */ -static int -rl2_pcmcia_match(parent, match, aux) - struct device *parent; - void *match, *aux; -{ - struct pcmcia_attach_args *pa = aux; - static const char *cis_7200[] = PCMCIA_CIS_RANGELAN2_7200; - static const char *cis_7400[] = PCMCIA_CIS_RANGELAN2_7400; - static const char *cis_symp[] = PCMCIA_CIS_SYMPHONY; - static const char **cis_info[] = { cis_7200, cis_7400, cis_symp, NULL }; - const char ***cis; - int i; - - for (cis = cis_info; *cis; cis++) { - for (i = 0; ; i++) { - if ((*cis)[i] == NULL) - return (1); - if (strcmp((*cis)[i], pa->card->cis1_info[i]) != 0) - break; - } - } - return (0); -} - -/* Attach and configure */ -static void -rl2_pcmcia_attach(parent, self, aux) - struct device *parent, *self; - void *aux; -{ - struct rl2_pcmcia_softc *psc = (void *) self; - struct rl2_softc *sc = &psc->sc_rl2; - struct pcmcia_attach_args *pa = aux; - struct pcmcia_config_entry *cfe; - struct rl2_pcmcia_product *rpp; - -#ifdef RL2DEBUG - /* Allowed i/o base addresses from the RoamAbout owner's manual */ - int i; - static bus_addr_t iobases[] = { - 0x270, /* useful in user-space debugging */ - 0x100, 0x120, 0x140, 0x218, 0x270, 0x280, 0x290, 0x298, - 0x2a0, 0x2a8, 0x2e0, 0x300, 0x310, 0x358, 0x360, 0x368, - 0 - }; -#endif - - psc->sc_pf = pa->pf; - cfe = psc->sc_pf->cfe_head.sqh_first; - - /* Guess the transfer width we will be using */ - if (cfe->flags & PCMCIA_CFE_IO16) - sc->sc_width = 16; - else if (cfe->flags & PCMCIA_CFE_IO8) - sc->sc_width = 8; - else - sc->sc_width = 0; - -#ifdef DIAGNOSTIC - /* We only expect one i/o region and no memory region */ - if (cfe->num_memspace != 0) - printf(": unexpected number of memory spaces (%d)\n", - cfe->num_memspace); - if (cfe->num_iospace != 1) - printf(": unexpected number of i/o spaces (%d)\n", - cfe->num_iospace); - else if (cfe->iospace[0].length != RL2_NPORTS) - printf(": unexpected size of i/o space (0x%x)\n", - cfe->iospace[0].length); - if (sc->sc_width == 0) - printf(": unknown bus width\n"); -#endif /* DIAGNOSTIC */ - - pcmcia_function_init(psc->sc_pf, cfe); - - /* Allocate i/o space */ -#ifdef RL2DEBUG - /* Try only those ports from the manual */ - for (i=0; iobases[i] != 0; i++) - if (pcmcia_io_alloc(psc->sc_pf, iobases[i], RL2_NPORTS, - RL2_NPORTS, &psc->sc_pcioh) == 0) - break; - if (iobases[i] == 0) { -#else - if (pcmcia_io_alloc(psc->sc_pf, 0, RL2_NPORTS, - RL2_NPORTS, &psc->sc_pcioh)) { -#endif - printf(": can't alloc i/o space\n"); - return; - } - - sc->sc_iot = psc->sc_pcioh.iot; - sc->sc_ioh = psc->sc_pcioh.ioh; - - /* Map i/o space */ - if (pcmcia_io_map(psc->sc_pf, ((sc->sc_width == 8) ? PCMCIA_WIDTH_IO8 : - (sc->sc_width == 16) ? PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_AUTO), - 0, RL2_NPORTS, &psc->sc_pcioh, &psc->sc_io_window)) { - printf(": can't map i/o space\n"); - return; - } - - /* Enable the card */ - if (pcmcia_function_enable(psc->sc_pf)) { - printf(": function enable failed\n"); - return; - } - -#ifdef notyet - sc->enable = rl2_pcmcia_enable; - sc->disable = rl2_pcmcia_disable; -#endif - - rpp = rl2_pcmcia_product_lookup(pa); - - /* Check if the device has a separate antenna module */ - sc->sc_cardtype = 0; - switch (psc->sc_pf->ccr_base) { - case 0x0100: - sc->sc_cardtype |= RL2_CTYPE_ONE_PIECE; - break; - case 0x0800: - sc->sc_cardtype &= ~RL2_CTYPE_ONE_PIECE; - break; -#ifdef DIAGNOSTIC - default: - printf("\n%s: cannot tell if one or two piece (ccr addr %x)\n", - sc->sc_dev.dv_xname, psc->sc_pf->ccr_base); -#endif - } - - /* The PC-card needs to be told to use 'irq' 15 */ - sc->sc_irq = 15; - - /* - * We need to get an interrupt before configuring, since - * polling registers (the alternative) to reading card - * responses, causes hard lock-ups. - */ - printf("\n"); - sc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, - rl2intr_pcmcia, sc); - if (sc->sc_ih == NULL) - printf("%s: couldn't establish interrupt\n", - sc->sc_dev.dv_xname); - - printf("%s: %s", sc->sc_dev.dv_xname, rpp->name); -#ifdef DIAGNOSTIC - if (rpp->manufacturer == 0) - printf(" manf %04x prod %04x", pa->manufacturer, pa->product); -#endif - rl2config(sc); - printf("\n"); -} - -/* Interrupt handler */ -static int -rl2intr_pcmcia(arg) - void *arg; -{ - struct rl2_softc *sc = (struct rl2_softc *)arg; - struct rl2_pcmcia_softc *psc = (struct rl2_pcmcia_softc *)sc; - int opt; - int ret; - - /* Need to immediately read/write the option register for PC-card */ - opt = pcmcia_ccr_read(psc->sc_pf, PCMCIA_CCR_OPTION); - pcmcia_ccr_write(psc->sc_pf, PCMCIA_CCR_OPTION, opt); - - /* Call actual interrupt handler */ - ret = rl2intr(arg); - - return (ret); -} - -#ifdef notyet -static int -rl2_pcmcia_enable(sc) - struct rl2_softc *sc; -{ - struct rl2_pcmcia_softc *psc = (struct rl2_pcmcia_softc *) sc; - struct pcmcia_function *pf = psc->sc_pf; - - /* Establish the interrupt */ - sc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, - rl2intr_pcmcia, sc); - if (sc->sc_ih == NULL) { - printf("%s: couldn't establish interrupt\n", - sc->sc_dev.dv_xname); - return (1); - } - - return (pcmcia_function_enable(pf)); -} - -static void -rl2_pcmcia_disable(sc) - struct rl2_softc *sc; -{ - struct rl2_pcmcia_softc *psc = (struct rl2_pcmcia_softc *) sc; - - pcmcia_function_disable(psc->sc_pf); - pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih); -} -#endif diff --git a/sys/dev/pcmcia/if_rln_pcmcia.c b/sys/dev/pcmcia/if_rln_pcmcia.c new file mode 100644 index 00000000000..8f42b0f77ef --- /dev/null +++ b/sys/dev/pcmcia/if_rln_pcmcia.c @@ -0,0 +1,300 @@ +/* $OpenBSD: if_rln_pcmcia.c,v 1.1 1999/07/30 13:43:37 d Exp $ */ +/* + * David Leonard , 1999. Public domain. + * + * Proxim RangeLAN2 PC-Card and compatibles + */ + +#include +#include +#include +#include +#include + +#include + +#ifdef INET +#include +#include +#endif + +#include +#include + +#include +#include +#include + +#include +#include +#include + +struct rln_pcmcia_softc { + struct rln_softc sc_rln; /* real "rln" softc */ + + struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o information */ + int sc_io_window; /* i/o window for the card */ + struct pcmcia_function *sc_pf; /* our PCMCIA function */ + void *sc_ih; /* our interrupt handle */ +}; + +static int rln_pcmcia_match __P((struct device *, void *, void *)); +static struct rln_pcmcia_product * rln_pcmcia_product_lookup __P(( + struct pcmcia_attach_args *)); +static void rln_pcmcia_attach __P((struct device *, struct device *, void *)); +static int rlnintr_pcmcia __P((void *arg)); + +#ifdef notyet +static int rln_pcmcia_enable __P((struct rln_softc *)); +static void rln_pcmcia_disable __P((struct rln_softc *)); +#endif + +struct cfattach rln_pcmcia_ca = { + sizeof(struct rln_pcmcia_softc), rln_pcmcia_match, rln_pcmcia_attach +}; + +#define PCMCIA_CIS_RANGELAN2_7200 { "PROXIM", "LAN CARD", "RANGELAN2", NULL } +#define PCMCIA_CIS_RANGELAN2_7400 { "PROXIM", "LAN PC CARD", "RANGELAN2", NULL } +#define PCMCIA_CIS_SYMPHONY { "PROXIM", "LAN PC CARD", "SYMPHONY", NULL } + +static struct rln_pcmcia_product { + u_int32_t manufacturer; + u_int32_t product; + const char *name; + u_int8_t flags; +} rln_pcmcia_products[] = { + { 0x0126, /* Digital */ + 0x1058, /* RoamAbout 2400 FH */ + "Digital RoamAbout 2400 FH", + 0 }, + { 0x8a01, /* AMP */ + 0x0066, /* Wireless */ + "AMP Wireless", + 0 }, + { 0, + 0, + "unknown RangeLAN2 wireless network card", + 0 }, +}; + +/* Match the product and manufacturer codes with known card types */ +static struct rln_pcmcia_product * +rln_pcmcia_product_lookup(pa) + struct pcmcia_attach_args *pa; +{ + struct rln_pcmcia_product *rpp; + + for (rpp = rln_pcmcia_products; rpp->manufacturer && rpp->product; + rpp++) + if (pa->manufacturer == rpp->manufacturer && + pa->product == rpp->product) + break; + return (rpp); +} + +/* Match card CIS info string with RangeLAN2 cards */ +static int +rln_pcmcia_match(parent, match, aux) + struct device *parent; + void *match, *aux; +{ + struct pcmcia_attach_args *pa = aux; + static const char *cis_7200[] = PCMCIA_CIS_RANGELAN2_7200; + static const char *cis_7400[] = PCMCIA_CIS_RANGELAN2_7400; + static const char *cis_symp[] = PCMCIA_CIS_SYMPHONY; + static const char **cis_info[] = { cis_7200, cis_7400, cis_symp, NULL }; + const char ***cis; + int i; + + for (cis = cis_info; *cis; cis++) { + for (i = 0; ; i++) { + if ((*cis)[i] == NULL) + return (1); + if (strcmp((*cis)[i], pa->card->cis1_info[i]) != 0) + break; + } + } + return (0); +} + +/* Attach and configure */ +static void +rln_pcmcia_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct rln_pcmcia_softc *psc = (void *) self; + struct rln_softc *sc = &psc->sc_rln; + struct pcmcia_attach_args *pa = aux; + struct pcmcia_config_entry *cfe; + struct rln_pcmcia_product *rpp; + +#ifdef RLNDEBUG + /* Allowed i/o base addresses from the RoamAbout owner's manual */ + int i; + static bus_addr_t iobases[] = { + 0x270, /* useful in user-space debugging */ + 0x100, 0x120, 0x140, 0x218, 0x270, 0x280, 0x290, 0x298, + 0x2a0, 0x2a8, 0x2e0, 0x300, 0x310, 0x358, 0x360, 0x368, + 0 + }; +#endif + + psc->sc_pf = pa->pf; + cfe = psc->sc_pf->cfe_head.sqh_first; + + /* Guess the transfer width we will be using */ + if (cfe->flags & PCMCIA_CFE_IO16) + sc->sc_width = 16; + else if (cfe->flags & PCMCIA_CFE_IO8) + sc->sc_width = 8; + else + sc->sc_width = 0; + +#ifdef DIAGNOSTIC + /* We only expect one i/o region and no memory region */ + if (cfe->num_memspace != 0) + printf(": unexpected number of memory spaces (%d)\n", + cfe->num_memspace); + if (cfe->num_iospace != 1) + printf(": unexpected number of i/o spaces (%d)\n", + cfe->num_iospace); + else if (cfe->iospace[0].length != RLN_NPORTS) + printf(": unexpected size of i/o space (0x%x)\n", + cfe->iospace[0].length); + if (sc->sc_width == 0) + printf(": unknown bus width\n"); +#endif /* DIAGNOSTIC */ + + pcmcia_function_init(psc->sc_pf, cfe); + + /* Allocate i/o space */ +#ifdef RLNDEBUG + /* Try only those ports from the manual */ + for (i=0; iobases[i] != 0; i++) + if (pcmcia_io_alloc(psc->sc_pf, iobases[i], RLN_NPORTS, + RLN_NPORTS, &psc->sc_pcioh) == 0) + break; + if (iobases[i] == 0) { +#else + if (pcmcia_io_alloc(psc->sc_pf, 0, RLN_NPORTS, + RLN_NPORTS, &psc->sc_pcioh)) { +#endif + printf(": can't alloc i/o space\n"); + return; + } + + sc->sc_iot = psc->sc_pcioh.iot; + sc->sc_ioh = psc->sc_pcioh.ioh; + + /* Map i/o space */ + if (pcmcia_io_map(psc->sc_pf, ((sc->sc_width == 8) ? PCMCIA_WIDTH_IO8 : + (sc->sc_width == 16) ? PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_AUTO), + 0, RLN_NPORTS, &psc->sc_pcioh, &psc->sc_io_window)) { + printf(": can't map i/o space\n"); + return; + } + + /* Enable the card */ + if (pcmcia_function_enable(psc->sc_pf)) { + printf(": function enable failed\n"); + return; + } + +#ifdef notyet + sc->enable = rln_pcmcia_enable; + sc->disable = rln_pcmcia_disable; +#endif + + rpp = rln_pcmcia_product_lookup(pa); + + /* Check if the device has a separate antenna module */ + sc->sc_cardtype = 0; + switch (psc->sc_pf->ccr_base) { + case 0x0100: + sc->sc_cardtype |= RLN_CTYPE_ONE_PIECE; + break; + case 0x0800: + sc->sc_cardtype &= ~RLN_CTYPE_ONE_PIECE; + break; +#ifdef DIAGNOSTIC + default: + printf("\n%s: cannot tell if one or two piece (ccr addr %x)\n", + sc->sc_dev.dv_xname, psc->sc_pf->ccr_base); +#endif + } + + /* The PC-card needs to be told to use 'irq' 15 */ + sc->sc_irq = 15; + + /* + * We need to get an interrupt before configuring, since + * polling registers (the alternative) to reading card + * responses, causes hard lock-ups. + */ + printf("\n"); + sc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, + rlnintr_pcmcia, sc); + if (sc->sc_ih == NULL) + printf("%s: couldn't establish interrupt\n", + sc->sc_dev.dv_xname); + + printf("%s: %s", sc->sc_dev.dv_xname, rpp->name); +#ifdef DIAGNOSTIC + if (rpp->manufacturer == 0) + printf(" manf %04x prod %04x", pa->manufacturer, pa->product); +#endif + rlnconfig(sc); + printf("\n"); +} + +/* Interrupt handler */ +static int +rlnintr_pcmcia(arg) + void *arg; +{ + struct rln_softc *sc = (struct rln_softc *)arg; + struct rln_pcmcia_softc *psc = (struct rln_pcmcia_softc *)sc; + int opt; + int ret; + + /* Need to immediately read/write the option register for PC-card */ + opt = pcmcia_ccr_read(psc->sc_pf, PCMCIA_CCR_OPTION); + pcmcia_ccr_write(psc->sc_pf, PCMCIA_CCR_OPTION, opt); + + /* Call actual interrupt handler */ + ret = rlnintr(arg); + + return (ret); +} + +#ifdef notyet +static int +rln_pcmcia_enable(sc) + struct rln_softc *sc; +{ + struct rln_pcmcia_softc *psc = (struct rln_pcmcia_softc *) sc; + struct pcmcia_function *pf = psc->sc_pf; + + /* Establish the interrupt */ + sc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, + rlnintr_pcmcia, sc); + if (sc->sc_ih == NULL) { + printf("%s: couldn't establish interrupt\n", + sc->sc_dev.dv_xname); + return (1); + } + + return (pcmcia_function_enable(pf)); +} + +static void +rln_pcmcia_disable(sc) + struct rln_softc *sc; +{ + struct rln_pcmcia_softc *psc = (struct rln_pcmcia_softc *) sc; + + pcmcia_function_disable(psc->sc_pf); + pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih); +} +#endif -- cgit v1.2.3