summaryrefslogtreecommitdiff
path: root/sys/dev/ic
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2005-02-15 19:44:16 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2005-02-15 19:44:16 +0000
commit665c26fbfa839aefa17124ac2f607c306e0de4fd (patch)
treeb12344918126d0a5f315a1a641fefcda1f35c259 /sys/dev/ic
parent61223f4f3d7070ebf88b91c6fdcc6892ed7bdbbd (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.c109
-rw-r--r--sys/dev/ic/if_wireg.h10
-rw-r--r--sys/dev/ic/if_wivar.h4
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