summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
-rw-r--r--sys/net80211/ieee80211_ioctl.c26
-rw-r--r--sys/net80211/ieee80211_ioctl.h16
-rw-r--r--sys/net80211/ieee80211_var.h6
6 files changed, 161 insertions, 10 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
diff --git a/sys/net80211/ieee80211_ioctl.c b/sys/net80211/ieee80211_ioctl.c
index 0a1ea1f2fe6..36dd974b946 100644
--- a/sys/net80211/ieee80211_ioctl.c
+++ b/sys/net80211/ieee80211_ioctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_ioctl.c,v 1.4 2004/11/25 11:20:04 reyk Exp $ */
+/* $OpenBSD: ieee80211_ioctl.c,v 1.5 2005/02/15 19:44:15 reyk Exp $ */
/* $NetBSD: ieee80211_ioctl.c,v 1.15 2004/05/06 02:58:16 dyoung Exp $ */
/*-
@@ -1130,6 +1130,7 @@ ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
struct ieee80211_bssid *bssid;
struct ieee80211chanreq *chanreq;
struct ieee80211_channel *chan;
+ struct ieee80211_txpower *txpower;
struct ieee80211_wepkey keys[IEEE80211_WEP_NKID];
static const u_int8_t empty_macaddr[IEEE80211_ADDR_LEN] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
@@ -1369,6 +1370,29 @@ ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
ifr = (struct ifreq *)data;
copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats));
break;
+ case SIOCS80211TXPOWER:
+ txpower = (struct ieee80211_txpower *)data;
+ if ((error = suser(curproc, 0)))
+ break;
+ if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0) {
+ error = EINVAL;
+ break;
+ }
+ if (!(IEEE80211_TXPOWER_MIN < txpower->i_val &&
+ txpower->i_val < IEEE80211_TXPOWER_MAX)) {
+ error = EINVAL;
+ break;
+ }
+ ic->ic_txpower = txpower->i_val;
+ error = ENETRESET;
+ break;
+ case SIOCG80211TXPOWER:
+ txpower = (struct ieee80211_txpower *)data;
+ if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
+ error = EINVAL;
+ else
+ txpower->i_val = ic->ic_txpower;
+ break;
case SIOCSIFMTU:
ifr = (struct ifreq *)data;
if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu &&
diff --git a/sys/net80211/ieee80211_ioctl.h b/sys/net80211/ieee80211_ioctl.h
index 7716947b961..a3a205cf046 100644
--- a/sys/net80211/ieee80211_ioctl.h
+++ b/sys/net80211/ieee80211_ioctl.h
@@ -1,5 +1,4 @@
-/* $OpenBSD: ieee80211_ioctl.h,v 1.1 2004/06/22 22:53:52 millert Exp $ */
-/* $OpenBSD: ieee80211_ioctl.h,v 1.1 2004/06/22 22:53:52 millert Exp $ */
+/* $OpenBSD: ieee80211_ioctl.h,v 1.2 2005/02/15 19:44:15 reyk Exp $ */
/* $NetBSD: ieee80211_ioctl.h,v 1.7 2004/04/30 22:51:04 dyoung Exp $ */
/*-
@@ -206,6 +205,19 @@ struct ieee80211_bssid {
#define SIOCG80211BSSID _IOWR('i', 241, struct ieee80211_bssid)
#define SIOCG80211STATS _IOWR('i', 242, struct ifreq)
+
+struct ieee80211_txpower {
+ char i_name[IFNAMSIZ]; /* if_name, e.g. "wi0" */
+ int i_mode; /* auto, manual */
+ int16_t i_val; /* dBm */
+};
+
+#define SIOCS80211TXPOWER _IOW('i', 243, struct ieee80211_txpower)
+#define SIOCG80211TXPOWER _IOWR('i', 244, struct ieee80211_txpower)
+
+#define IEEE80211_TXPOWER_MODE_FIXED 0 /* fixed tx power value */
+#define IEEE80211_TXPOWER_MODE_AUTO 1 /* auto level control */
+
#endif
#endif /* _NET80211_IEEE80211_IOCTL_H_ */
diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h
index 8903d3dcebc..26fd666bbd4 100644
--- a/sys/net80211/ieee80211_var.h
+++ b/sys/net80211/ieee80211_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_var.h,v 1.4 2004/12/25 20:40:19 deraadt Exp $ */
+/* $OpenBSD: ieee80211_var.h,v 1.5 2005/02/15 19:44:15 reyk Exp $ */
/* $NetBSD: ieee80211_var.h,v 1.7 2004/05/06 03:07:10 dyoung Exp $ */
/*-
@@ -53,7 +53,7 @@
((struct ieee80211_channel *) IEEE80211_CHAN_ANY)
#define IEEE80211_TXPOWER_MAX 100 /* max power */
-#define IEEE80211_TXPOWER_MIN 0 /* kill radio (if possible) */
+#define IEEE80211_TXPOWER_MIN -50 /* kill radio (if possible) */
enum ieee80211_phytype {
IEEE80211_T_DS, /* direct sequence spread spectrum */
@@ -225,7 +225,7 @@ struct ieee80211com {
u_int16_t ic_txmin; /* min tx retry count */
u_int16_t ic_txmax; /* max tx retry count */
u_int16_t ic_txlifetime; /* tx lifetime */
- u_int16_t ic_txpower; /* tx power setting (dbM) */
+ int16_t ic_txpower; /* tx power setting (dBm) */
u_int16_t ic_bmisstimeout;/* beacon miss threshold (ms) */
int ic_mgt_timer; /* mgmt timeout */
int ic_inact_timer; /* inactivity timer wait */