diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2005-02-15 19:44:16 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2005-02-15 19:44:16 +0000 |
commit | 665c26fbfa839aefa17124ac2f607c306e0de4fd (patch) | |
tree | b12344918126d0a5f315a1a641fefcda1f35c259 /sys/dev/ic | |
parent | 61223f4f3d7070ebf88b91c6fdcc6892ed7bdbbd (diff) |
add the manual tx power option. this is supported by some prism2/2.5/3
cards in hostap mode but it depends on the firmware version. support
for other wireless chipsets will be added in the future using the
net80211-framework.
ok robert@ bob@ danh@, tested by some others
Diffstat (limited to 'sys/dev/ic')
-rw-r--r-- | sys/dev/ic/if_wi.c | 109 | ||||
-rw-r--r-- | sys/dev/ic/if_wireg.h | 10 | ||||
-rw-r--r-- | sys/dev/ic/if_wivar.h | 4 |
3 files changed, 119 insertions, 4 deletions
diff --git a/sys/dev/ic/if_wi.c b/sys/dev/ic/if_wi.c index add84ce8de6..95851e093c4 100644 --- a/sys/dev/ic/if_wi.c +++ b/sys/dev/ic/if_wi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_wi.c,v 1.115 2005/01/15 05:24:11 brad Exp $ */ +/* $OpenBSD: if_wi.c,v 1.116 2005/02/15 19:44:15 reyk Exp $ */ /* * Copyright (c) 1997, 1998, 1999 @@ -127,7 +127,7 @@ u_int32_t widebug = WIDEBUG; #if !defined(lint) && !defined(__OpenBSD__) static const char rcsid[] = - "$OpenBSD: if_wi.c,v 1.115 2005/01/15 05:24:11 brad Exp $"; + "$OpenBSD: if_wi.c,v 1.116 2005/02/15 19:44:15 reyk Exp $"; #endif /* lint */ #ifdef foo @@ -167,6 +167,8 @@ STATIC int wi_get_nwkey(struct wi_softc *, struct ieee80211_nwkey *); STATIC int wi_sync_media(struct wi_softc *, int, int); STATIC int wi_set_pm(struct wi_softc *, struct ieee80211_power *); STATIC int wi_get_pm(struct wi_softc *, struct ieee80211_power *); +STATIC int wi_set_txpower(struct wi_softc *, struct ieee80211_txpower *); +STATIC int wi_get_txpower(struct wi_softc *, struct ieee80211_txpower *); STATIC int wi_get_debug(struct wi_softc *, struct wi_req *); STATIC int wi_set_debug(struct wi_softc *, struct wi_req *); @@ -1595,6 +1597,7 @@ wi_ioctl(ifp, command, data) case SIOCS80211NWID: case SIOCS80211NWKEY: case SIOCS80211POWER: + case SIOCS80211TXPOWER: error = suser(p, 0); if (error) { splx(s); @@ -1856,6 +1859,12 @@ wi_ioctl(ifp, command, data) case SIOCG80211POWER: error = wi_get_pm(sc, (struct ieee80211_power *)data); break; + case SIOCS80211TXPOWER: + error = wi_set_txpower(sc, (struct ieee80211_txpower *)data); + break; + case SIOCG80211TXPOWER: + error = wi_get_txpower(sc, (struct ieee80211_txpower *)data); + break; case SIOCHOSTAP_ADD: case SIOCHOSTAP_DEL: case SIOCHOSTAP_GET: @@ -2008,6 +2017,10 @@ wi_init_io(sc) WI_PRT_ARG(sc)); sc->wi_tx_mgmt_id = id; + /* Set txpower */ + if (sc->wi_flags & WI_FLAGS_TXPOWER) + wi_set_txpower(sc, NULL); + /* enable interrupts */ wi_intr_enable(sc, WI_INTRS); @@ -2878,6 +2891,98 @@ wi_get_pm(struct wi_softc *sc, struct ieee80211_power *power) } STATIC int +wi_set_txpower(struct wi_softc *sc, struct ieee80211_txpower *txpower) +{ + u_int16_t cmd; + u_int16_t power; + int8_t tmp; + int error; + int alc; + + if (txpower == NULL) { + if (!(sc->wi_flags & WI_FLAGS_TXPOWER)) + return (EINVAL); + alc = 0; /* disable ALC */ + } else { + if (txpower->i_mode == IEEE80211_TXPOWER_MODE_AUTO) { + alc = 1; /* enable ALC */ + sc->wi_flags &= ~WI_FLAGS_TXPOWER; + } else { + alc = 0; /* disable ALC */ + sc->wi_flags |= WI_FLAGS_TXPOWER; + sc->wi_txpower = txpower->i_val; + } + } + + /* Set ALC */ + cmd = WI_CMD_DEBUG | (WI_DEBUG_CONFBITS << 8); + if ((error = wi_cmd(sc, cmd, alc, 0x8, 0)) != 0) + return (error); + + /* No need to set the TX power value if ALC is enabled */ + if (alc) + return (0); + + /* Convert dBM to internal TX power value */ + if (sc->wi_txpower > 20) + power = 128; + else if (sc->wi_txpower < -43) + power = 127; + else { + tmp = sc->wi_txpower; + tmp = -12 - tmp; + tmp <<= 2; + + power = (u_int16_t)tmp; + } + + /* Set manual TX power */ + cmd = WI_CMD_WRITE_MIF; + if ((error = wi_cmd(sc, cmd, + WI_HFA384X_CR_MANUAL_TX_POWER, power, 0)) != 0) + return (error); + + if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG) + printf("%s: %u (%d dBm)\n", sc->sc_dev.dv_xname, power, + sc->wi_txpower); + + return (0); +} + +STATIC int +wi_get_txpower(struct wi_softc *sc, struct ieee80211_txpower *txpower) +{ + u_int16_t cmd; + u_int16_t power; + int8_t tmp; + int error; + + /* Get manual TX power */ + cmd = WI_CMD_READ_MIF; + if ((error = wi_cmd(sc, cmd, + WI_HFA384X_CR_MANUAL_TX_POWER, 0, 0)) != 0) + return (error); + + power = CSR_READ_2(sc, WI_RESP0); + + /* Convert internal TX power value to dBM */ + if (power > 255) + txpower->i_val = 255; + else { + tmp = power; + tmp >>= 2; + txpower->i_val = (u_int16_t)(-12 - tmp); + } + + if (sc->wi_flags & WI_FLAGS_TXPOWER) + txpower->i_mode = IEEE80211_TXPOWER_MODE_FIXED; + else + txpower->i_mode = IEEE80211_TXPOWER_MODE_AUTO; + + return (0); +} + +STATIC int wi_set_ssid(ws, id, len) struct ieee80211_nwid *ws; u_int8_t *id; diff --git a/sys/dev/ic/if_wireg.h b/sys/dev/ic/if_wireg.h index c295d3a0150..602dbbc6b27 100644 --- a/sys/dev/ic/if_wireg.h +++ b/sys/dev/ic/if_wireg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_wireg.h,v 1.34 2004/03/02 21:59:29 millert Exp $ */ +/* $OpenBSD: if_wireg.h,v 1.35 2005/02/15 19:44:15 reyk Exp $ */ /* * Copyright (c) 1997, 1998, 1999 @@ -194,6 +194,8 @@ #define WI_CMD_INQUIRE 0x0011 #define WI_CMD_ACCESS 0x0021 #define WI_CMD_PROGRAM 0x0022 +#define WI_CMD_READ_MIF 0x0030 /* prism2 */ +#define WI_CMD_WRITE_MIF 0x0031 /* prism2 */ #define WI_CMD_CODE_MASK 0x003F @@ -604,3 +606,9 @@ struct wi_frame { #define WI_FCS_LEN 0x4 #define WI_ETHERTYPE_LEN 0x2 + +/* + * HFA3861/3863 (BBP) Control Registers + */ +#define WI_HFA384X_CR_A_D_TEST_MODES2 0x1a +#define WI_HFA384X_CR_MANUAL_TX_POWER 0x3e diff --git a/sys/dev/ic/if_wivar.h b/sys/dev/ic/if_wivar.h index cdc35f6aa6f..d9058470204 100644 --- a/sys/dev/ic/if_wivar.h +++ b/sys/dev/ic/if_wivar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_wivar.h,v 1.24 2004/03/18 16:16:10 millert Exp $ */ +/* $OpenBSD: if_wivar.h,v 1.25 2005/02/15 19:44:15 reyk Exp $ */ /* * Copyright (c) 1997, 1998, 1999 @@ -93,6 +93,7 @@ struct wi_softc { u_int32_t wi_icv; int wi_icv_flag; int wi_ibss_port; + int16_t wi_txpower; struct { u_int16_t wi_sleep; @@ -137,6 +138,7 @@ struct wi_softc { #define WI_FLAGS_BUS_PCMCIA 0x0200 #define WI_FLAGS_BUS_USB 0x0400 #define WI_FLAGS_HAS_ENH_SECURITY 0x0800 +#define WI_FLAGS_TXPOWER 0x1000 #define WI_PRT_FMT "%s" #define WI_PRT_ARG(sc) (sc)->sc_dev.dv_xname |