/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2004 David Young. All rights reserved.
*
* This code was written by David Young.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* 3. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY David Young ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL David
* Young BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#include <sys/sysmacros.h>
#include <sys/mac_provider.h>
#include <sys/mac_wifi.h>
#include <sys/net80211.h>
#include <sys/byteorder.h>
#include "rtwreg.h"
#include "rtwvar.h"
#include "smc93cx6var.h"
#include "rtwphy.h"
#include "rtwphyio.h"
/*
* PIO access attributes for registers
*/
};
/*
* DMA access attributes for descriptors and bufs: NOT to be byte swapped.
*/
};
};
/*
* Describes the chip's DMA engine
*/
DMA_ATTR_V0, /* dma_attr version */
0x0000000000000000ull, /* dma_attr_addr_lo */
0xFFFFFFFF, /* dma_attr_addr_hi */
0x00000000FFFFFFFFull, /* dma_attr_count_max */
0x100, /* dma_attr_align */
0xFFFFFFFF, /* dma_attr_burstsizes */
0x00000001, /* dma_attr_minxfer */
0x00000000FFFFull, /* dma_attr_maxxfer */
0xFFFFFFFFFFFFFFFFull, /* dma_attr_seg */
1, /* dma_attr_sgllen */
1, /* dma_attr_granular */
0 /* dma_attr_flags */
};
DMA_ATTR_V0, /* dma_attr version */
0x0000000000000000ull, /* dma_attr_addr_lo */
0xFFFFFFFF, /* dma_attr_addr_hi */
0x00000000FFFFFFFFull, /* dma_attr_count_max */
0xFFFFFFFF, /* dma_attr_burstsizes */
0x00000001, /* dma_attr_minxfer */
0x00000000FFFFull, /* dma_attr_maxxfer */
0xFFFFFFFFFFFFFFFFull, /* dma_attr_seg */
1, /* dma_attr_sgllen */
1, /* dma_attr_granular */
0 /* dma_attr_flags */
};
DMA_ATTR_V0, /* dma_attr version */
0x0000000000000000ull, /* dma_attr_addr_lo */
0xFFFFFFFF, /* dma_attr_addr_hi */
0x00000000FFFFFFFFull, /* dma_attr_count_max */
0xFFFFFFFF, /* dma_attr_burstsizes */
0x00000001, /* dma_attr_minxfer */
0x00000000FFFFull, /* dma_attr_maxxfer */
0xFFFFFFFFFFFFFFFFull, /* dma_attr_seg */
1, /* dma_attr_sgllen */
1, /* dma_attr_granular */
0 /* dma_attr_flags */
};
static void rtw_stop(void *);
static int rtw_quiesce(dev_info_t *);
static int rtw_m_start(void *);
static void rtw_m_stop(void *);
static int rtw_m_promisc(void *, boolean_t);
static int rtw_m_unicst(void *, const uint8_t *);
static int rtw_m_setprop(void *, const char *, mac_prop_id_t,
uint_t, const void *);
static int rtw_m_getprop(void *, const char *, mac_prop_id_t,
uint_t, void *);
static void rtw_m_propinfo(void *, const char *, mac_prop_id_t,
NULL,
NULL, /* mc_getcapab */
NULL,
NULL,
};
&mod_driverops, /* Type of module. This one is a driver */
"realtek 8180L driver 1.7", /* short description */
&rtw_dev_ops /* driver specific ops */
};
};
};
/*
* RTW_DEBUG_ATTACH | RTW_DEBUG_TUNE |
* RTW_DEBUG_ACCESS | RTW_DEBUG_INIT | RTW_DEBUG_PKTFILT |
* RTW_DEBUG_RECV | RTW_DEBUG_XMIT | RTW_DEBUG_80211 | RTW_DEBUG_INTR |
* RTW_DEBUG_PKTDUMP;
*/
/*
* Supported rates for 802.11b modes (in 500Kbps unit).
*/
{ 4, { 2, 4, 11, 22 } };
int
{
}
int
_init(void)
{
int status;
sizeof (rtw_softc_t), 1);
if (status != 0)
return (status);
if (status != 0) {
}
return (status);
}
int
_fini(void)
{
int status;
if (status == 0) {
}
return (status);
}
void
{
if (dbg_flags & rtw_dbg_flags) {
}
}
#ifdef DEBUG
static void
{
/* 16-bit registers */
/* 8-bit registers */
}
#endif /* DEBUG */
static const char *
{
switch (access) {
case RTW_ACCESS_NONE:
return ("none");
case RTW_ACCESS_CONFIG:
return ("config");
case RTW_ACCESS_ANAPARM:
return ("anaparm");
default:
return ("unknown");
}
}
/*
* Enable registers, switch register banks.
*/
void
{
if (enable)
else {
}
}
/*
* requires rtw_config0123_enable(, 1)
*/
void
{
if (enable)
else
cfg3 &= ~RTW_CONFIG3_PARMEN;
}
/*
* requires rtw_anaparm_enable(, 1)
*/
void
{
if (enable)
else
}
static void
{
return;
switch (naccess) {
case RTW_ACCESS_NONE:
case RTW_ACCESS_ANAPARM:
rtw_anaparm_enable(regs, 0);
/*FALLTHROUGH*/
case RTW_ACCESS_CONFIG:
/*FALLTHROUGH*/
case RTW_ACCESS_NONE:
break;
}
break;
case RTW_ACCESS_CONFIG:
case RTW_ACCESS_NONE:
/*FALLTHROUGH*/
case RTW_ACCESS_CONFIG:
break;
case RTW_ACCESS_ANAPARM:
rtw_anaparm_enable(regs, 0);
break;
}
break;
case RTW_ACCESS_ANAPARM:
case RTW_ACCESS_NONE:
/*FALLTHROUGH*/
case RTW_ACCESS_CONFIG:
/*FALLTHROUGH*/
case RTW_ACCESS_ANAPARM:
break;
}
break;
}
}
void
{
"%s: access %s -> %s\n", __func__,
}
void
{
tcr &= ~RTW_TCR_LBK_MASK;
if (enable)
tcr |= RTW_TCR_LBK_CONT;
else
}
static int
{
int i;
for (i = 0; i < 1000; i++) {
if ((cr & RTW_CR_RST) == 0) {
"%s: reset in %dus\n", dvname, i);
return (0);
}
}
return (ETIMEDOUT);
}
static int
{
}
static void
{
}
static void
{
/* XXX necessary? */
}
static int
{
int i;
/* wait 25ms for completion */
for (i = 0; i < 250; i++) {
return (0);
}
DELAY(100);
}
return (ETIMEDOUT);
}
static int
{
int rc;
if (rc != 0)
return (rc);
return (0);
}
void
{
}
void
{
switch (priority) {
case (0):
break;
case (1):
break;
case (2):
break;
}
}
void
{
}
static void
void
{
}
static void
{
return;
}
/*ARGSUSED*/
static void
{
*rcr |= RTW_RCR_ENCS1;
}
static int
const char *dvname)
{
int i;
if (version <= 0x0101) {
"with defaults\n");
return (0);
}
for (i = 0; i < IEEE80211_ADDR_LEN; i++)
*flags |= RTW_F_ANTDIV;
/*
* Note well: the sense of the RTW_SR_RFPARM_DIGPHY bit seems
* to be reversed.
*/
*flags |= RTW_F_DIGPHY;
*flags |= RTW_F_DFLANTB;
switch (*rfchipid) {
case RTW_RFCHIPID_GCT: /* this combo seen in the wild */
rfname = "GCT GRF5101";
paname = "Winspring WS9901";
break;
case RTW_RFCHIPID_MAXIM:
break;
case RTW_RFCHIPID_INTERSIL:
paname = "Intersil <unknown>";
break;
case RTW_RFCHIPID_PHILIPS: /* this combo seen in the wild */
rfname = "Philips SA2400A";
paname = "Philips SA2411";
break;
case RTW_RFCHIPID_RFMD:
/*
* this is the same front-end as an atw(4)!
*/
"LNA: RFMD RF2494, " /* mentioned in Realtek docs */
"SYN: Silicon Labs Si4126";
break;
case RTW_RFCHIPID_RESERVED:
break;
default:
"unknown 0x%02x", *rfchipid);
}
case RTW_CONFIG0_GL_USA:
*locale = RTW_LOCALE_USA;
break;
case RTW_CONFIG0_GL_EUROPE:
break;
case RTW_CONFIG0_GL_JAPAN:
break;
default:
break;
}
return (0);
}
/*
* Returns -1 on failure.
*/
static int
const char *dvname)
{
int rc;
if ((flags & RTW_F_9356SROM) != 0) {
} else {
}
dvname);
return (ENOMEM);
}
/*
* RTL8180 has a single 8-bit register for controlling the
* 93cx6 SROM. There is no "ready" bit. The RTL8180
*/
/*
*/
/*
* TBD bus barriers
*/
return (-1); /* XXX */
}
/*
*/
return (rc);
#ifdef SROM_DEBUG
{
int i;
"\n%s: serial ROM:\n\t", dvname);
}
}
#endif /* DEBUG */
return (0);
}
static void
const char *dvname)
{
const char *method;
switch (rfchipid) {
default:
method = "fallback";
break;
case RTW_RFCHIPID_INTERSIL:
method = "Intersil";
break;
case RTW_RFCHIPID_PHILIPS:
method = "Philips";
break;
case RTW_RFCHIPID_GCT: /* XXX a guess */
case RTW_RFCHIPID_RFMD:
method = "RFMD";
break;
}
}
static void
const char *dvname)
{
int i;
}
switch (locale) {
case RTW_LOCALE_USA: /* 1-11 */
name = "USA";
for (i = 1; i <= 11; i++)
ADD_CHANNEL(chans, i);
break;
case RTW_LOCALE_JAPAN: /* 1-14 */
name = "Japan";
for (i = 1; i <= 14; i++)
ADD_CHANNEL(chans, i);
break;
case RTW_LOCALE_EUROPE: /* 1-13 */
name = "Europe";
for (i = 1; i <= 13; i++)
ADD_CHANNEL(chans, i);
break;
default: /* 10-11 allowed by most countries */
name = "<unknown>";
for (i = 10; i <= 11; i++)
ADD_CHANNEL(chans, i);
break;
}
}
static void
{
/* IEEE80211_C_HOSTAP | IEEE80211_C_MONITOR | IEEE80211_C_WEP */
}
/*ARGSUSED*/
static void
const char *dvname)
{
switch (cfg0 & RTW_CONFIG0_GL_MASK) {
case RTW_CONFIG0_GL_USA:
*locale = RTW_LOCALE_USA;
break;
case RTW_CONFIG0_GL_JAPAN:
break;
case RTW_CONFIG0_GL_EUROPE:
break;
default:
break;
}
}
static int
const char *dvname)
{
"%s: 802.11mac address %x:%x:%x:%x:%x:%x\n", dvname,
return (0);
}
static uint8_t
struct ieee80211_channel *chan)
{
}
static void
{
if (is_last)
ctl |= RTW_RXCTL_EOR;
/* sync the mbuf */
/* sync the descriptor */
sizeof (struct rtw_rxdesc),
}
static void
{
int active;
/* request stop DMA; wait for packets to stop transmitting. */
drv_usecwait(10);
}
static void
{
/* The receive engine will always start at RDSAR. */
RTW_DESC_OFFSET(hd_rx, 0),
sizeof (struct rtw_rxdesc),
}
if (enable)
else
}
/*
* Allocate an area of memory and a DMA handle for accessing it
*/
static int
{
int err;
/*
* Allocate handle
*/
if (err != DDI_SUCCESS)
return (DDI_FAILURE);
/*
* Allocate memory
*/
if (err != DDI_SUCCESS)
return (DDI_FAILURE);
/*
* Bind the two together
*/
return (DDI_FAILURE);
return (DDI_SUCCESS);
}
/*
* Free one allocated area of DMAable memory
*/
static void
{
}
}
}
static void
{
int i, j;
/* Free TX DMA buffer */
for (i = 0; i < RTW_NTXPRI; i++) {
}
}
}
}
/* Free RX DMA buffer */
for (j = 0; j < RTW_RXQLEN; j++) {
rxbf++;
}
sizeof (struct rtw_rxbuf) * RTW_RXQLEN);
}
}
static int
{
int i, j, err;
&rsc->sc_desc_dma);
if (err != DDI_SUCCESS)
goto error;
for (i = 0; i < RTW_NTXPRI; i++) {
i, vtx[i]);
sizeof (struct rtw_txbuf),
sizeof (struct rtw_txbuf),
/* virtual address of the first descriptor */
/* allocate data structures to describe TX DMA buffers */
/* alloc DMA memory */
if (err != DDI_SUCCESS)
goto error;
}
}
/* virtual address of the first descriptor */
/* allocate data structures to describe RX DMA buffers */
/* alloc DMA memory */
if (err != DDI_SUCCESS)
goto error;
}
return (DDI_SUCCESS);
return (DDI_FAILURE);
}
static void
{
}
static void
{
int i, j;
int is_last;
/* sync tx desc and tx buf */
for (i = 0; i < RTW_NTXPRI; i++) {
}
}
baddr_desc = ptx[i];
for (j = 0; j < rtw_qlen[i]; j++) {
if (j == (rtw_qlen[i] - 1)) {
is_last = 1;
} else {
is_last = 0;
}
if (is_last) {
} else {
}
txbf++;
taddr_desc += sizeof (struct rtw_txdesc);
}
}
if (!flag)
return;
/* sync rx desc and rx buf */
for (j = 0; j < RTW_RXQLEN; j++) {
if (j == (RTW_RXQLEN - 1))
is_last = 1;
else
is_last = 0;
rxbf++;
}
}
static void
{
}
const char *
{
switch (power) {
case RTW_ON:
return ("on");
case RTW_SLEEP:
return ("sleep");
case RTW_OFF:
return ("off");
default:
return ("unknown");
}
}
/*
* XXX For Maxim, I am using the RFMD settings gleaned from the
* reference driver, plus a magic Maxim "ON" value that comes from
* the Realtek document "Windows PG for Rtl8180."
*/
/*ARGSUSED*/
static void
{
switch (power) {
case RTW_OFF:
if (before_rf)
return;
break;
case RTW_SLEEP:
if (!before_rf)
return;
break;
case RTW_ON:
if (!before_rf)
return;
break;
}
"%s: power state %s, %s RF, reg[ANAPARM] <- %08x\n",
}
/*
* XXX I am using the RFMD settings gleaned from the reference
* driver. They agree
*/
/*ARGSUSED*/
static void
{
switch (power) {
case RTW_OFF:
if (before_rf)
return;
break;
case RTW_SLEEP:
if (!before_rf)
return;
break;
case RTW_ON:
if (!before_rf)
return;
break;
}
"%s: power state %s, %s RF, reg[ANAPARM] <- %08x\n",
}
static void
{
switch (power) {
case RTW_OFF:
if (before_rf)
return;
break;
case RTW_SLEEP:
if (!before_rf)
return;
break;
case RTW_ON:
if (!before_rf)
return;
if (digphy) {
/* XXX guess */
} else
break;
}
"%s: power state %s, %s RF, reg[ANAPARM] <- %08x\n",
}
static void
int digphy)
{
}
static void
{
}
static int
{
}
static int
{
int rc;
"%s: %s->%s\n", __func__,
return (0);
switch (power) {
case RTW_ON:
/* TBD set LEDs */
break;
case RTW_SLEEP:
/* TBD */
break;
case RTW_OFF:
/* TBD */
break;
}
if (rc == 0)
else
return (rc);
}
void
{
int rc;
return;
/* turn off PHY */
}
}
int
{
return (EIO);
}
}
return (0);
}
static void
{
/* I'm guessing that MSR is protected as CONFIG[0123] are. */
switch (opmode) {
case IEEE80211_M_AHDEMO:
case IEEE80211_M_IBSS:
break;
case IEEE80211_M_HOSTAP:
break;
case IEEE80211_M_STA:
break;
}
}
static void
{
/* MAC auto-reset PHY (huh?) */
/* DMA whole Rx packets, only. Set Tx DMA burst size to 1024 bytes. */
case IEEE80211_M_AHDEMO:
case IEEE80211_M_IBSS:
/* receive broadcasts in our BSS */
break;
default:
break;
}
#if 0
/* XXX accept all broadcast if scanning */
#endif
"RTW_MAR0 %08x RTW_MAR1 %08x RTW_RCR %08x\n",
}
static void
{
tcr |= RTW_TCR_CWMIN;
tcr &= ~RTW_TCR_MXDMA_MASK;
tcr &= ~RTW_TCR_LBK_MASK;
}
int
{
int rc = 0;
if (rc != 0)
return (-1);
return (0);
}
static int
{
int rc;
if (chan == IEEE80211_CHAN_ANY) {
return (-1);
}
return (0);
}
/* XXX condition on powersaving */
}
return (rc);
}
static int
{
int rc = 0;
goto out;
if (rc != 0) {
return (rc);
}
rsc->sc_invalid = 0;
out:
return (rc);
}
static struct rtw_rf *
{
int rtw_host_rfio;
switch (rfchipid) {
default:
break;
case RTW_RFCHIPID_INTERSIL:
case RTW_RFCHIPID_PHILIPS:
case RTW_RFCHIPID_GCT: /* XXX a guess */
case RTW_RFCHIPID_RFMD:
rtw_host_rfio = 1;
break;
}
switch (rfchipid) {
case RTW_RFCHIPID_MAXIM:
break;
case RTW_RFCHIPID_PHILIPS:
break;
case RTW_RFCHIPID_RFMD:
/* XXX RFMD has no RF constructor */
/*FALLTHROUGH*/
default:
return (NULL);
}
}
return (rf);
}
/*
* Revision C and later use a different PHY delay setting than
* revisions A and B.
*/
static uint8_t
{
return (phydelay);
}
static int
{
int rate;
else
rate = 0;
return (rate & IEEE80211_RATE_VAL);
}
/*
* Arguments in:
*
* paylen: payload length (no FCS, no WEP header)
*
* hdrlen: header length
*
* rate: MSDU speed, units 500kb/s
*
* flags: IEEE80211_F_SHPREAMBLE (use short preamble),
* IEEE80211_F_SHSLOT (use short slot length)
*
* Arguments out:
*
* d: 802.11 Duration field for RTS,
* 802.11 Duration field for data frame,
* PLCP Length for data frame,
* residual octets at end of data slot
*/
static int
struct rtw_ieee80211_duration *d)
{
/*
* RTS reserves medium for SIFS | CTS | SIFS | (DATA) | SIFS | ACK
* DATA reserves medium for SIFS | ACK
*
*/
if ((flags & IEEE80211_F_SHPREAMBLE) != 0)
else
d->d_residue = 0;
if (remainder != 0) {
if (rate == 22)
data_dur++;
}
switch (rate) {
case 2: /* 1 Mb/s */
case 4: /* 2 Mb/s */
ctsrate = 2;
break;
case 11: /* 5.5 Mb/s */
case 22: /* 11 Mb/s */
case 44: /* 22 Mb/s */
ctsrate = 4;
break;
default:
/* TBD */
return (-1);
}
d->d_plcp_len = data_dur;
d->d_rts_dur =
ack;
d->d_data_dur = ack;
return (0);
}
/*
* Arguments in:
*
* wh: 802.11 header
*
* paylen: payload length (no FCS, no WEP header)
*
* rate: MSDU speed, units 500kb/s
*
* fraglen: fragment length, set to maximum (or higher) for no
* fragmentation
*
* flags: IEEE80211_F_PRIVACY (hardware adds WEP),
* IEEE80211_F_SHPREAMBLE (use short preamble),
* IEEE80211_F_SHSLOT (use short slot length)
*
* Arguments out:
*
*
*/
static int
{
/* don't think about addr4 here */
hdrlen = sizeof (struct ieee80211_frame);
paylen -= 8;
} else
if (npkt == 0) /* no fragments */
else if (lastlen0 != 0) { /* a short "tail" fragment */
npkt++;
} else /* full-length "tail" fragment */
if (npkt > 1)
else
if (rc == -1)
return (rc);
if (npkt <= 1) {
return (0);
}
}
static int
{
/* ieee80211_crypto_encap() needs a single mblk */
return (-1);
}
}
if (iswep) {
struct ieee80211_key *k;
if (k == NULL) {
__func__);
return (-1);
}
}
#if 0
#endif
/* RTW_DMA_SYNC(bf->bf_dma, DDI_DMA_SYNC_FORDEV); */
return (-1);
}
/* setup descriptor */
ctl0 |= RTW_TXCTL0_SPLCP;
}
/* XXX do real rate control */
rate = 2;
else {
}
switch (rate) {
default:
case 2:
break;
case 4:
break;
case 11:
break;
case 22:
break;
}
/* XXX >= ? Compare after fragmentation? */
ctl0 |= RTW_TXCTL0_RTSEN;
}
}
"%s: fail compute duration\n", __func__);
return (-1);
}
"%s: seg too long\n", __func__);
return (-1);
}
sizeof (struct rtw_txdesc),
"descriptor: order = %d, phy_addr=%x, ctl0=%x,"
rsc->sc_pktxmt64++;
return (0);
}
static int
{
rsc->sc_noxmtbuf++;
if ((type & IEEE80211_FC0_TYPE_MASK) ==
__func__);
} else {
}
return (1);
}
/* assemble 802.11 frame here */
if (ret != 0) {
if ((type & IEEE80211_FC0_TYPE_MASK) !=
}
return (1);
}
return (0);
}
static mblk_t *
{
return (NULL);
}
break;
}
}
return (mp);
}
static void
{
rsc->sc_scan_id = 0;
(void) ieee80211_next_scan(ic);
}
}
static void
{
int i;
for (i = 0; i < IEEE80211_ADDR_LEN; i++)
/* TBD WEP */
/* RTW_WRITE8(regs, RTW_SCR, 0); */
}
/*
* Set the starting transmit rate for a node.
*/
static void
{
/*
* No fixed rate is requested. For 11b start with
* the highest negotiated rate; otherwise, for 11g
* and 11a, we start "in the middle" at 24Mb or 36Mb.
*/
/*
* Scan the negotiated rate set to find the
* closest rate.
*/
/* NB: the rate set is assumed sorted */
srate--)
;
}
} else {
/*
* A fixed rate is to be used; We know the rate is
* there because the rate set is checked when the
* station associates.
*/
/* NB: the rate set is assumed sorted */
srate--)
;
}
}
/*
* Reset the rate control state for each 802.11 state transition.
*/
static void
{
/*
* Reset local xmit state; this is really only
* meaningful when operating in station mode.
*/
if (state == IEEE80211_S_RUN) {
} else {
}
}
}
/*
* Examine and potentially adjust the transmit rate.
*/
static void
{
/* err ratio is high -> down */
mod = -1;
switch (mod) {
case -1:
if (nrate > 0) {
nrate--;
}
break;
case 1:
nrate++;
}
break;
}
drv_usectohz(1000000));
}
static int32_t
{
int error;
"rtw_new_state: ostate:0x%x, nstate:0x%x, opmode:0x%x\n",
if (rsc->sc_scan_id != 0) {
rsc->sc_scan_id = 0;
}
if (rsc->sc_ratectl_id != 0) {
rsc->sc_ratectl_id = 0;
}
if (nstate != IEEE80211_S_INIT) {
return (error);
}
}
switch (nstate) {
case IEEE80211_S_INIT:
break;
case IEEE80211_S_SCAN:
drv_usectohz(200000));
break;
case IEEE80211_S_RUN:
case IEEE80211_M_HOSTAP:
case IEEE80211_M_IBSS:
/* TBD */
/*FALLTHROUGH*/
case IEEE80211_M_AHDEMO:
case IEEE80211_M_STA:
"rtw_new_state: sta\n");
drv_usectohz(1000000));
break;
case IEEE80211_M_MONITOR:
break;
}
break;
case IEEE80211_S_ASSOC:
case IEEE80211_S_AUTH:
break;
}
/*
* Invoke the parent method to complete the work.
*/
return (error);
}
static void
{
/*
* ratetbl[4] = {2, 4, 11, 22};
*/
for (i = 0; i < RTW_RXQLEN; i++) {
sizeof (struct rtw_rxdesc),
n++;
/* htsfth = ds->rd_tsfth; */
/* still belongs to NIC */
if ((hstat & RTW_RXSTAT_OWN) != 0) {
if (n > 1) {
"%s: n > 1\n", __func__);
break;
}
RTW_DESC_OFFSET(hd_rx, 0),
sizeof (struct rtw_rxdesc),
if ((hstat & RTW_RXSTAT_OWN) != 0)
break;
next = 0 /* RTW_RXQLEN - 1 */;
continue;
}
rsc->sc_pktrcv64++;
if ((hstat & RTW_RXSTAT_IOERROR) != 0) {
"rx descriptor %d\n",
goto next;
}
/* CRC is included with the packet; trim it off. */
/* len -= IEEE80211_CRC_LEN; */
if (hwrate >= 4) {
goto next;
}
if ((hstat & RTW_RXSTAT_RES) != 0 &&
goto next;
}
/* if bad flags, skip descriptor */
"rtw too many rx segments\n");
goto next;
}
else {
/*
* TBD find out each front-end's LNA gain in the
* front-end's units
*/
if ((hrssi & RTW_RXRSSI_IMR_LNA) == 0)
rssi |= 0x80;
}
/* sq = MASK_AND_RSHIFT(hrssi, RTW_RXRSSI_SQ); */
/* deal with the frame itself here */
rsc->sc_norcvbuf++;
return;
}
len -= IEEE80211_CRC_LEN;
goto next;
}
next:
if (next == 63)
is_last = 1;
else
is_last = 0;
}
}
static void
{
return;
}
"rtw_ring_recycling: dirty bf[%d] NULL\n", pri);
return;
}
cnt++;
if (idx == 63)
else
sizeof (struct rtw_txdesc),
"%s rtw_ring_recycling: stat=%x, pri=%x\n",
if (hstat & RTW_TXSTAT_TOK)
else {
"TX err @%d, o %d, retry[%d], isr[0x%x], cnt %d\n",
} else {
}
}
rsc->sc_tx_retr +=
(hstat & RTW_TXSTAT_DRC_MASK);
rsc->sc_xmtretry +=
(hstat & RTW_TXSTAT_DRC_MASK);
bf);
rsc->sc_need_reschedule = 0;
}
"rtw_ring_recycling: nfree[%d]=%d\n",
sizeof (struct rtw_txdesc),
}
}
static void
{
}
static uint_t
{
/* LINTED E_BAD_PTR_CAST_ALIGN */
if (isr == 0) {
return (DDI_INTR_UNCLAIMED);
}
#ifdef DEBUG
} \
}
}
#endif /* DEBUG */
if ((isr & RTW_INTR_RX) != 0) {
}
if ((isr & RTW_INTR_TIMEOUT) != 0)
if ((isr & RTW_INTR_TX) != 0)
return (DDI_INTR_CLAIMED);
}
static void
{
}
static void
{
}
/*
* quiesce(9E) entry point.
*
* This function is called when the system is single-threaded at high
* PIL with preemption disabled. Therefore, this function must not be
* blocked.
*
* This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
* DDI_FAILURE indicates an error condition and should almost never happen.
*/
int
{
rtw_dbg_flags = 0;
return (DDI_SUCCESS);
}
/*
*/
static int
{
int err;
}
err = 0;
}
return (err);
}
static int
{
int err;
return (err);
}
static void
{
}
static int
{
int ret;
#ifdef DEBUG
#endif
if (ret) {
return (EIO);
}
return (0);
}
static int
{
uint32_t t;
return (0);
}
static int
{
if (on)
else
return (0);
}
static int
{
uint32_t t;
if (add) {
} else {
}
return (0);
}
static void
{
int err;
(void) ieee80211_new_state(ic,
IEEE80211_S_SCAN, -1);
}
}
}
static int
{
switch (stat) {
case MAC_STAT_IFSPEED:
break;
case MAC_STAT_NOXMTBUF:
break;
case MAC_STAT_NORCVBUF:
break;
case MAC_STAT_RBYTES:
break;
case MAC_STAT_IPACKETS:
break;
case MAC_STAT_OBYTES:
break;
case MAC_STAT_OPACKETS:
break;
case WIFI_STAT_TX_RETRANS:
break;
case WIFI_STAT_TX_FRAGS:
case WIFI_STAT_MCAST_TX:
case WIFI_STAT_RTS_SUCCESS:
case WIFI_STAT_RTS_FAILURE:
case WIFI_STAT_ACK_FAILURE:
case WIFI_STAT_RX_FRAGS:
case WIFI_STAT_MCAST_RX:
case WIFI_STAT_RX_DUPS:
default:
*val = 0;
break;
}
return (0);
}
static void
{
int i;
for (i = 0; i < RTW_NTXPRI; i++) {
}
}
static int
{
uint32_t i;
switch (cmd) {
case DDI_ATTACH:
break;
case DDI_RESUME:
if (err == 0) {
}
}
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
"Unable to alloc softstate\n");
return (DDI_FAILURE);
}
if (err != DDI_SUCCESS) {
"ddi_regs_map_setup() failed");
goto attach_fail0;
}
if (!csz)
csz = 16;
/*
* Enable response to memory space accesses,
* and enabe bus master.
*/
"set command reg to 0x%x \n", command);
if (err != DDI_SUCCESS) {
"ddi_regs_map_setup() failed");
goto attach_fail0;
}
if (err != DDI_SUCCESS) {
"failed to init dma: %d\n", err);
goto attach_fail1;
}
/*
* Stop the transmit and receive processes. First stop DMA,
* then disable receiver and transmitter.
*/
/* Reset the chip to a known state. */
"failed to reset\n");
goto attach_fail2;
}
"rtw") != 0) {
"failed to read srom\n");
goto attach_fail2;
}
"rtw") != 0) {
" malformed serial ROM\n");
goto attach_fail3;
}
goto attach_fail3;
}
"rtw");
"rtw");
"rtw") != 0)
goto attach_fail4;
ic->ic_def_txkey = 0;
!= DDI_SUCCESS) {
"Can not get iblock cookie for INT\n");
goto attach_fail5;
}
for (i = 0; i < RTW_NTXPRI; i++) {
}
"Can not add intr for rtw driver\n");
goto attach_fail7;
}
/*
* Provide initial settings for the WiFi plugin; whenever this
* information changes, we need to call mac_plugindata_update()
*/
"MAC version mismatch\n");
goto attach_fail8;
}
if (err != 0) {
"mac_register err %x\n", err);
goto attach_fail8;
}
/* Create minor node of type DDI_NT_NET_WIFI */
"rtw", instance);
if (err != DDI_SUCCESS) {
"Create minor node failed - %d\n", err);
goto attach_fail9;
}
rsc->sc_need_reschedule = 0;
return (DDI_SUCCESS);
return (DDI_FAILURE);
}
static int32_t
{
switch (cmd) {
case DDI_DETACH:
break;
case DDI_SUSPEND:
if (rsc->sc_invalid == 0) {
}
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
return (DDI_FAILURE);
return (DDI_FAILURE);
/* free intterrupt resources */
/*
* Unregister from the MAC layer subsystem
*/
return (DDI_SUCCESS);
}