sync ural with HEAD.

Brings automatic rate control in BSS mode and other goodies.
This commit is contained in:
damien 2006-01-29 14:16:36 +00:00
parent f4e3675df0
commit 384ea2a095
4 changed files with 474 additions and 150 deletions

View File

@ -1,7 +1,7 @@
/* $FreeBSD$ */
/*-
* Copyright (c) 2005
* Copyright (c) 2005, 2006
* Damien Bergamini <damien.bergamini@free.fr>
*
* Permission to use, copy, modify, and distribute this software for any
@ -70,7 +70,7 @@ __FBSDID("$FreeBSD$");
#ifdef USB_DEBUG
#define DPRINTF(x) do { if (uraldebug > 0) logprintf x; } while (0)
#define DPRINTFN(n, x) do { if (uraldebug >= (n)) logprintf x; } while (0)
int uraldebug = 2;
int uraldebug = 0;
SYSCTL_NODE(_hw_usb, OID_AUTO, ural, CTLFLAG_RW, 0, "USB ural");
SYSCTL_INT(_hw_usb_ural, OID_AUTO, debug, CTLFLAG_RW, &uraldebug, 0,
"ural debug level");
@ -90,9 +90,11 @@ static const struct usb_devno ural_devs[] = {
{ USB_VENDOR_GUILLEMOT, USB_PRODUCT_GUILLEMOT_HWGUSB254 },
{ USB_VENDOR_LINKSYS4, USB_PRODUCT_LINKSYS4_WUSB54G },
{ USB_VENDOR_LINKSYS4, USB_PRODUCT_LINKSYS4_WUSB54GP },
{ USB_VENDOR_LINKSYS4, USB_PRODUCT_LINKSYS4_HU200TS },
{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_KG54 },
{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_KG54AI },
{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_KG54YB },
{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_NINWIFI },
{ USB_VENDOR_MSI, USB_PRODUCT_MSI_RT2570 },
{ USB_VENDOR_MSI, USB_PRODUCT_MSI_RT2570_2 },
{ USB_VENDOR_MSI, USB_PRODUCT_MSI_RT2570_3 },
@ -113,6 +115,7 @@ Static void ural_next_scan(void *);
Static void ural_task(void *);
Static int ural_newstate(struct ieee80211com *,
enum ieee80211_state, int);
Static int ural_rxrate(struct ural_rx_desc *);
Static void ural_txeof(usbd_xfer_handle, usbd_private_handle,
usbd_status);
Static void ural_rxeof(usbd_xfer_handle, usbd_private_handle,
@ -132,6 +135,7 @@ Static void ural_start(struct ifnet *);
Static void ural_watchdog(struct ifnet *);
Static int ural_reset(struct ifnet *);
Static int ural_ioctl(struct ifnet *, u_long, caddr_t);
Static void ural_set_testmode(struct ural_softc *);
Static void ural_eeprom_read(struct ural_softc *, uint16_t, void *,
int);
Static uint16_t ural_read(struct ural_softc *, uint16_t);
@ -145,10 +149,11 @@ Static uint8_t ural_bbp_read(struct ural_softc *, uint8_t);
Static void ural_rf_write(struct ural_softc *, uint8_t, uint32_t);
Static void ural_set_chan(struct ural_softc *,
struct ieee80211_channel *);
#if 0
Static void ural_disable_rf_tune(struct ural_softc *);
#endif
Static void ural_enable_tsf_sync(struct ural_softc *);
Static void ural_update_slot(struct ifnet *);
Static void ural_set_txpreamble(struct ural_softc *);
Static void ural_set_basicrates(struct ural_softc *);
Static void ural_set_bssid(struct ural_softc *, uint8_t *);
Static void ural_set_macaddr(struct ural_softc *, uint8_t *);
Static void ural_update_promisc(struct ural_softc *);
@ -159,6 +164,13 @@ Static void ural_set_txantenna(struct ural_softc *, int);
Static void ural_set_rxantenna(struct ural_softc *, int);
Static void ural_init(void *);
Static void ural_stop(void *);
Static void ural_amrr_start(struct ural_softc *,
struct ieee80211_node *);
Static void ural_amrr_timeout(void *);
Static void ural_amrr_update(usbd_xfer_handle, usbd_private_handle,
usbd_status status);
Static void ural_ratectl(struct ural_amrr *,
struct ieee80211_node *);
/*
* Supported rates for 802.11a/b/g modes (in 500Kbps unit).
@ -292,7 +304,6 @@ static const struct {
uint32_t r2;
uint32_t r4;
} ural_rf5222[] = {
/* channels in the 2.4GHz band */
{ 1, 0x08808, 0x0044d, 0x00282 },
{ 2, 0x08808, 0x0044e, 0x00282 },
{ 3, 0x08808, 0x0044f, 0x00282 },
@ -308,7 +319,6 @@ static const struct {
{ 13, 0x08808, 0x00469, 0x00282 },
{ 14, 0x08808, 0x0046b, 0x00286 },
/* channels in the 5.2GHz band */
{ 36, 0x08804, 0x06225, 0x00287 },
{ 40, 0x08804, 0x06226, 0x00287 },
{ 44, 0x08804, 0x06227, 0x00287 },
@ -411,6 +421,7 @@ USB_ATTACH(ural)
usb_init_task(&sc->sc_task, ural_task, sc);
callout_init(&sc->scan_ch, debug_mpsafenet ? CALLOUT_MPSAFE : 0);
callout_init(&sc->amrr_ch, 0);
/* retrieve RT2570 rev. no */
sc->asic_rev = ural_read(sc, RAL_MAC_CSR0);
@ -445,9 +456,14 @@ USB_ATTACH(ural)
ic->ic_state = IEEE80211_S_INIT;
/* set device capabilities */
ic->ic_caps = IEEE80211_C_MONITOR | IEEE80211_C_IBSS |
IEEE80211_C_HOSTAP | IEEE80211_C_SHPREAMBLE | IEEE80211_C_SHSLOT |
IEEE80211_C_PMGT | IEEE80211_C_TXPMGT | IEEE80211_C_WPA;
ic->ic_caps =
IEEE80211_C_IBSS | /* IBSS mode supported */
IEEE80211_C_MONITOR | /* monitor mode supported */
IEEE80211_C_HOSTAP | /* HostAp mode supported */
IEEE80211_C_TXPMGT | /* tx power management */
IEEE80211_C_SHPREAMBLE | /* short preamble supported */
IEEE80211_C_SHSLOT | /* short slot time supported */
IEEE80211_C_WPA; /* 802.11i */
if (sc->rf_rev == RAL_RF_5222) {
/* set supported .11a rates */
@ -517,6 +533,12 @@ USB_DETACH(ural)
usb_rem_task(sc->sc_udev, &sc->sc_task);
callout_stop(&sc->scan_ch);
callout_stop(&sc->amrr_ch);
if (sc->amrr_xfer != NULL) {
usbd_free_xfer(sc->amrr_xfer);
sc->amrr_xfer = NULL;
}
if (sc->sc_rx_pipeh != NULL) {
usbd_abort_pipe(sc->sc_rx_pipeh);
@ -676,7 +698,7 @@ ural_media_change(struct ifnet *ifp)
return error;
}
if ((ifp->if_flags & IFF_UP) &&
if ((ifp->if_flags & IFF_UP) &&
(ifp->if_drv_flags & IFF_DRV_RUNNING))
ural_init(sc);
@ -705,6 +727,7 @@ ural_task(void *arg)
struct ural_softc *sc = arg;
struct ieee80211com *ic = &sc->sc_ic;
enum ieee80211_state ostate;
struct ieee80211_node *ni;
struct mbuf *m;
ostate = ic->ic_state;
@ -736,31 +759,25 @@ ural_task(void *arg)
case IEEE80211_S_RUN:
ural_set_chan(sc, ic->ic_curchan);
/* update basic rate set */
if (ic->ic_curmode == IEEE80211_MODE_11B) {
/* 11b basic rates: 1, 2Mbps */
ural_write(sc, RAL_TXRX_CSR11, 0x3);
} else if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) {
/* 11a basic rates: 6, 12, 24Mbps */
ural_write(sc, RAL_TXRX_CSR11, 0x150);
} else {
/* 11g basic rates: 1, 2, 5.5, 11, 6, 12, 24Mbps */
ural_write(sc, RAL_TXRX_CSR11, 0x15f);
}
ni = ic->ic_bss;
if (ic->ic_opmode != IEEE80211_M_MONITOR)
ural_set_bssid(sc, ic->ic_bss->ni_bssid);
if (ic->ic_opmode != IEEE80211_M_MONITOR) {
ural_update_slot(ic->ic_ifp);
ural_set_txpreamble(sc);
ural_set_basicrates(sc);
ural_set_bssid(sc, ni->ni_bssid);
}
if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
ic->ic_opmode == IEEE80211_M_IBSS) {
m = ieee80211_beacon_alloc(ic, ic->ic_bss, &sc->sc_bo);
m = ieee80211_beacon_alloc(ic, ni, &sc->sc_bo);
if (m == NULL) {
printf("%s: could not allocate beacon\n",
USBDEVNAME(sc->sc_dev));
return;
}
if (ural_tx_bcn(sc, m, ic->ic_bss) != 0) {
if (ural_tx_bcn(sc, m, ni) != 0) {
printf("%s: could not send beacon\n",
USBDEVNAME(sc->sc_dev));
return;
@ -772,6 +789,12 @@ ural_task(void *arg)
if (ic->ic_opmode != IEEE80211_M_MONITOR)
ural_enable_tsf_sync(sc);
/* enable automatic rate adaptation in STA mode */
if (ic->ic_opmode == IEEE80211_M_STA &&
ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE)
ural_amrr_start(sc, ni);
break;
}
@ -785,6 +808,7 @@ ural_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
usb_rem_task(sc->sc_udev, &sc->sc_task);
callout_stop(&sc->scan_ch);
callout_stop(&sc->amrr_ch);
/* do it in a process context */
sc->sc_state = nstate;
@ -798,7 +822,41 @@ ural_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
#define RAL_ACK_SIZE 14 /* 10 + 4(FCS) */
#define RAL_CTS_SIZE 14 /* 10 + 4(FCS) */
#define RAL_SIFS 10
#define RAL_SIFS 10 /* us */
#define RAL_RXTX_TURNAROUND 5 /* us */
/*
* This function is only used by the Rx radiotap code.
*/
Static int
ural_rxrate(struct ural_rx_desc *desc)
{
if (le32toh(desc->flags) & RAL_RX_OFDM) {
/* reverse function of ural_plcp_signal */
switch (desc->rate) {
case 0xb: return 12;
case 0xf: return 18;
case 0xa: return 24;
case 0xe: return 36;
case 0x9: return 48;
case 0xd: return 72;
case 0x8: return 96;
case 0xc: return 108;
}
} else {
if (desc->rate == 10)
return 2;
if (desc->rate == 20)
return 4;
if (desc->rate == 55)
return 11;
if (desc->rate == 110)
return 22;
}
return 2; /* should not get there */
}
Static void
ural_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
@ -815,7 +873,7 @@ ural_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
USBDEVNAME(sc->sc_dev), usbd_errstr(status));
if (status == USBD_STALLED)
usbd_clear_endpoint_stall(sc->sc_rx_pipeh);
usbd_clear_endpoint_stall_async(sc->sc_rx_pipeh);
ifp->if_oerrors++;
return;
@ -846,7 +904,7 @@ ural_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
struct ural_rx_desc *desc;
struct ieee80211_frame *wh;
struct ieee80211_node *ni;
struct mbuf *m;
struct mbuf *mnew, *m;
int len;
if (status != USBD_NORMAL_COMPLETION) {
@ -854,14 +912,15 @@ ural_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
return;
if (status == USBD_STALLED)
usbd_clear_endpoint_stall(sc->sc_rx_pipeh);
usbd_clear_endpoint_stall_async(sc->sc_rx_pipeh);
goto skip;
}
usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL);
if (len < RAL_RX_DESC_SIZE) {
printf("%s: xfer too short %d\n", USBDEVNAME(sc->sc_dev), len);
if (len < RAL_RX_DESC_SIZE + IEEE80211_MIN_LEN) {
DPRINTF(("%s: xfer too short %d\n", USBDEVNAME(sc->sc_dev),
len));
ifp->if_ierrors++;
goto skip;
}
@ -880,11 +939,33 @@ ural_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
goto skip;
}
/* finalize mbuf */
mnew = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
if (mnew == NULL) {
ifp->if_ierrors++;
goto skip;
}
m = data->m;
data->m = mnew;
data->buf = mtod(data->m, uint8_t *);
/* finalize mbuf */
m->m_pkthdr.rcvif = ifp;
m->m_pkthdr.len = m->m_len = (le32toh(desc->flags) >> 16) & 0xfff;
m->m_flags |= M_HASFCS; /* hardware appends FCS */
m->m_flags |= M_HASFCS; /* h/w leaves FCS */
if (sc->sc_drvbpf != NULL) {
struct ural_rx_radiotap_header *tap = &sc->sc_rxtap;
tap->wr_flags = IEEE80211_RADIOTAP_F_FCS;
tap->wr_rate = ural_rxrate(desc);
tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
tap->wr_antenna = sc->rx_ant;
tap->wr_antsignal = desc->rssi;
bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m);
}
wh = mtod(m, struct ieee80211_frame *);
ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
@ -895,15 +976,6 @@ ural_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
/* node is no longer needed */
ieee80211_free_node(ni);
data->m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
if (data->m == NULL) {
printf("%s: could not allocate rx mbuf\n",
USBDEVNAME(sc->sc_dev));
return;
}
data->buf = mtod(data->m, uint8_t *);
DPRINTFN(15, ("rx done\n"));
skip: /* setup a new transfer */
@ -955,35 +1027,19 @@ Static uint16_t
ural_txtime(int len, int rate, uint32_t flags)
{
uint16_t txtime;
int ceil, dbps;
if (RAL_RATE_IS_OFDM(rate)) {
/*
* OFDM TXTIME calculation.
* From IEEE Std 802.11a-1999, pp. 37.
*/
dbps = rate * 2; /* data bits per OFDM symbol */
ceil = (16 + 8 * len + 6) / dbps;
if ((16 + 8 * len + 6) % dbps != 0)
ceil++;
txtime = 16 + 4 + 4 * ceil + 6;
/* IEEE Std 802.11a-1999, pp. 37 */
txtime = (8 + 4 * len + 3 + rate - 1) / rate;
txtime = 16 + 4 + 4 * txtime + 6;
} else {
/*
* High Rate TXTIME calculation.
* From IEEE Std 802.11b-1999, pp. 28.
*/
ceil = (8 * len * 2) / rate;
if ((8 * len * 2) % rate != 0)
ceil++;
/* IEEE Std 802.11b-1999, pp. 28 */
txtime = (16 * len + rate - 1) / rate;
if (rate != 2 && (flags & IEEE80211_F_SHPREAMBLE))
txtime = 72 + 24 + ceil;
txtime += 72 + 24;
else
txtime = 144 + 48 + ceil;
txtime += 144 + 48;
}
return txtime;
}
@ -1024,44 +1080,33 @@ ural_setup_tx_desc(struct ural_softc *sc, struct ural_tx_desc *desc,
desc->flags |= htole32(RAL_TX_NEWSEQ);
desc->flags |= htole32(len << 16);
if (RAL_RATE_IS_OFDM(rate))
desc->flags |= htole32(RAL_TX_OFDM);
desc->wme = htole16(RAL_AIFSN(3) | RAL_LOGCWMIN(4) | RAL_LOGCWMAX(6));
desc->wme = htole16(RAL_AIFSN(2) | RAL_LOGCWMIN(3) | RAL_LOGCWMAX(5));
desc->wme |= htole16(RAL_IVOFFSET(sizeof (struct ieee80211_frame)));
/*
* Fill PLCP fields.
*/
/* setup PLCP fields */
desc->plcp_signal = ural_plcp_signal(rate);
desc->plcp_service = 4;
len += 4; /* account for FCS */
len += IEEE80211_CRC_LEN;
if (RAL_RATE_IS_OFDM(rate)) {
/*
* PLCP length field (LENGTH).
* From IEEE Std 802.11a-1999, pp. 14.
*/
plcp_length = len & 0xfff;
desc->plcp_length = htole16((plcp_length >> 6) << 8 |
(plcp_length & 0x3f));
} else {
/*
* Long PLCP LENGTH field.
* From IEEE Std 802.11b-1999, pp. 16.
*/
plcp_length = (8 * len * 2) / rate;
remainder = (8 * len * 2) % rate;
if (remainder != 0) {
if (rate == 22 && (rate - remainder) / 16 != 0)
desc->plcp_service |= RAL_PLCP_LENGEXT;
plcp_length++;
}
desc->plcp_length = htole16(plcp_length);
}
desc->flags |= htole32(RAL_TX_OFDM);
desc->plcp_signal = ural_plcp_signal(rate);
if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
desc->plcp_signal |= 0x08;
plcp_length = len & 0xfff;
desc->plcp_length_hi = plcp_length >> 6;
desc->plcp_length_lo = plcp_length & 0x3f;
} else {
plcp_length = (16 * len + rate - 1) / rate;
if (rate == 22) {
remainder = (16 * len) % 22;
if (remainder != 0 && remainder < 7)
desc->plcp_service |= RAL_PLCP_LENGEXT;
}
desc->plcp_length_hi = plcp_length >> 8;
desc->plcp_length_lo = plcp_length & 0xff;
if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
desc->plcp_signal |= 0x08;
}
desc->iv = 0;
desc->eiv = 0;
@ -1079,7 +1124,7 @@ ural_tx_bcn(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
uint8_t *buf;
int xferlen, rate;
rate = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? 12 : 4;
rate = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? 12 : 2;
xfer = usbd_alloc_xfer(sc->sc_udev);
if (xfer == NULL)
@ -1136,19 +1181,7 @@ ural_tx_mgt(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
data = &sc->tx_data[0];
desc = (struct ural_tx_desc *)data->buf;
rate = IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ? 12 : 4;
if (sc->sc_drvbpf != NULL) {
struct ural_tx_radiotap_header *tap = &sc->sc_txtap;
tap->wt_flags = 0;
tap->wt_rate = rate;
tap->wt_chan_freq = htole16(ic->ic_ibss_chan->ic_freq);
tap->wt_chan_flags = htole16(ic->ic_ibss_chan->ic_flags);
tap->wt_antenna = sc->tx_ant;
bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0);
}
rate = IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ? 12 : 2;
data->m = m0;
data->ni = ni;
@ -1169,12 +1202,31 @@ ural_tx_mgt(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
flags |= RAL_TX_TIMESTAMP;
}
if (sc->sc_drvbpf != NULL) {
struct ural_tx_radiotap_header *tap = &sc->sc_txtap;
tap->wt_flags = 0;
tap->wt_rate = rate;
tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
tap->wt_antenna = sc->tx_ant;
bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0);
}
m_copydata(m0, 0, m0->m_pkthdr.len, data->buf + RAL_TX_DESC_SIZE);
ural_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate);
/* xfer length needs to be a multiple of two! */
/* align end on a 2-bytes boundary */
xferlen = (RAL_TX_DESC_SIZE + m0->m_pkthdr.len + 1) & ~1;
/*
* No space left in the last URB to store the extra 2 bytes, force
* sending of another URB.
*/
if ((xferlen % 64) == 0)
xferlen += 2;
DPRINTFN(10, ("sending mgt frame len=%u rate=%u xfer len=%u\n",
m0->m_pkthdr.len, rate, xferlen));
@ -1206,7 +1258,6 @@ ural_tx_data(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
wh = mtod(m0, struct ieee80211_frame *);
/* XXX should do automatic rate adaptation */
if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE)
rate = ic->ic_bss->ni_rates.rs_rates[ic->ic_fixed_rate];
else
@ -1225,18 +1276,6 @@ ural_tx_data(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
wh = mtod(m0, struct ieee80211_frame *);
}
if (sc->sc_drvbpf != NULL) {
struct ural_tx_radiotap_header *tap = &sc->sc_txtap;
tap->wt_flags = 0;
tap->wt_rate = rate;
tap->wt_chan_freq = htole16(ic->ic_ibss_chan->ic_freq);
tap->wt_chan_flags = htole16(ic->ic_ibss_chan->ic_flags);
tap->wt_antenna = sc->tx_ant;
bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0);
}
data = &sc->tx_data[0];
desc = (struct ural_tx_desc *)data->buf;
@ -1252,12 +1291,31 @@ ural_tx_data(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
*(uint16_t *)wh->i_dur = htole16(dur);
}
if (sc->sc_drvbpf != NULL) {
struct ural_tx_radiotap_header *tap = &sc->sc_txtap;
tap->wt_flags = 0;
tap->wt_rate = rate;
tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
tap->wt_antenna = sc->tx_ant;
bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0);
}
m_copydata(m0, 0, m0->m_pkthdr.len, data->buf + RAL_TX_DESC_SIZE);
ural_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate);
/* xfer length needs to be a multiple of two! */
/* align end on a 2-bytes boundary */
xferlen = (RAL_TX_DESC_SIZE + m0->m_pkthdr.len + 1) & ~1;
/*
* No space left in the last URB to store the extra 2 bytes, force
* sending of another URB.
*/
if ((xferlen % 64) == 0)
xferlen += 2;
DPRINTFN(10, ("sending data frame len=%u rate=%u xfer len=%u\n",
m0->m_pkthdr.len, rate, xferlen));
@ -1386,7 +1444,7 @@ ural_reset(struct ifnet *ifp)
if (ic->ic_opmode != IEEE80211_M_MONITOR)
return ENETRESET;
ural_set_chan(sc, ic->ic_ibss_chan);
ural_set_chan(sc, ic->ic_curchan);
return 0;
}
@ -1430,6 +1488,25 @@ ural_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
return error;
}
Static void
ural_set_testmode(struct ural_softc *sc)
{
usb_device_request_t req;
usbd_status error;
req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
req.bRequest = RAL_VENDOR_REQUEST;
USETW(req.wValue, 4);
USETW(req.wIndex, 1);
USETW(req.wLength, 0);
error = usbd_do_request(sc->sc_udev, &req, NULL);
if (error != 0) {
printf("%s: could not set test mode: %s\n",
USBDEVNAME(sc->sc_dev), usbd_errstr(error));
}
}
Static void
ural_eeprom_read(struct ural_softc *sc, uint16_t addr, void *buf, int len)
{
@ -1488,7 +1565,6 @@ ural_read_multi(struct ural_softc *sc, uint16_t reg, void *buf, int len)
if (error != 0) {
printf("%s: could not read MAC register: %s\n",
USBDEVNAME(sc->sc_dev), usbd_errstr(error));
return;
}
}
@ -1598,7 +1674,6 @@ ural_rf_write(struct ural_softc *sc, uint8_t reg, uint32_t val)
Static void
ural_set_chan(struct ural_softc *sc, struct ieee80211_channel *c)
{
#define N(a) (sizeof (a) / sizeof ((a)[0]))
struct ieee80211com *ic = &sc->sc_ic;
uint8_t power, tmp;
u_int i, chan;
@ -1612,6 +1687,9 @@ ural_set_chan(struct ural_softc *sc, struct ieee80211_channel *c)
else
power = 31;
/* adjust txpower using ifconfig settings */
power -= (100 - ic->ic_txpowlimit) / 8;
DPRINTFN(2, ("setting channel to %u, txpower to %u\n", chan, power));
switch (sc->rf_rev) {
@ -1666,16 +1744,12 @@ ural_set_chan(struct ural_softc *sc, struct ieee80211_channel *c)
/* dual-band RF */
case RAL_RF_5222:
for (i = 0; i < N(ural_rf5222); i++)
if (ural_rf5222[i].chan == chan)
break;
for (i = 0; i < ural_rf5222[i].chan != chan; i++);
if (i < N(ural_rf5222)) {
ural_rf_write(sc, RAL_RF1, ural_rf5222[i].r1);
ural_rf_write(sc, RAL_RF2, ural_rf5222[i].r2);
ural_rf_write(sc, RAL_RF3, power << 7 | 0x00040);
ural_rf_write(sc, RAL_RF4, ural_rf5222[i].r4);
}
ural_rf_write(sc, RAL_RF1, ural_rf5222[i].r1);
ural_rf_write(sc, RAL_RF2, ural_rf5222[i].r2);
ural_rf_write(sc, RAL_RF3, power << 7 | 0x00040);
ural_rf_write(sc, RAL_RF4, ural_rf5222[i].r4);
break;
}
@ -1692,11 +1766,12 @@ ural_set_chan(struct ural_softc *sc, struct ieee80211_channel *c)
/* clear CRC errors */
ural_read(sc, RAL_STA_CSR0);
DELAY(10000);
ural_disable_rf_tune(sc);
}
#undef N
}
#if 0
/*
* Disable RF auto-tuning.
*/
@ -1715,7 +1790,6 @@ ural_disable_rf_tune(struct ural_softc *sc)
DPRINTFN(2, ("disabling RF autotune\n"));
}
#endif
/*
* Refer to IEEE Std 802.11-1999 pp. 123 for more information on TSF
@ -1749,6 +1823,64 @@ ural_enable_tsf_sync(struct ural_softc *sc)
DPRINTF(("enabling TSF synchronization\n"));
}
Static void
ural_update_slot(struct ifnet *ifp)
{
struct ural_softc *sc = ifp->if_softc;
struct ieee80211com *ic = &sc->sc_ic;
uint16_t slottime, sifs, eifs;
slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20;
/*
* These settings may sound a bit inconsistent but this is what the
* reference driver does.
*/
if (ic->ic_curmode == IEEE80211_MODE_11B) {
sifs = 16 - RAL_RXTX_TURNAROUND;
eifs = 364;
} else {
sifs = 10 - RAL_RXTX_TURNAROUND;
eifs = 64;
}
ural_write(sc, RAL_MAC_CSR10, slottime);
ural_write(sc, RAL_MAC_CSR11, sifs);
ural_write(sc, RAL_MAC_CSR12, eifs);
}
Static void
ural_set_txpreamble(struct ural_softc *sc)
{
uint16_t tmp;
tmp = ural_read(sc, RAL_TXRX_CSR10);
tmp &= ~RAL_SHORT_PREAMBLE;
if (sc->sc_ic.ic_flags & IEEE80211_F_SHPREAMBLE)
tmp |= RAL_SHORT_PREAMBLE;
ural_write(sc, RAL_TXRX_CSR10, tmp);
}
Static void
ural_set_basicrates(struct ural_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
/* update basic rate set */
if (ic->ic_curmode == IEEE80211_MODE_11B) {
/* 11b basic rates: 1, 2Mbps */
ural_write(sc, RAL_TXRX_CSR11, 0x3);
} else if (IEEE80211_IS_CHAN_5GHZ(ic->ic_bss->ni_chan)) {
/* 11a basic rates: 6, 12, 24Mbps */
ural_write(sc, RAL_TXRX_CSR11, 0x150);
} else {
/* 11g basic rates: 1, 2, 5.5, 11, 6, 12, 24Mbps */
ural_write(sc, RAL_TXRX_CSR11, 0x15f);
}
}
Static void
ural_set_bssid(struct ural_softc *sc, uint8_t *bssid)
{
@ -1933,10 +2065,13 @@ ural_init(void *priv)
struct ifnet *ifp = ic->ic_ifp;
struct ieee80211_key *wk;
struct ural_rx_data *data;
uint16_t sta[11], tmp;
uint16_t tmp;
usbd_status error;
int i, ntries;
ural_set_testmode(sc);
ural_write(sc, 0x308, 0x00f0); /* XXX magic */
ural_stop(sc);
/* initialize MAC registers to default values */
@ -1961,18 +2096,16 @@ ural_init(void *priv)
ural_write(sc, RAL_MAC_CSR1, RAL_HOST_READY);
/* set basic rate set (will be updated later) */
ural_write(sc, RAL_TXRX_CSR11, 0x153);
ural_write(sc, RAL_TXRX_CSR11, 0x15f);
if (ural_bbp_init(sc) != 0)
goto fail;
/* set default BSS channel */
ic->ic_bss->ni_chan = ic->ic_ibss_chan;
ic->ic_curchan = ic->ic_ibss_chan;
ural_set_chan(sc, ic->ic_curchan);
/* clear statistic registers (STA_CSR0 to STA_CSR10) */
ural_read_multi(sc, RAL_STA_CSR0, sta, sizeof sta);
ural_read_multi(sc, RAL_STA_CSR0, sc->sta, sizeof sc->sta);
ural_set_txantenna(sc, sc->tx_ant);
ural_set_rxantenna(sc, sc->rx_ant);
@ -1989,6 +2122,16 @@ ural_init(void *priv)
RAL_SEC_CSR0, wk->wk_key, IEEE80211_KEYBUF_SIZE);
}
/*
* Allocate xfer for AMRR statistics requests.
*/
sc->amrr_xfer = usbd_alloc_xfer(sc->sc_udev);
if (sc->amrr_xfer == NULL) {
printf("%s: could not allocate AMRR xfer\n",
USBDEVNAME(sc->sc_dev));
goto fail;
}
/*
* Open Tx and Rx USB bulk pipes.
*/
@ -2082,6 +2225,11 @@ ural_stop(void *priv)
ural_write(sc, RAL_MAC_CSR1, RAL_RESET_ASIC | RAL_RESET_BBP);
ural_write(sc, RAL_MAC_CSR1, 0);
if (sc->amrr_xfer != NULL) {
usbd_free_xfer(sc->amrr_xfer);
sc->amrr_xfer = NULL;
}
if (sc->sc_rx_pipeh != NULL) {
usbd_abort_pipe(sc->sc_rx_pipeh);
usbd_close_pipe(sc->sc_rx_pipeh);
@ -2098,4 +2246,155 @@ ural_stop(void *priv)
ural_free_tx_list(sc);
}
#define URAL_AMRR_MIN_SUCCESS_THRESHOLD 1
#define URAL_AMRR_MAX_SUCCESS_THRESHOLD 10
Static void
ural_amrr_start(struct ural_softc *sc, struct ieee80211_node *ni)
{
struct ural_amrr *amrr = &sc->amrr;
int i;
/* clear statistic registers (STA_CSR0 to STA_CSR10) */
ural_read_multi(sc, RAL_STA_CSR0, sc->sta, sizeof sc->sta);
amrr->success = 0;
amrr->recovery = 0;
amrr->txcnt = amrr->retrycnt = 0;
amrr->success_threshold = URAL_AMRR_MIN_SUCCESS_THRESHOLD;
/* set rate to some reasonable initial value */
for (i = ni->ni_rates.rs_nrates - 1;
i > 0 && (ni->ni_rates.rs_rates[i] & IEEE80211_RATE_VAL) > 72;
i--);
ni->ni_txrate = i;
callout_reset(&sc->amrr_ch, hz, ural_amrr_timeout, sc);
}
Static void
ural_amrr_timeout(void *arg)
{
struct ural_softc *sc = (struct ural_softc *)arg;
usb_device_request_t req;
int s;
s = splusb();
/*
* Asynchronously read statistic registers (cleared by read).
*/
req.bmRequestType = UT_READ_VENDOR_DEVICE;
req.bRequest = RAL_READ_MULTI_MAC;
USETW(req.wValue, 0);
USETW(req.wIndex, RAL_STA_CSR0);
USETW(req.wLength, sizeof sc->sta);
usbd_setup_default_xfer(sc->amrr_xfer, sc->sc_udev, sc,
USBD_DEFAULT_TIMEOUT, &req, sc->sta, sizeof sc->sta, 0,
ural_amrr_update);
(void)usbd_transfer(sc->amrr_xfer);
splx(s);
}
Static void
ural_amrr_update(usbd_xfer_handle xfer, usbd_private_handle priv,
usbd_status status)
{
struct ural_softc *sc = (struct ural_softc *)priv;
struct ural_amrr *amrr = &sc->amrr;
struct ifnet *ifp = sc->sc_ic.ic_ifp;
if (status != USBD_NORMAL_COMPLETION) {
device_printf(sc->sc_dev, "could not retrieve Tx statistics - "
"cancelling automatic rate control\n");
return;
}
/* count TX retry-fail as Tx errors */
ifp->if_oerrors += sc->sta[9];
amrr->retrycnt =
sc->sta[7] + /* TX one-retry ok count */
sc->sta[8] + /* TX more-retry ok count */
sc->sta[9]; /* TX retry-fail count */
amrr->txcnt =
amrr->retrycnt +
sc->sta[6]; /* TX no-retry ok count */
ural_ratectl(amrr, sc->sc_ic.ic_bss);
callout_reset(&sc->amrr_ch, hz, ural_amrr_timeout, sc);
}
/*-
* Naive implementation of the Adaptive Multi Rate Retry algorithm:
* "IEEE 802.11 Rate Adaptation: A Practical Approach"
* Mathieu Lacage, Hossein Manshaei, Thierry Turletti
* INRIA Sophia - Projet Planete
* http://www-sop.inria.fr/rapports/sophia/RR-5208.html
*
* This algorithm is particularly well suited for ural since it does not
* require per-frame retry statistics. Note however that since h/w does
* not provide per-frame stats, we can't do per-node rate adaptation and
* thus automatic rate adaptation is only enabled in STA operating mode.
*/
#define is_success(amrr) \
((amrr)->retrycnt < (amrr)->txcnt / 10)
#define is_failure(amrr) \
((amrr)->retrycnt > (amrr)->txcnt / 3)
#define is_enough(amrr) \
((amrr)->txcnt > 10)
#define is_min_rate(ni) \
((ni)->ni_txrate == 0)
#define is_max_rate(ni) \
((ni)->ni_txrate == (ni)->ni_rates.rs_nrates - 1)
#define increase_rate(ni) \
((ni)->ni_txrate++)
#define decrease_rate(ni) \
((ni)->ni_txrate--)
#define reset_cnt(amrr) \
do { (amrr)->txcnt = (amrr)->retrycnt = 0; } while (0)
Static void
ural_ratectl(struct ural_amrr *amrr, struct ieee80211_node *ni)
{
int need_change = 0;
if (is_success(amrr) && is_enough(amrr)) {
amrr->success++;
if (amrr->success >= amrr->success_threshold &&
!is_max_rate(ni)) {
amrr->recovery = 1;
amrr->success = 0;
increase_rate(ni);
need_change = 1;
} else {
amrr->recovery = 0;
}
} else if (is_failure(amrr)) {
amrr->success = 0;
if (!is_min_rate(ni)) {
if (amrr->recovery) {
amrr->success_threshold *= 2;
if (amrr->success_threshold >
URAL_AMRR_MAX_SUCCESS_THRESHOLD)
amrr->success_threshold =
URAL_AMRR_MAX_SUCCESS_THRESHOLD;
} else {
amrr->success_threshold =
URAL_AMRR_MIN_SUCCESS_THRESHOLD;
}
decrease_rate(ni);
need_change = 1;
}
amrr->recovery = 0; /* original paper was incorrect */
}
if (is_enough(amrr) || need_change)
reset_cnt(amrr);
}
DRIVER_MODULE(ural, uhub, ural_driver, ural_devclass, usbd_driver_load, 0);

View File

@ -1,7 +1,7 @@
/* $FreeBSD$ */
/*-
* Copyright (c) 2005
* Copyright (c) 2005, 2006
* Damien Bergamini <damien.bergamini@free.fr>
*
* Permission to use, copy, modify, and distribute this software for any
@ -23,6 +23,7 @@
#define RAL_CONFIG_NO 1
#define RAL_IFACE_INDEX 0
#define RAL_VENDOR_REQUEST 0x01
#define RAL_WRITE_MAC 0x02
#define RAL_READ_MAC 0x03
#define RAL_WRITE_MULTI_MAC 0x06
@ -42,6 +43,7 @@
#define RAL_MAC_CSR7 0x040e /* BSSID2 */
#define RAL_MAC_CSR8 0x0410 /* Max frame length */
#define RAL_MAC_CSR9 0x0412 /* Timer control */
#define RAL_MAC_CSR10 0x0414 /* Slot time */
#define RAL_MAC_CSR11 0x0416 /* IFS */
#define RAL_MAC_CSR12 0x0418 /* EIFS */
#define RAL_MAC_CSR13 0x041a /* Power mode0 */
@ -63,6 +65,7 @@
#define RAL_TXRX_CSR6 0x044c /* CCK Tx BBP ID1 */
#define RAL_TXRX_CSR7 0x044e /* OFDM Tx BBP ID0 */
#define RAL_TXRX_CSR8 0x0450 /* OFDM Tx BBP ID1 */
#define RAL_TXRX_CSR10 0x0454 /* Auto responder control */
#define RAL_TXRX_CSR11 0x0456 /* Auto responder basic rate */
#define RAL_TXRX_CSR18 0x0464 /* Beacon interval */
#define RAL_TXRX_CSR19 0x0466 /* Beacon/sync control */
@ -102,6 +105,8 @@
#define RAL_DROP_MULTICAST (1 << 9)
#define RAL_DROP_BROADCAST (1 << 10)
#define RAL_SHORT_PREAMBLE (1 << 2)
#define RAL_RESET_ASIC (1 << 0)
#define RAL_RESET_BBP (1 << 1)
#define RAL_HOST_READY (1 << 2)
@ -167,7 +172,8 @@ struct ural_tx_desc {
uint8_t plcp_service;
#define RAL_PLCP_LENGEXT 0x80
uint16_t plcp_length;
uint8_t plcp_length_lo;
uint8_t plcp_length_hi;
uint32_t iv;
uint32_t eiv;
} __packed;
@ -175,10 +181,11 @@ struct ural_tx_desc {
struct ural_rx_desc {
uint32_t flags;
#define RAL_RX_CRC_ERROR (1 << 5)
#define RAL_RX_OFDM (1 << 6)
#define RAL_RX_PHY_ERROR (1 << 7)
uint8_t rate;
uint8_t rssi;
uint8_t rate;
uint16_t reserved;
uint32_t iv;

View File

@ -1,7 +1,7 @@
/* $FreeBSD$ */
/*-
* Copyright (c) 2005
* Copyright (c) 2005, 2006
* Damien Bergamini <damien.bergamini@free.fr>
*
* Permission to use, copy, modify, and distribute this software for any
@ -23,6 +23,7 @@
struct ural_rx_radiotap_header {
struct ieee80211_radiotap_header wr_ihdr;
uint8_t wr_flags;
uint8_t wr_rate;
uint16_t wr_chan_freq;
uint16_t wr_chan_flags;
uint8_t wr_antenna;
@ -31,6 +32,7 @@ struct ural_rx_radiotap_header {
#define RAL_RX_RADIOTAP_PRESENT \
((1 << IEEE80211_RADIOTAP_FLAGS) | \
(1 << IEEE80211_RADIOTAP_RATE) | \
(1 << IEEE80211_RADIOTAP_CHANNEL) | \
(1 << IEEE80211_RADIOTAP_ANTENNA) | \
(1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL))
@ -67,6 +69,14 @@ struct ural_rx_data {
struct mbuf *m;
};
struct ural_amrr {
int txcnt;
int retrycnt;
int success;
int success_threshold;
int recovery;
};
struct ural_softc {
struct ifnet *sc_ifp;
struct ieee80211com sc_ic;
@ -82,12 +92,16 @@ struct ural_softc {
uint32_t asic_rev;
uint8_t rf_rev;
usbd_xfer_handle amrr_xfer;
usbd_pipe_handle sc_rx_pipeh;
usbd_pipe_handle sc_tx_pipeh;
enum ieee80211_state sc_state;
struct usb_task sc_task;
struct ural_amrr amrr;
struct ural_rx_data rx_data[RAL_RX_LIST_COUNT];
struct ural_tx_data tx_data[RAL_TX_LIST_COUNT];
int tx_queued;
@ -97,9 +111,11 @@ struct ural_softc {
struct mtx sc_mtx;
struct callout scan_ch;
struct callout amrr_ch;
int sc_tx_timer;
uint16_t sta[11];
uint32_t rf_regs[4];
uint8_t txpow[14];

View File

@ -1095,6 +1095,7 @@ product LINKSYS2 USB200M 0x2226 USB 2.0 10/100 ethernet
product LINKSYS3 WUSB11v28 0x2233 WUSB11 v2.8 wireless adapter
product LINKSYS4 WUSB54G 0x000d WUSB54G wireless adapter
product LINKSYS4 WUSB54GP 0x0011 WUSB54GP wireless adapter
product LINKSYS4 HU200TS 0x001a HU200TS wireless adapter
/* Logitech products */
product LOGITECH M2452 0x0203 M2452 keyboard
@ -1155,6 +1156,7 @@ product MELCO LUAU2KTX 0x003d LUA-U2-KTX Ethernet
product MELCO KG54YB 0x005e WLI-U2-KG54-YB WLAN
product MELCO KG54 0x0066 WLI-U2-KG54 WLAN
product MELCO KG54AI 0x0067 WLI-U2-KG54-AI WLAN
product MELCO NINWIFI 0x008b Nintendo Wi-Fi
/* Metricom products */
product METRICOM RICOCHET_GS 0x0001 Ricochet GS