--- prism2_wlan.h-2001-12-18 Tue Jan 1 08:54:52 2002 +++ prism2_wlan.h Tue Jan 1 10:39:08 2002 @@ -220,6 +220,8 @@ /* Test mode operations */ #define HFA384X_TEST_MONITOR 0x0B #define HFA384X_TEST_STOP 0x0F +#define HFA384X_TEST_CFG_BITS 0x15 +#define HFA384X_TEST_CFG_BIT_ALC BIT(3) #define HFA384X_CMD_BUSY BIT(15) @@ -409,6 +411,9 @@ #define HFA384X_TX_STATUS_DISCON BIT(2) #define HFA384X_TX_STATUS_FORMERR BIT(3) +/* HFA3861/3863 (BBP) Control Registers */ +#define HFA386X_CR_MANUAL_TX_POWER 0x3E + /* IEEE 802.11 defines */ #define WLAN_FC_PVER (BIT(1) | BIT(0)) @@ -566,6 +571,12 @@ int hw_resetting; int hw_ready; int hw_reset_tries; /* how many times reset has been tried */ + + enum { + PRISM2_TXPOWER_AUTO = 0, PRISM2_TXPOWER_OFF, + PRISM2_TXPOWER_FIXED + } txpower_type; + int txpower; /* if txpower_type == PRISM2_TXPOWER_FIXED */ /* skb queue for packets to be send using dev_queue_xmit() after * exiting hard IRQ handler (prism2_rx) */ --- prism2.c-2001-12-18 Tue Jan 1 08:54:52 2002 +++ prism2.c Tue Jan 1 11:02:42 2002 @@ -2129,6 +2129,42 @@ #endif /* WIRELESS_EXT */ +/* + * FIX: check power mapping.. this may be completely wrong + * + * This version assumes following mapping: + * 0x00: 0mW, 0x80: 100mW, 0xFF: 0mW (linear) + * HFA3861 data sheet: CR31 bit7:1 (7 bits; bit0 ignored) to DAC input; + * -64 to 63 in range + */ + +static int prism2_txpower_hfa386x_to_mW(u16 val) +{ + u16 tmp; + int ret; + tmp = val > 0xff ? 0xff : val; + if (tmp > 0x80) + tmp = 0xff - tmp; /* 0x00 .. 0x80 */ + ret = (100 * tmp) / 0x80; + printk(KERN_DEBUG "prism2_txpower: %d => %d mW\n", + val, ret); + return ret; +} + +static u16 prism2_txpower_mW_to_hfa386x(int val) +{ + int tmp; + + if (val >= 100) + return 0x80; + if (val < 0) + return 0; + + tmp = (0x80 * val) / 100; + tmp = 0xff - tmp; /* 0x80 .. 0xff */ + printk(KERN_DEBUG "prism2_txpower: %d mW => %d\n", val, tmp); + return tmp; +} static int prism2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { @@ -2165,6 +2201,10 @@ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "reset" } , { SIOCDEVPRIVATE + 8, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dump" } + , { SIOCDEVPRIVATE + 9, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "alc" } + , { SIOCDEVPRIVATE + 10, + IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "txpower" } }; switch (cmd) { @@ -2395,6 +2435,17 @@ } wrq->u.data.length = sizeof(range); memset(&range, 0, sizeof(range)); + +#if WIRELESS_EXT > 9 + /* FIX: actually there are more available TX powers, but let + * just list something for now.. */ + range.num_txpower = 3; + range.txpower[0] = 10; + range.txpower[1] = 30; + range.txpower[2] = 100; + range.txpower_capa = IW_TXPOW_MWATT; +#endif /* WIRELESS_EXT > 9 */ + #if WIRELESS_EXT > 10 range.we_version_compiled = WIRELESS_EXT; range.we_version_source = 11; @@ -2477,6 +2528,97 @@ } break; +#if WIRELESS_EXT > 9 + case SIOCSIWTXPOW: + printk(KERN_DEBUG "SIOCSIWTXPOW\n"); + if (wrq->u.txpower.disabled) { + if (local->txpower_type != PRISM2_TXPOWER_OFF) { + printk(KERN_DEBUG "Turning radio off " + "(not yet implemented)\n"); + /* TODO: turn the radio power off */ + local->txpower_type = PRISM2_TXPOWER_OFF; + } + break; + } + + if (local->txpower_type == PRISM2_TXPOWER_OFF) { + printk(KERN_DEBUG "Turning radio on " + "(not yet implemented)\n"); + /* TODO: turn the radio power on */ + } + + if (!wrq->u.txpower.fixed && + local->txpower_type != PRISM2_TXPOWER_AUTO) { + printk(KERN_DEBUG "Setting ALC on\n"); + val = HFA384X_TEST_CFG_BIT_ALC; + hfa384x_cmd(dev, HFA384X_CMDCODE_TEST | + (HFA384X_TEST_CFG_BITS << 8), + 1, &val, NULL); + local->txpower_type = PRISM2_TXPOWER_AUTO; + break; + } + + if (local->txpower_type != PRISM2_TXPOWER_FIXED) { + printk(KERN_DEBUG "Setting ALC off\n"); + val = HFA384X_TEST_CFG_BIT_ALC; + hfa384x_cmd(dev, HFA384X_CMDCODE_TEST | + (HFA384X_TEST_CFG_BITS << 8), + 0, &val, NULL); + local->txpower_type = PRISM2_TXPOWER_FIXED; + } + + { + char *tmp; + if (wrq->u.txpower.flags == IW_TXPOW_DBM) + tmp = "dBm"; + else if (wrq->u.txpower.flags == IW_TXPOW_MWATT) + tmp = "mW"; + else + tmp = "UNKNOWN"; + printk(KERN_DEBUG "Setting TX power to %d %s\n", + wrq->u.txpower.value, tmp); + } + if (wrq->u.txpower.flags != IW_TXPOW_MWATT) { + printk("SIOCSIWTXPOW with dBm is not supported; " + "use mW\n"); + ret = -EOPNOTSUPP; + break; + } + local->txpower = wrq->u.txpower.value; + val = prism2_txpower_mW_to_hfa386x(local->txpower); + if (hfa384x_cmd(dev, HFA384X_CMDCODE_WRITEMIF, + HFA386X_CR_MANUAL_TX_POWER, &val, NULL)) + ret = -EOPNOTSUPP; + break; + + case SIOCGIWTXPOW: + printk(KERN_DEBUG "SIOCGIWTXPOW\n"); + wrq->u.txpower.flags = IW_TXPOW_MWATT; + wrq->u.txpower.disabled = 0; + wrq->u.txpower.fixed = 0; + if (local->txpower_type == PRISM2_TXPOWER_AUTO) { + if (hfa384x_cmd(dev, HFA384X_CMDCODE_READMIF, + HFA386X_CR_MANUAL_TX_POWER, + NULL, &resp0) == 0) { + wrq->u.txpower.value = + prism2_txpower_hfa386x_to_mW(resp0); + } else { + /* Could not get real txpower; guess 30 mW */ + wrq->u.txpower.value = 30; + } + } else if (local->txpower_type == PRISM2_TXPOWER_OFF) { + wrq->u.txpower.value = 0; + wrq->u.txpower.disabled = 1; + } else if (local->txpower_type == PRISM2_TXPOWER_FIXED) { + wrq->u.txpower.value = local->txpower; + wrq->u.txpower.fixed = 1; + } else { + printk("SIOCGIWTXPOW - unknown txpower_type=%d\n", + local->txpower_type); + } + break; +#endif + case SIOCGIWPRIV: if (!wrq->u.data.pointer || verify_area(VERIFY_WRITE, wrq->u.data.pointer, @@ -2706,6 +2848,28 @@ local->frame_dump = i; break; + case SIOCDEVPRIVATE + 9: + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + break; + } + + i = *((int *) wrq->u.name); + printk(KERN_DEBUG "%s: %s ALC\n", dev->name, + i == 0 ? "Disabling" : "Enabling"); + val = HFA384X_TEST_CFG_BIT_ALC; + hfa384x_cmd(dev, HFA384X_CMDCODE_TEST | + (HFA384X_TEST_CFG_BITS << 8), + i == 0 ? 0 : 1, &val, NULL); + break; + + case SIOCDEVPRIVATE + 10: + val = __cpu_to_le16(*((int *) wrq->u.name)); + if (hfa384x_cmd(dev, HFA384X_CMDCODE_WRITEMIF, + HFA386X_CR_MANUAL_TX_POWER, &val, NULL)) + ret = -EOPNOTSUPP; + break; + /* not supported wireless extensions */ case SIOCSIWNAME: case SIOCSIWNWID: @@ -2717,10 +2881,6 @@ #if WIRELESS_EXT > 8 case SIOCSIWPOWER: case SIOCGIWPOWER: -#endif -#if WIRELESS_EXT > 9 - case SIOCSIWTXPOW: - case SIOCGIWTXPOW: #endif #if WIRELESS_EXT > 10 case SIOCSIWRETRY: