aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Buesch <mb@bu3sch.de>2007-09-20 16:14:18 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:52:24 -0400
commitfda9abcf1a5b6b78a4ead25729583541af9876b5 (patch)
treead8029180557a5c4dce3f0a4e7c118bffca25eef
parent6a724d68a38c33ba4c7f7b5f008301ac12c9ced1 (diff)
[B43]: Support for turning the radio off from software.
This adds support for turning the radio off in software. That's useful in environments, where you don't want the RF to radiate any signals, but don't want to bring the interface down. Cc: Larry Finger <larry.finger@lwfinger.net> Signed-off-by: Michael Buesch <mb@bu3sch.de> Signed-off-by: John W. Linville <linville@tuxdriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/wireless/b43/b43.h11
-rw-r--r--drivers/net/wireless/b43/main.c17
-rw-r--r--drivers/net/wireless/b43/phy.c48
3 files changed, 63 insertions, 13 deletions
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 270a2112de2a..a22435ade8ca 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -459,7 +459,6 @@ struct b43_phy {
459 u16 radio_ver; /* Radio version */ 459 u16 radio_ver; /* Radio version */
460 u8 radio_rev; /* Radio revision */ 460 u8 radio_rev; /* Radio revision */
461 461
462 bool radio_on; /* Radio switched on/off */
463 bool locked; /* Only used in b43_phy_{un}lock() */ 462 bool locked; /* Only used in b43_phy_{un}lock() */
464 bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */ 463 bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */
465 464
@@ -468,6 +467,16 @@ struct b43_phy {
468 bool aci_wlan_automatic; 467 bool aci_wlan_automatic;
469 bool aci_hw_rssi; 468 bool aci_hw_rssi;
470 469
470 /* Radio switched on/off */
471 bool radio_on;
472 struct {
473 /* Values saved when turning the radio off.
474 * They are needed when turning it on again. */
475 bool valid;
476 u16 rfover;
477 u16 rfoverval;
478 } radio_off_context;
479
471 u16 minlowsig[2]; 480 u16 minlowsig[2];
472 u16 minlowsigpos[2]; 481 u16 minlowsigpos[2];
473 482
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index cc5285407e88..b44c9f928848 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -2874,6 +2874,21 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
2874 if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) 2874 if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP))
2875 b43_set_beacon_int(dev, conf->beacon_int); 2875 b43_set_beacon_int(dev, conf->beacon_int);
2876 2876
2877 if (!!conf->radio_enabled != phy->radio_on) {
2878 if (conf->radio_enabled) {
2879 b43_radio_turn_on(dev);
2880 b43info(dev->wl, "Radio turned on by software\n");
2881 if (!dev->radio_hw_enable) {
2882 b43info(dev->wl, "The hardware RF-kill button "
2883 "still turns the radio physically off. "
2884 "Press the button to turn it on.\n");
2885 }
2886 } else {
2887 b43_radio_turn_off(dev);
2888 b43info(dev->wl, "Radio turned off by software\n");
2889 }
2890 }
2891
2877 spin_lock_irqsave(&wl->irq_lock, flags); 2892 spin_lock_irqsave(&wl->irq_lock, flags);
2878 b43_interrupt_enable(dev, savedirqs); 2893 b43_interrupt_enable(dev, savedirqs);
2879 mmiowb(); 2894 mmiowb();
@@ -3218,6 +3233,8 @@ static void setup_struct_phy_for_init(struct b43_wldev *dev,
3218 phy->aci_wlan_automatic = 0; 3233 phy->aci_wlan_automatic = 0;
3219 phy->aci_hw_rssi = 0; 3234 phy->aci_hw_rssi = 0;
3220 3235
3236 phy->radio_off_context.valid = 0;
3237
3221 lo = phy->lo_control; 3238 lo = phy->lo_control;
3222 if (lo) { 3239 if (lo) {
3223 memset(lo, 0, sizeof(*(phy->lo_control))); 3240 memset(lo, 0, sizeof(*(phy->lo_control)));
diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c
index 3282893021b0..354d18238752 100644
--- a/drivers/net/wireless/b43/phy.c
+++ b/drivers/net/wireless/b43/phy.c
@@ -1205,10 +1205,7 @@ static void b43_phy_initb2(struct b43_wldev *dev)
1205 val -= 0x0202; 1205 val -= 0x0202;
1206 } 1206 }
1207 b43_phy_write(dev, 0x03E4, 0x3000); 1207 b43_phy_write(dev, 0x03E4, 0x3000);
1208 if (phy->channel == 0xFF) 1208 b43_radio_selectchannel(dev, phy->channel, 0);
1209 b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_BG, 0);
1210 else
1211 b43_radio_selectchannel(dev, phy->channel, 0);
1212 if (phy->radio_ver != 0x2050) { 1209 if (phy->radio_ver != 0x2050) {
1213 b43_radio_write16(dev, 0x0075, 0x0080); 1210 b43_radio_write16(dev, 0x0075, 0x0080);
1214 b43_radio_write16(dev, 0x0079, 0x0081); 1211 b43_radio_write16(dev, 0x0079, 0x0081);
@@ -1256,10 +1253,7 @@ static void b43_phy_initb4(struct b43_wldev *dev)
1256 val -= 0x0202; 1253 val -= 0x0202;
1257 } 1254 }
1258 b43_phy_write(dev, 0x03E4, 0x3000); 1255 b43_phy_write(dev, 0x03E4, 0x3000);
1259 if (phy->channel == 0xFF) 1256 b43_radio_selectchannel(dev, phy->channel, 0);
1260 b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_BG, 0);
1261 else
1262 b43_radio_selectchannel(dev, phy->channel, 0);
1263 if (phy->radio_ver != 0x2050) { 1257 if (phy->radio_ver != 0x2050) {
1264 b43_radio_write16(dev, 0x0075, 0x0080); 1258 b43_radio_write16(dev, 0x0075, 0x0080);
1265 b43_radio_write16(dev, 0x0079, 0x0081); 1259 b43_radio_write16(dev, 0x0079, 0x0081);
@@ -4110,6 +4104,20 @@ int b43_radio_selectchannel(struct b43_wldev *dev,
4110 u16 freq; 4104 u16 freq;
4111 u16 channelcookie; 4105 u16 channelcookie;
4112 4106
4107 if (channel == 0xFF) {
4108 switch (phy->type) {
4109 case B43_PHYTYPE_A:
4110 channel = B43_DEFAULT_CHANNEL_A;
4111 break;
4112 case B43_PHYTYPE_B:
4113 case B43_PHYTYPE_G:
4114 channel = B43_DEFAULT_CHANNEL_BG;
4115 break;
4116 default:
4117 B43_WARN_ON(1);
4118 }
4119 }
4120
4113 /* First we set the channel radio code to prevent the 4121 /* First we set the channel radio code to prevent the
4114 * firmware from sending ghost packets. 4122 * firmware from sending ghost packets.
4115 */ 4123 */
@@ -4302,6 +4310,7 @@ void b43_radio_turn_on(struct b43_wldev *dev)
4302{ 4310{
4303 struct b43_phy *phy = &dev->phy; 4311 struct b43_phy *phy = &dev->phy;
4304 int err; 4312 int err;
4313 u8 channel;
4305 4314
4306 might_sleep(); 4315 might_sleep();
4307 4316
@@ -4321,14 +4330,23 @@ void b43_radio_turn_on(struct b43_wldev *dev)
4321 b43_phy_write(dev, 0x0015, 0x8000); 4330 b43_phy_write(dev, 0x0015, 0x8000);
4322 b43_phy_write(dev, 0x0015, 0xCC00); 4331 b43_phy_write(dev, 0x0015, 0xCC00);
4323 b43_phy_write(dev, 0x0015, (phy->gmode ? 0x00C0 : 0x0000)); 4332 b43_phy_write(dev, 0x0015, (phy->gmode ? 0x00C0 : 0x0000));
4333 if (phy->radio_off_context.valid) {
4334 /* Restore the RFover values. */
4335 b43_phy_write(dev, B43_PHY_RFOVER,
4336 phy->radio_off_context.rfover);
4337 b43_phy_write(dev, B43_PHY_RFOVERVAL,
4338 phy->radio_off_context.rfoverval);
4339 phy->radio_off_context.valid = 0;
4340 }
4341 channel = phy->channel;
4324 err = b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_BG, 1); 4342 err = b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_BG, 1);
4343 err |= b43_radio_selectchannel(dev, channel, 0);
4325 B43_WARN_ON(err); 4344 B43_WARN_ON(err);
4326 break; 4345 break;
4327 default: 4346 default:
4328 B43_WARN_ON(1); 4347 B43_WARN_ON(1);
4329 } 4348 }
4330 phy->radio_on = 1; 4349 phy->radio_on = 1;
4331 b43dbg(dev->wl, "Radio turned on\n");
4332} 4350}
4333 4351
4334void b43_radio_turn_off(struct b43_wldev *dev) 4352void b43_radio_turn_off(struct b43_wldev *dev)
@@ -4342,10 +4360,16 @@ void b43_radio_turn_off(struct b43_wldev *dev)
4342 b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008); 4360 b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008);
4343 } 4361 }
4344 if (phy->type == B43_PHYTYPE_G && dev->dev->id.revision >= 5) { 4362 if (phy->type == B43_PHYTYPE_G && dev->dev->id.revision >= 5) {
4345 b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x008C); 4363 u16 rfover, rfoverval;
4346 b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) & 0xFF73); 4364
4365 rfover = b43_phy_read(dev, B43_PHY_RFOVER);
4366 rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL);
4367 phy->radio_off_context.rfover = rfover;
4368 phy->radio_off_context.rfoverval = rfoverval;
4369 phy->radio_off_context.valid = 1;
4370 b43_phy_write(dev, B43_PHY_RFOVER, rfover | 0x008C);
4371 b43_phy_write(dev, B43_PHY_RFOVERVAL, rfoverval & 0xFF73);
4347 } else 4372 } else
4348 b43_phy_write(dev, 0x0015, 0xAA00); 4373 b43_phy_write(dev, 0x0015, 0xAA00);
4349 phy->radio_on = 0; 4374 phy->radio_on = 0;
4350 b43dbg(dev->wl, "Radio turned off\n");
4351} 4375}