diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-06-02 07:01:37 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-06-03 14:06:13 -0400 |
commit | 19d337dff95cbf76edd3ad95c0cee2732c3e1ec5 (patch) | |
tree | 33326eeb09cb9664cc8427a5dc7cd2b08b5a57c3 /drivers | |
parent | 0f6399c4c525b518644a9b09f8d6fb125a418c4d (diff) |
rfkill: rewrite
This patch completely rewrites the rfkill core to address
the following deficiencies:
* all rfkill drivers need to implement polling where necessary
rather than having one central implementation
* updating the rfkill state cannot be done from arbitrary
contexts, forcing drivers to use schedule_work and requiring
lots of code
* rfkill drivers need to keep track of soft/hard blocked
internally -- the core should do this
* the rfkill API has many unexpected quirks, for example being
asymmetric wrt. alloc/free and register/unregister
* rfkill can call back into a driver from within a function the
driver called -- this is prone to deadlocks and generally
should be avoided
* rfkill-input pointlessly is a separate module
* drivers need to #ifdef rfkill functions (unless they want to
depend on or select RFKILL) -- rfkill should provide inlines
that do nothing if it isn't compiled in
* the rfkill structure is not opaque -- drivers need to initialise
it correctly (lots of sanity checking code required) -- instead
force drivers to pass the right variables to rfkill_alloc()
* the documentation is hard to read because it always assumes the
reader is completely clueless and contains way TOO MANY CAPS
* the rfkill code needlessly uses a lot of locks and atomic
operations in locked sections
* fix LED trigger to actually change the LED when the radio state
changes -- this wasn't done before
Tested-by: Alan Jenkins <alan-jenkins@tuffmail.co.uk>
Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> [thinkpad]
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
30 files changed, 904 insertions, 1281 deletions
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 837135f0390a..5ddd8c4f9019 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c | |||
@@ -2481,10 +2481,10 @@ static int add_net_device(struct hso_device *hso_dev) | |||
2481 | return 0; | 2481 | return 0; |
2482 | } | 2482 | } |
2483 | 2483 | ||
2484 | static int hso_radio_toggle(void *data, enum rfkill_state state) | 2484 | static int hso_rfkill_set_block(void *data, bool blocked) |
2485 | { | 2485 | { |
2486 | struct hso_device *hso_dev = data; | 2486 | struct hso_device *hso_dev = data; |
2487 | int enabled = (state == RFKILL_STATE_UNBLOCKED); | 2487 | int enabled = !blocked; |
2488 | int rv; | 2488 | int rv; |
2489 | 2489 | ||
2490 | mutex_lock(&hso_dev->mutex); | 2490 | mutex_lock(&hso_dev->mutex); |
@@ -2498,6 +2498,10 @@ static int hso_radio_toggle(void *data, enum rfkill_state state) | |||
2498 | return rv; | 2498 | return rv; |
2499 | } | 2499 | } |
2500 | 2500 | ||
2501 | static const struct rfkill_ops hso_rfkill_ops = { | ||
2502 | .set_block = hso_rfkill_set_block, | ||
2503 | }; | ||
2504 | |||
2501 | /* Creates and sets up everything for rfkill */ | 2505 | /* Creates and sets up everything for rfkill */ |
2502 | static void hso_create_rfkill(struct hso_device *hso_dev, | 2506 | static void hso_create_rfkill(struct hso_device *hso_dev, |
2503 | struct usb_interface *interface) | 2507 | struct usb_interface *interface) |
@@ -2506,29 +2510,25 @@ static void hso_create_rfkill(struct hso_device *hso_dev, | |||
2506 | struct device *dev = &hso_net->net->dev; | 2510 | struct device *dev = &hso_net->net->dev; |
2507 | char *rfkn; | 2511 | char *rfkn; |
2508 | 2512 | ||
2509 | hso_net->rfkill = rfkill_allocate(&interface_to_usbdev(interface)->dev, | ||
2510 | RFKILL_TYPE_WWAN); | ||
2511 | if (!hso_net->rfkill) { | ||
2512 | dev_err(dev, "%s - Out of memory\n", __func__); | ||
2513 | return; | ||
2514 | } | ||
2515 | rfkn = kzalloc(20, GFP_KERNEL); | 2513 | rfkn = kzalloc(20, GFP_KERNEL); |
2516 | if (!rfkn) { | 2514 | if (!rfkn) |
2517 | rfkill_free(hso_net->rfkill); | ||
2518 | hso_net->rfkill = NULL; | ||
2519 | dev_err(dev, "%s - Out of memory\n", __func__); | 2515 | dev_err(dev, "%s - Out of memory\n", __func__); |
2520 | return; | 2516 | |
2521 | } | ||
2522 | snprintf(rfkn, 20, "hso-%d", | 2517 | snprintf(rfkn, 20, "hso-%d", |
2523 | interface->altsetting->desc.bInterfaceNumber); | 2518 | interface->altsetting->desc.bInterfaceNumber); |
2524 | hso_net->rfkill->name = rfkn; | 2519 | |
2525 | hso_net->rfkill->state = RFKILL_STATE_UNBLOCKED; | 2520 | hso_net->rfkill = rfkill_alloc(rfkn, |
2526 | hso_net->rfkill->data = hso_dev; | 2521 | &interface_to_usbdev(interface)->dev, |
2527 | hso_net->rfkill->toggle_radio = hso_radio_toggle; | 2522 | RFKILL_TYPE_WWAN, |
2523 | &hso_rfkill_ops, hso_dev); | ||
2524 | if (!hso_net->rfkill) { | ||
2525 | dev_err(dev, "%s - Out of memory\n", __func__); | ||
2526 | kfree(rfkn); | ||
2527 | return; | ||
2528 | } | ||
2528 | if (rfkill_register(hso_net->rfkill) < 0) { | 2529 | if (rfkill_register(hso_net->rfkill) < 0) { |
2530 | rfkill_destroy(hso_net->rfkill); | ||
2529 | kfree(rfkn); | 2531 | kfree(rfkn); |
2530 | hso_net->rfkill->name = NULL; | ||
2531 | rfkill_free(hso_net->rfkill); | ||
2532 | hso_net->rfkill = NULL; | 2532 | hso_net->rfkill = NULL; |
2533 | dev_err(dev, "%s - Failed to register rfkill\n", __func__); | 2533 | dev_err(dev, "%s - Failed to register rfkill\n", __func__); |
2534 | return; | 2534 | return; |
@@ -3165,8 +3165,10 @@ static void hso_free_interface(struct usb_interface *interface) | |||
3165 | hso_stop_net_device(network_table[i]); | 3165 | hso_stop_net_device(network_table[i]); |
3166 | cancel_work_sync(&network_table[i]->async_put_intf); | 3166 | cancel_work_sync(&network_table[i]->async_put_intf); |
3167 | cancel_work_sync(&network_table[i]->async_get_intf); | 3167 | cancel_work_sync(&network_table[i]->async_get_intf); |
3168 | if (rfk) | 3168 | if (rfk) { |
3169 | rfkill_unregister(rfk); | 3169 | rfkill_unregister(rfk); |
3170 | rfkill_destroy(rfk); | ||
3171 | } | ||
3170 | hso_free_net_device(network_table[i]); | 3172 | hso_free_net_device(network_table[i]); |
3171 | } | 3173 | } |
3172 | } | 3174 | } |
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 796a3adffea0..515880aa2116 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -460,12 +460,9 @@ struct ath_led { | |||
460 | bool registered; | 460 | bool registered; |
461 | }; | 461 | }; |
462 | 462 | ||
463 | /* Rfkill */ | ||
464 | #define ATH_RFKILL_POLL_INTERVAL 2000 /* msecs */ | ||
465 | |||
466 | struct ath_rfkill { | 463 | struct ath_rfkill { |
467 | struct rfkill *rfkill; | 464 | struct rfkill *rfkill; |
468 | struct delayed_work rfkill_poll; | 465 | struct rfkill_ops ops; |
469 | char rfkill_name[32]; | 466 | char rfkill_name[32]; |
470 | }; | 467 | }; |
471 | 468 | ||
@@ -509,8 +506,6 @@ struct ath_rfkill { | |||
509 | #define SC_OP_RXFLUSH BIT(7) | 506 | #define SC_OP_RXFLUSH BIT(7) |
510 | #define SC_OP_LED_ASSOCIATED BIT(8) | 507 | #define SC_OP_LED_ASSOCIATED BIT(8) |
511 | #define SC_OP_RFKILL_REGISTERED BIT(9) | 508 | #define SC_OP_RFKILL_REGISTERED BIT(9) |
512 | #define SC_OP_RFKILL_SW_BLOCKED BIT(10) | ||
513 | #define SC_OP_RFKILL_HW_BLOCKED BIT(11) | ||
514 | #define SC_OP_WAIT_FOR_BEACON BIT(12) | 509 | #define SC_OP_WAIT_FOR_BEACON BIT(12) |
515 | #define SC_OP_LED_ON BIT(13) | 510 | #define SC_OP_LED_ON BIT(13) |
516 | #define SC_OP_SCANNING BIT(14) | 511 | #define SC_OP_SCANNING BIT(14) |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 61da08a1648c..f7baa406918b 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -1192,120 +1192,69 @@ static bool ath_is_rfkill_set(struct ath_softc *sc) | |||
1192 | ah->rfkill_polarity; | 1192 | ah->rfkill_polarity; |
1193 | } | 1193 | } |
1194 | 1194 | ||
1195 | /* h/w rfkill poll function */ | 1195 | /* s/w rfkill handlers */ |
1196 | static void ath_rfkill_poll(struct work_struct *work) | 1196 | static int ath_rfkill_set_block(void *data, bool blocked) |
1197 | { | 1197 | { |
1198 | struct ath_softc *sc = container_of(work, struct ath_softc, | 1198 | struct ath_softc *sc = data; |
1199 | rf_kill.rfkill_poll.work); | ||
1200 | bool radio_on; | ||
1201 | |||
1202 | if (sc->sc_flags & SC_OP_INVALID) | ||
1203 | return; | ||
1204 | |||
1205 | radio_on = !ath_is_rfkill_set(sc); | ||
1206 | |||
1207 | /* | ||
1208 | * enable/disable radio only when there is a | ||
1209 | * state change in RF switch | ||
1210 | */ | ||
1211 | if (radio_on == !!(sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED)) { | ||
1212 | enum rfkill_state state; | ||
1213 | |||
1214 | if (sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED) { | ||
1215 | state = radio_on ? RFKILL_STATE_SOFT_BLOCKED | ||
1216 | : RFKILL_STATE_HARD_BLOCKED; | ||
1217 | } else if (radio_on) { | ||
1218 | ath_radio_enable(sc); | ||
1219 | state = RFKILL_STATE_UNBLOCKED; | ||
1220 | } else { | ||
1221 | ath_radio_disable(sc); | ||
1222 | state = RFKILL_STATE_HARD_BLOCKED; | ||
1223 | } | ||
1224 | |||
1225 | if (state == RFKILL_STATE_HARD_BLOCKED) | ||
1226 | sc->sc_flags |= SC_OP_RFKILL_HW_BLOCKED; | ||
1227 | else | ||
1228 | sc->sc_flags &= ~SC_OP_RFKILL_HW_BLOCKED; | ||
1229 | 1199 | ||
1230 | rfkill_force_state(sc->rf_kill.rfkill, state); | 1200 | if (blocked) |
1231 | } | 1201 | ath_radio_disable(sc); |
1202 | else | ||
1203 | ath_radio_enable(sc); | ||
1232 | 1204 | ||
1233 | queue_delayed_work(sc->hw->workqueue, &sc->rf_kill.rfkill_poll, | 1205 | return 0; |
1234 | msecs_to_jiffies(ATH_RFKILL_POLL_INTERVAL)); | ||
1235 | } | 1206 | } |
1236 | 1207 | ||
1237 | /* s/w rfkill handler */ | 1208 | static void ath_rfkill_poll_state(struct rfkill *rfkill, void *data) |
1238 | static int ath_sw_toggle_radio(void *data, enum rfkill_state state) | ||
1239 | { | 1209 | { |
1240 | struct ath_softc *sc = data; | 1210 | struct ath_softc *sc = data; |
1211 | bool blocked = !!ath_is_rfkill_set(sc); | ||
1241 | 1212 | ||
1242 | switch (state) { | 1213 | if (rfkill_set_hw_state(rfkill, blocked)) |
1243 | case RFKILL_STATE_SOFT_BLOCKED: | 1214 | ath_radio_disable(sc); |
1244 | if (!(sc->sc_flags & (SC_OP_RFKILL_HW_BLOCKED | | 1215 | else |
1245 | SC_OP_RFKILL_SW_BLOCKED))) | 1216 | ath_radio_enable(sc); |
1246 | ath_radio_disable(sc); | ||
1247 | sc->sc_flags |= SC_OP_RFKILL_SW_BLOCKED; | ||
1248 | return 0; | ||
1249 | case RFKILL_STATE_UNBLOCKED: | ||
1250 | if ((sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED)) { | ||
1251 | sc->sc_flags &= ~SC_OP_RFKILL_SW_BLOCKED; | ||
1252 | if (sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED) { | ||
1253 | DPRINTF(sc, ATH_DBG_FATAL, "Can't turn on the" | ||
1254 | "radio as it is disabled by h/w\n"); | ||
1255 | return -EPERM; | ||
1256 | } | ||
1257 | ath_radio_enable(sc); | ||
1258 | } | ||
1259 | return 0; | ||
1260 | default: | ||
1261 | return -EINVAL; | ||
1262 | } | ||
1263 | } | 1217 | } |
1264 | 1218 | ||
1265 | /* Init s/w rfkill */ | 1219 | /* Init s/w rfkill */ |
1266 | static int ath_init_sw_rfkill(struct ath_softc *sc) | 1220 | static int ath_init_sw_rfkill(struct ath_softc *sc) |
1267 | { | 1221 | { |
1268 | sc->rf_kill.rfkill = rfkill_allocate(wiphy_dev(sc->hw->wiphy), | 1222 | sc->rf_kill.ops.set_block = ath_rfkill_set_block; |
1269 | RFKILL_TYPE_WLAN); | 1223 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) |
1224 | sc->rf_kill.ops.poll = ath_rfkill_poll_state; | ||
1225 | |||
1226 | snprintf(sc->rf_kill.rfkill_name, sizeof(sc->rf_kill.rfkill_name), | ||
1227 | "ath9k-%s::rfkill", wiphy_name(sc->hw->wiphy)); | ||
1228 | |||
1229 | sc->rf_kill.rfkill = rfkill_alloc(sc->rf_kill.rfkill_name, | ||
1230 | wiphy_dev(sc->hw->wiphy), | ||
1231 | RFKILL_TYPE_WLAN, | ||
1232 | &sc->rf_kill.ops, sc); | ||
1270 | if (!sc->rf_kill.rfkill) { | 1233 | if (!sc->rf_kill.rfkill) { |
1271 | DPRINTF(sc, ATH_DBG_FATAL, "Failed to allocate rfkill\n"); | 1234 | DPRINTF(sc, ATH_DBG_FATAL, "Failed to allocate rfkill\n"); |
1272 | return -ENOMEM; | 1235 | return -ENOMEM; |
1273 | } | 1236 | } |
1274 | 1237 | ||
1275 | snprintf(sc->rf_kill.rfkill_name, sizeof(sc->rf_kill.rfkill_name), | ||
1276 | "ath9k-%s::rfkill", wiphy_name(sc->hw->wiphy)); | ||
1277 | sc->rf_kill.rfkill->name = sc->rf_kill.rfkill_name; | ||
1278 | sc->rf_kill.rfkill->data = sc; | ||
1279 | sc->rf_kill.rfkill->toggle_radio = ath_sw_toggle_radio; | ||
1280 | sc->rf_kill.rfkill->state = RFKILL_STATE_UNBLOCKED; | ||
1281 | |||
1282 | return 0; | 1238 | return 0; |
1283 | } | 1239 | } |
1284 | 1240 | ||
1285 | /* Deinitialize rfkill */ | 1241 | /* Deinitialize rfkill */ |
1286 | static void ath_deinit_rfkill(struct ath_softc *sc) | 1242 | static void ath_deinit_rfkill(struct ath_softc *sc) |
1287 | { | 1243 | { |
1288 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
1289 | cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); | ||
1290 | |||
1291 | if (sc->sc_flags & SC_OP_RFKILL_REGISTERED) { | 1244 | if (sc->sc_flags & SC_OP_RFKILL_REGISTERED) { |
1292 | rfkill_unregister(sc->rf_kill.rfkill); | 1245 | rfkill_unregister(sc->rf_kill.rfkill); |
1246 | rfkill_destroy(sc->rf_kill.rfkill); | ||
1293 | sc->sc_flags &= ~SC_OP_RFKILL_REGISTERED; | 1247 | sc->sc_flags &= ~SC_OP_RFKILL_REGISTERED; |
1294 | sc->rf_kill.rfkill = NULL; | ||
1295 | } | 1248 | } |
1296 | } | 1249 | } |
1297 | 1250 | ||
1298 | static int ath_start_rfkill_poll(struct ath_softc *sc) | 1251 | static int ath_start_rfkill_poll(struct ath_softc *sc) |
1299 | { | 1252 | { |
1300 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
1301 | queue_delayed_work(sc->hw->workqueue, | ||
1302 | &sc->rf_kill.rfkill_poll, 0); | ||
1303 | |||
1304 | if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) { | 1253 | if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) { |
1305 | if (rfkill_register(sc->rf_kill.rfkill)) { | 1254 | if (rfkill_register(sc->rf_kill.rfkill)) { |
1306 | DPRINTF(sc, ATH_DBG_FATAL, | 1255 | DPRINTF(sc, ATH_DBG_FATAL, |
1307 | "Unable to register rfkill\n"); | 1256 | "Unable to register rfkill\n"); |
1308 | rfkill_free(sc->rf_kill.rfkill); | 1257 | rfkill_destroy(sc->rf_kill.rfkill); |
1309 | 1258 | ||
1310 | /* Deinitialize the device */ | 1259 | /* Deinitialize the device */ |
1311 | ath_cleanup(sc); | 1260 | ath_cleanup(sc); |
@@ -1678,10 +1627,6 @@ int ath_attach(u16 devid, struct ath_softc *sc) | |||
1678 | goto error_attach; | 1627 | goto error_attach; |
1679 | 1628 | ||
1680 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) | 1629 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) |
1681 | /* Initialze h/w Rfkill */ | ||
1682 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
1683 | INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll); | ||
1684 | |||
1685 | /* Initialize s/w rfkill */ | 1630 | /* Initialize s/w rfkill */ |
1686 | error = ath_init_sw_rfkill(sc); | 1631 | error = ath_init_sw_rfkill(sc); |
1687 | if (error) | 1632 | if (error) |
@@ -2214,10 +2159,8 @@ static void ath9k_stop(struct ieee80211_hw *hw) | |||
2214 | } else | 2159 | } else |
2215 | sc->rx.rxlink = NULL; | 2160 | sc->rx.rxlink = NULL; |
2216 | 2161 | ||
2217 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) | 2162 | rfkill_pause_polling(sc->rf_kill.rfkill); |
2218 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | 2163 | |
2219 | cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); | ||
2220 | #endif | ||
2221 | /* disable HAL and put h/w to sleep */ | 2164 | /* disable HAL and put h/w to sleep */ |
2222 | ath9k_hw_disable(sc->sc_ah); | 2165 | ath9k_hw_disable(sc->sc_ah); |
2223 | ath9k_hw_configpcipowersave(sc->sc_ah, 1); | 2166 | ath9k_hw_configpcipowersave(sc->sc_ah, 1); |
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 168411d322a2..ccdf20a2e9be 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c | |||
@@ -227,11 +227,6 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) | |||
227 | 227 | ||
228 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); | 228 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); |
229 | 229 | ||
230 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) | ||
231 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
232 | cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); | ||
233 | #endif | ||
234 | |||
235 | pci_save_state(pdev); | 230 | pci_save_state(pdev); |
236 | pci_disable_device(pdev); | 231 | pci_disable_device(pdev); |
237 | pci_set_power_state(pdev, PCI_D3hot); | 232 | pci_set_power_state(pdev, PCI_D3hot); |
@@ -256,16 +251,6 @@ static int ath_pci_resume(struct pci_dev *pdev) | |||
256 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | 251 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); |
257 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); | 252 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); |
258 | 253 | ||
259 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) | ||
260 | /* | ||
261 | * check the h/w rfkill state on resume | ||
262 | * and start the rfkill poll timer | ||
263 | */ | ||
264 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
265 | queue_delayed_work(sc->hw->workqueue, | ||
266 | &sc->rf_kill.rfkill_poll, 0); | ||
267 | #endif | ||
268 | |||
269 | return 0; | 254 | return 0; |
270 | } | 255 | } |
271 | 256 | ||
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 21572e40b79d..07a99e3faf94 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig | |||
@@ -102,7 +102,7 @@ config B43_LEDS | |||
102 | # if it's possible. | 102 | # if it's possible. |
103 | config B43_RFKILL | 103 | config B43_RFKILL |
104 | bool | 104 | bool |
105 | depends on B43 && (RFKILL = y || RFKILL = B43) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43) | 105 | depends on B43 && (RFKILL = y || RFKILL = B43) |
106 | default y | 106 | default y |
107 | 107 | ||
108 | # This config option automatically enables b43 HW-RNG support, | 108 | # This config option automatically enables b43 HW-RNG support, |
diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c index 76f4c7bad8b8..9a498d3fc653 100644 --- a/drivers/net/wireless/b43/leds.c +++ b/drivers/net/wireless/b43/leds.c | |||
@@ -87,7 +87,7 @@ static void b43_led_brightness_set(struct led_classdev *led_dev, | |||
87 | } | 87 | } |
88 | 88 | ||
89 | static int b43_register_led(struct b43_wldev *dev, struct b43_led *led, | 89 | static int b43_register_led(struct b43_wldev *dev, struct b43_led *led, |
90 | const char *name, char *default_trigger, | 90 | const char *name, const char *default_trigger, |
91 | u8 led_index, bool activelow) | 91 | u8 led_index, bool activelow) |
92 | { | 92 | { |
93 | int err; | 93 | int err; |
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index cb4a8712946a..1d3e40095ada 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -3470,7 +3470,7 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) | |||
3470 | 3470 | ||
3471 | if (!!conf->radio_enabled != phy->radio_on) { | 3471 | if (!!conf->radio_enabled != phy->radio_on) { |
3472 | if (conf->radio_enabled) { | 3472 | if (conf->radio_enabled) { |
3473 | b43_software_rfkill(dev, RFKILL_STATE_UNBLOCKED); | 3473 | b43_software_rfkill(dev, false); |
3474 | b43info(dev->wl, "Radio turned on by software\n"); | 3474 | b43info(dev->wl, "Radio turned on by software\n"); |
3475 | if (!dev->radio_hw_enable) { | 3475 | if (!dev->radio_hw_enable) { |
3476 | b43info(dev->wl, "The hardware RF-kill button " | 3476 | b43info(dev->wl, "The hardware RF-kill button " |
@@ -3478,7 +3478,7 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) | |||
3478 | "Press the button to turn it on.\n"); | 3478 | "Press the button to turn it on.\n"); |
3479 | } | 3479 | } |
3480 | } else { | 3480 | } else { |
3481 | b43_software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED); | 3481 | b43_software_rfkill(dev, true); |
3482 | b43info(dev->wl, "Radio turned off by software\n"); | 3482 | b43info(dev->wl, "Radio turned off by software\n"); |
3483 | } | 3483 | } |
3484 | } | 3484 | } |
diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c index c836c077d51d..816e028a2620 100644 --- a/drivers/net/wireless/b43/phy_a.c +++ b/drivers/net/wireless/b43/phy_a.c | |||
@@ -480,11 +480,11 @@ static bool b43_aphy_op_supports_hwpctl(struct b43_wldev *dev) | |||
480 | } | 480 | } |
481 | 481 | ||
482 | static void b43_aphy_op_software_rfkill(struct b43_wldev *dev, | 482 | static void b43_aphy_op_software_rfkill(struct b43_wldev *dev, |
483 | enum rfkill_state state) | 483 | bool blocked) |
484 | { | 484 | { |
485 | struct b43_phy *phy = &dev->phy; | 485 | struct b43_phy *phy = &dev->phy; |
486 | 486 | ||
487 | if (state == RFKILL_STATE_UNBLOCKED) { | 487 | if (!blocked) { |
488 | if (phy->radio_on) | 488 | if (phy->radio_on) |
489 | return; | 489 | return; |
490 | b43_radio_write16(dev, 0x0004, 0x00C0); | 490 | b43_radio_write16(dev, 0x0004, 0x00C0); |
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index e176b6e0d9cf..6d241622210e 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c | |||
@@ -84,7 +84,7 @@ int b43_phy_init(struct b43_wldev *dev) | |||
84 | 84 | ||
85 | phy->channel = ops->get_default_chan(dev); | 85 | phy->channel = ops->get_default_chan(dev); |
86 | 86 | ||
87 | ops->software_rfkill(dev, RFKILL_STATE_UNBLOCKED); | 87 | ops->software_rfkill(dev, false); |
88 | err = ops->init(dev); | 88 | err = ops->init(dev); |
89 | if (err) { | 89 | if (err) { |
90 | b43err(dev->wl, "PHY init failed\n"); | 90 | b43err(dev->wl, "PHY init failed\n"); |
@@ -104,7 +104,7 @@ err_phy_exit: | |||
104 | if (ops->exit) | 104 | if (ops->exit) |
105 | ops->exit(dev); | 105 | ops->exit(dev); |
106 | err_block_rf: | 106 | err_block_rf: |
107 | ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED); | 107 | ops->software_rfkill(dev, true); |
108 | 108 | ||
109 | return err; | 109 | return err; |
110 | } | 110 | } |
@@ -113,7 +113,7 @@ void b43_phy_exit(struct b43_wldev *dev) | |||
113 | { | 113 | { |
114 | const struct b43_phy_operations *ops = dev->phy.ops; | 114 | const struct b43_phy_operations *ops = dev->phy.ops; |
115 | 115 | ||
116 | ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED); | 116 | ops->software_rfkill(dev, true); |
117 | if (ops->exit) | 117 | if (ops->exit) |
118 | ops->exit(dev); | 118 | ops->exit(dev); |
119 | } | 119 | } |
@@ -295,18 +295,13 @@ err_restore_cookie: | |||
295 | return err; | 295 | return err; |
296 | } | 296 | } |
297 | 297 | ||
298 | void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state) | 298 | void b43_software_rfkill(struct b43_wldev *dev, bool blocked) |
299 | { | 299 | { |
300 | struct b43_phy *phy = &dev->phy; | 300 | struct b43_phy *phy = &dev->phy; |
301 | 301 | ||
302 | if (state == RFKILL_STATE_HARD_BLOCKED) { | ||
303 | /* We cannot hardware-block the device */ | ||
304 | state = RFKILL_STATE_SOFT_BLOCKED; | ||
305 | } | ||
306 | |||
307 | b43_mac_suspend(dev); | 302 | b43_mac_suspend(dev); |
308 | phy->ops->software_rfkill(dev, state); | 303 | phy->ops->software_rfkill(dev, blocked); |
309 | phy->radio_on = (state == RFKILL_STATE_UNBLOCKED); | 304 | phy->radio_on = !blocked; |
310 | b43_mac_enable(dev); | 305 | b43_mac_enable(dev); |
311 | } | 306 | } |
312 | 307 | ||
diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index b2d99101947b..f4c2d79cbc89 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h | |||
@@ -159,7 +159,7 @@ struct b43_phy_operations { | |||
159 | 159 | ||
160 | /* Radio */ | 160 | /* Radio */ |
161 | bool (*supports_hwpctl)(struct b43_wldev *dev); | 161 | bool (*supports_hwpctl)(struct b43_wldev *dev); |
162 | void (*software_rfkill)(struct b43_wldev *dev, enum rfkill_state state); | 162 | void (*software_rfkill)(struct b43_wldev *dev, bool blocked); |
163 | void (*switch_analog)(struct b43_wldev *dev, bool on); | 163 | void (*switch_analog)(struct b43_wldev *dev, bool on); |
164 | int (*switch_channel)(struct b43_wldev *dev, unsigned int new_channel); | 164 | int (*switch_channel)(struct b43_wldev *dev, unsigned int new_channel); |
165 | unsigned int (*get_default_chan)(struct b43_wldev *dev); | 165 | unsigned int (*get_default_chan)(struct b43_wldev *dev); |
@@ -364,7 +364,7 @@ int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel); | |||
364 | /** | 364 | /** |
365 | * b43_software_rfkill - Turn the radio ON or OFF in software. | 365 | * b43_software_rfkill - Turn the radio ON or OFF in software. |
366 | */ | 366 | */ |
367 | void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state); | 367 | void b43_software_rfkill(struct b43_wldev *dev, bool blocked); |
368 | 368 | ||
369 | /** | 369 | /** |
370 | * b43_phy_txpower_check - Check TX power output. | 370 | * b43_phy_txpower_check - Check TX power output. |
diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index e7b98f013b0f..5300232449f6 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c | |||
@@ -2592,7 +2592,7 @@ static bool b43_gphy_op_supports_hwpctl(struct b43_wldev *dev) | |||
2592 | } | 2592 | } |
2593 | 2593 | ||
2594 | static void b43_gphy_op_software_rfkill(struct b43_wldev *dev, | 2594 | static void b43_gphy_op_software_rfkill(struct b43_wldev *dev, |
2595 | enum rfkill_state state) | 2595 | bool blocked) |
2596 | { | 2596 | { |
2597 | struct b43_phy *phy = &dev->phy; | 2597 | struct b43_phy *phy = &dev->phy; |
2598 | struct b43_phy_g *gphy = phy->g; | 2598 | struct b43_phy_g *gphy = phy->g; |
@@ -2600,7 +2600,7 @@ static void b43_gphy_op_software_rfkill(struct b43_wldev *dev, | |||
2600 | 2600 | ||
2601 | might_sleep(); | 2601 | might_sleep(); |
2602 | 2602 | ||
2603 | if (state == RFKILL_STATE_UNBLOCKED) { | 2603 | if (!blocked) { |
2604 | /* Turn radio ON */ | 2604 | /* Turn radio ON */ |
2605 | if (phy->radio_on) | 2605 | if (phy->radio_on) |
2606 | return; | 2606 | return; |
diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 58e319d6b1ed..ea0d3a3a6a64 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c | |||
@@ -488,7 +488,7 @@ static void b43_lpphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) | |||
488 | } | 488 | } |
489 | 489 | ||
490 | static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev, | 490 | static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev, |
491 | enum rfkill_state state) | 491 | bool blocked) |
492 | { | 492 | { |
493 | //TODO | 493 | //TODO |
494 | } | 494 | } |
diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 8bcfda5f3f07..be7b5604947b 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c | |||
@@ -579,7 +579,7 @@ static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) | |||
579 | } | 579 | } |
580 | 580 | ||
581 | static void b43_nphy_op_software_rfkill(struct b43_wldev *dev, | 581 | static void b43_nphy_op_software_rfkill(struct b43_wldev *dev, |
582 | enum rfkill_state state) | 582 | bool blocked) |
583 | {//TODO | 583 | {//TODO |
584 | } | 584 | } |
585 | 585 | ||
diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c index 9e1d00bc24d3..96047843cd56 100644 --- a/drivers/net/wireless/b43/rfkill.c +++ b/drivers/net/wireless/b43/rfkill.c | |||
@@ -45,12 +45,11 @@ static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) | |||
45 | } | 45 | } |
46 | 46 | ||
47 | /* The poll callback for the hardware button. */ | 47 | /* The poll callback for the hardware button. */ |
48 | static void b43_rfkill_poll(struct input_polled_dev *poll_dev) | 48 | static void b43_rfkill_poll(struct rfkill *rfkill, void *data) |
49 | { | 49 | { |
50 | struct b43_wldev *dev = poll_dev->private; | 50 | struct b43_wldev *dev = data; |
51 | struct b43_wl *wl = dev->wl; | 51 | struct b43_wl *wl = dev->wl; |
52 | bool enabled; | 52 | bool enabled; |
53 | bool report_change = 0; | ||
54 | 53 | ||
55 | mutex_lock(&wl->mutex); | 54 | mutex_lock(&wl->mutex); |
56 | if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED)) { | 55 | if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED)) { |
@@ -60,68 +59,55 @@ static void b43_rfkill_poll(struct input_polled_dev *poll_dev) | |||
60 | enabled = b43_is_hw_radio_enabled(dev); | 59 | enabled = b43_is_hw_radio_enabled(dev); |
61 | if (unlikely(enabled != dev->radio_hw_enable)) { | 60 | if (unlikely(enabled != dev->radio_hw_enable)) { |
62 | dev->radio_hw_enable = enabled; | 61 | dev->radio_hw_enable = enabled; |
63 | report_change = 1; | ||
64 | b43info(wl, "Radio hardware status changed to %s\n", | 62 | b43info(wl, "Radio hardware status changed to %s\n", |
65 | enabled ? "ENABLED" : "DISABLED"); | 63 | enabled ? "ENABLED" : "DISABLED"); |
64 | enabled = !rfkill_set_hw_state(rfkill, !enabled); | ||
65 | if (enabled != dev->phy.radio_on) | ||
66 | b43_software_rfkill(dev, !enabled); | ||
66 | } | 67 | } |
67 | mutex_unlock(&wl->mutex); | 68 | mutex_unlock(&wl->mutex); |
68 | |||
69 | /* send the radio switch event to the system - note both a key press | ||
70 | * and a release are required */ | ||
71 | if (unlikely(report_change)) { | ||
72 | input_report_key(poll_dev->input, KEY_WLAN, 1); | ||
73 | input_report_key(poll_dev->input, KEY_WLAN, 0); | ||
74 | } | ||
75 | } | 69 | } |
76 | 70 | ||
77 | /* Called when the RFKILL toggled in software. */ | 71 | /* Called when the RFKILL toggled in software. */ |
78 | static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state) | 72 | static int b43_rfkill_soft_set(void *data, bool blocked) |
79 | { | 73 | { |
80 | struct b43_wldev *dev = data; | 74 | struct b43_wldev *dev = data; |
81 | struct b43_wl *wl = dev->wl; | 75 | struct b43_wl *wl = dev->wl; |
82 | int err = -EBUSY; | 76 | int err = -EINVAL; |
83 | 77 | ||
84 | if (!wl->rfkill.registered) | 78 | if (WARN_ON(!wl->rfkill.registered)) |
85 | return 0; | 79 | return -EINVAL; |
86 | 80 | ||
87 | mutex_lock(&wl->mutex); | 81 | mutex_lock(&wl->mutex); |
82 | |||
88 | if (b43_status(dev) < B43_STAT_INITIALIZED) | 83 | if (b43_status(dev) < B43_STAT_INITIALIZED) |
89 | goto out_unlock; | 84 | goto out_unlock; |
85 | |||
86 | if (!dev->radio_hw_enable) | ||
87 | goto out_unlock; | ||
88 | |||
89 | if (!blocked != dev->phy.radio_on) | ||
90 | b43_software_rfkill(dev, blocked); | ||
90 | err = 0; | 91 | err = 0; |
91 | switch (state) { | ||
92 | case RFKILL_STATE_UNBLOCKED: | ||
93 | if (!dev->radio_hw_enable) { | ||
94 | /* No luck. We can't toggle the hardware RF-kill | ||
95 | * button from software. */ | ||
96 | err = -EBUSY; | ||
97 | goto out_unlock; | ||
98 | } | ||
99 | if (!dev->phy.radio_on) | ||
100 | b43_software_rfkill(dev, state); | ||
101 | break; | ||
102 | case RFKILL_STATE_SOFT_BLOCKED: | ||
103 | if (dev->phy.radio_on) | ||
104 | b43_software_rfkill(dev, state); | ||
105 | break; | ||
106 | default: | ||
107 | b43warn(wl, "Received unexpected rfkill state %d.\n", state); | ||
108 | break; | ||
109 | } | ||
110 | out_unlock: | 92 | out_unlock: |
111 | mutex_unlock(&wl->mutex); | 93 | mutex_unlock(&wl->mutex); |
112 | |||
113 | return err; | 94 | return err; |
114 | } | 95 | } |
115 | 96 | ||
116 | char *b43_rfkill_led_name(struct b43_wldev *dev) | 97 | const char *b43_rfkill_led_name(struct b43_wldev *dev) |
117 | { | 98 | { |
118 | struct b43_rfkill *rfk = &(dev->wl->rfkill); | 99 | struct b43_rfkill *rfk = &(dev->wl->rfkill); |
119 | 100 | ||
120 | if (!rfk->registered) | 101 | if (!rfk->registered) |
121 | return NULL; | 102 | return NULL; |
122 | return rfkill_get_led_name(rfk->rfkill); | 103 | return rfkill_get_led_trigger_name(rfk->rfkill); |
123 | } | 104 | } |
124 | 105 | ||
106 | static const struct rfkill_ops b43_rfkill_ops = { | ||
107 | .set_block = b43_rfkill_soft_set, | ||
108 | .poll = b43_rfkill_poll, | ||
109 | }; | ||
110 | |||
125 | void b43_rfkill_init(struct b43_wldev *dev) | 111 | void b43_rfkill_init(struct b43_wldev *dev) |
126 | { | 112 | { |
127 | struct b43_wl *wl = dev->wl; | 113 | struct b43_wl *wl = dev->wl; |
@@ -130,65 +116,26 @@ void b43_rfkill_init(struct b43_wldev *dev) | |||
130 | 116 | ||
131 | rfk->registered = 0; | 117 | rfk->registered = 0; |
132 | 118 | ||
133 | rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN); | ||
134 | if (!rfk->rfkill) | ||
135 | goto out_error; | ||
136 | snprintf(rfk->name, sizeof(rfk->name), | 119 | snprintf(rfk->name, sizeof(rfk->name), |
137 | "b43-%s", wiphy_name(wl->hw->wiphy)); | 120 | "b43-%s", wiphy_name(wl->hw->wiphy)); |
138 | rfk->rfkill->name = rfk->name; | ||
139 | rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; | ||
140 | rfk->rfkill->data = dev; | ||
141 | rfk->rfkill->toggle_radio = b43_rfkill_soft_toggle; | ||
142 | |||
143 | rfk->poll_dev = input_allocate_polled_device(); | ||
144 | if (!rfk->poll_dev) { | ||
145 | rfkill_free(rfk->rfkill); | ||
146 | goto err_freed_rfk; | ||
147 | } | ||
148 | |||
149 | rfk->poll_dev->private = dev; | ||
150 | rfk->poll_dev->poll = b43_rfkill_poll; | ||
151 | rfk->poll_dev->poll_interval = 1000; /* msecs */ | ||
152 | 121 | ||
153 | rfk->poll_dev->input->name = rfk->name; | 122 | rfk->rfkill = rfkill_alloc(rfk->name, |
154 | rfk->poll_dev->input->id.bustype = BUS_HOST; | 123 | dev->dev->dev, |
155 | rfk->poll_dev->input->id.vendor = dev->dev->bus->boardinfo.vendor; | 124 | RFKILL_TYPE_WLAN, |
156 | rfk->poll_dev->input->evbit[0] = BIT(EV_KEY); | 125 | &b43_rfkill_ops, dev); |
157 | set_bit(KEY_WLAN, rfk->poll_dev->input->keybit); | 126 | if (!rfk->rfkill) |
127 | goto out_error; | ||
158 | 128 | ||
159 | err = rfkill_register(rfk->rfkill); | 129 | err = rfkill_register(rfk->rfkill); |
160 | if (err) | 130 | if (err) |
161 | goto err_free_polldev; | 131 | goto err_free; |
162 | |||
163 | #ifdef CONFIG_RFKILL_INPUT_MODULE | ||
164 | /* B43 RF-kill isn't useful without the rfkill-input subsystem. | ||
165 | * Try to load the module. */ | ||
166 | err = request_module("rfkill-input"); | ||
167 | if (err) | ||
168 | b43warn(wl, "Failed to load the rfkill-input module. " | ||
169 | "The built-in radio LED will not work.\n"); | ||
170 | #endif /* CONFIG_RFKILL_INPUT */ | ||
171 | |||
172 | #if !defined(CONFIG_RFKILL_INPUT) && !defined(CONFIG_RFKILL_INPUT_MODULE) | ||
173 | b43warn(wl, "The rfkill-input subsystem is not available. " | ||
174 | "The built-in radio LED will not work.\n"); | ||
175 | #endif | ||
176 | |||
177 | err = input_register_polled_device(rfk->poll_dev); | ||
178 | if (err) | ||
179 | goto err_unreg_rfk; | ||
180 | 132 | ||
181 | rfk->registered = 1; | 133 | rfk->registered = 1; |
182 | 134 | ||
183 | return; | 135 | return; |
184 | err_unreg_rfk: | 136 | err_free: |
185 | rfkill_unregister(rfk->rfkill); | 137 | rfkill_destroy(rfk->rfkill); |
186 | err_free_polldev: | 138 | out_error: |
187 | input_free_polled_device(rfk->poll_dev); | ||
188 | rfk->poll_dev = NULL; | ||
189 | err_freed_rfk: | ||
190 | rfk->rfkill = NULL; | ||
191 | out_error: | ||
192 | rfk->registered = 0; | 139 | rfk->registered = 0; |
193 | b43warn(wl, "RF-kill button init failed\n"); | 140 | b43warn(wl, "RF-kill button init failed\n"); |
194 | } | 141 | } |
@@ -201,9 +148,7 @@ void b43_rfkill_exit(struct b43_wldev *dev) | |||
201 | return; | 148 | return; |
202 | rfk->registered = 0; | 149 | rfk->registered = 0; |
203 | 150 | ||
204 | input_unregister_polled_device(rfk->poll_dev); | ||
205 | rfkill_unregister(rfk->rfkill); | 151 | rfkill_unregister(rfk->rfkill); |
206 | input_free_polled_device(rfk->poll_dev); | 152 | rfkill_destroy(rfk->rfkill); |
207 | rfk->poll_dev = NULL; | ||
208 | rfk->rfkill = NULL; | 153 | rfk->rfkill = NULL; |
209 | } | 154 | } |
diff --git a/drivers/net/wireless/b43/rfkill.h b/drivers/net/wireless/b43/rfkill.h index adacf936d815..da497e01bbb1 100644 --- a/drivers/net/wireless/b43/rfkill.h +++ b/drivers/net/wireless/b43/rfkill.h | |||
@@ -7,14 +7,11 @@ struct b43_wldev; | |||
7 | #ifdef CONFIG_B43_RFKILL | 7 | #ifdef CONFIG_B43_RFKILL |
8 | 8 | ||
9 | #include <linux/rfkill.h> | 9 | #include <linux/rfkill.h> |
10 | #include <linux/input-polldev.h> | ||
11 | 10 | ||
12 | 11 | ||
13 | struct b43_rfkill { | 12 | struct b43_rfkill { |
14 | /* The RFKILL subsystem data structure */ | 13 | /* The RFKILL subsystem data structure */ |
15 | struct rfkill *rfkill; | 14 | struct rfkill *rfkill; |
16 | /* The poll device for the RFKILL input button */ | ||
17 | struct input_polled_dev *poll_dev; | ||
18 | /* Did initialization succeed? Used for freeing. */ | 15 | /* Did initialization succeed? Used for freeing. */ |
19 | bool registered; | 16 | bool registered; |
20 | /* The unique name of this rfkill switch */ | 17 | /* The unique name of this rfkill switch */ |
@@ -26,7 +23,7 @@ struct b43_rfkill { | |||
26 | void b43_rfkill_init(struct b43_wldev *dev); | 23 | void b43_rfkill_init(struct b43_wldev *dev); |
27 | void b43_rfkill_exit(struct b43_wldev *dev); | 24 | void b43_rfkill_exit(struct b43_wldev *dev); |
28 | 25 | ||
29 | char * b43_rfkill_led_name(struct b43_wldev *dev); | 26 | const char *b43_rfkill_led_name(struct b43_wldev *dev); |
30 | 27 | ||
31 | 28 | ||
32 | #else /* CONFIG_B43_RFKILL */ | 29 | #else /* CONFIG_B43_RFKILL */ |
diff --git a/drivers/net/wireless/b43legacy/Kconfig b/drivers/net/wireless/b43legacy/Kconfig index d4f628a74bbd..6893f439df70 100644 --- a/drivers/net/wireless/b43legacy/Kconfig +++ b/drivers/net/wireless/b43legacy/Kconfig | |||
@@ -47,7 +47,7 @@ config B43LEGACY_LEDS | |||
47 | # if it's possible. | 47 | # if it's possible. |
48 | config B43LEGACY_RFKILL | 48 | config B43LEGACY_RFKILL |
49 | bool | 49 | bool |
50 | depends on B43LEGACY && (RFKILL = y || RFKILL = B43LEGACY) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43LEGACY) | 50 | depends on B43LEGACY && (RFKILL = y || RFKILL = B43LEGACY) |
51 | default y | 51 | default y |
52 | 52 | ||
53 | # This config option automatically enables b43 HW-RNG support, | 53 | # This config option automatically enables b43 HW-RNG support, |
diff --git a/drivers/net/wireless/b43legacy/leds.c b/drivers/net/wireless/b43legacy/leds.c index 3ea55b18c700..538d3117594b 100644 --- a/drivers/net/wireless/b43legacy/leds.c +++ b/drivers/net/wireless/b43legacy/leds.c | |||
@@ -86,7 +86,8 @@ static void b43legacy_led_brightness_set(struct led_classdev *led_dev, | |||
86 | 86 | ||
87 | static int b43legacy_register_led(struct b43legacy_wldev *dev, | 87 | static int b43legacy_register_led(struct b43legacy_wldev *dev, |
88 | struct b43legacy_led *led, | 88 | struct b43legacy_led *led, |
89 | const char *name, char *default_trigger, | 89 | const char *name, |
90 | const char *default_trigger, | ||
90 | u8 led_index, bool activelow) | 91 | u8 led_index, bool activelow) |
91 | { | 92 | { |
92 | int err; | 93 | int err; |
diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c index 4b0c7d27a51f..c6230a64505a 100644 --- a/drivers/net/wireless/b43legacy/rfkill.c +++ b/drivers/net/wireless/b43legacy/rfkill.c | |||
@@ -45,12 +45,11 @@ static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) | |||
45 | } | 45 | } |
46 | 46 | ||
47 | /* The poll callback for the hardware button. */ | 47 | /* The poll callback for the hardware button. */ |
48 | static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev) | 48 | static void b43legacy_rfkill_poll(struct rfkill *rfkill, void *data) |
49 | { | 49 | { |
50 | struct b43legacy_wldev *dev = poll_dev->private; | 50 | struct b43legacy_wldev *dev = data; |
51 | struct b43legacy_wl *wl = dev->wl; | 51 | struct b43legacy_wl *wl = dev->wl; |
52 | bool enabled; | 52 | bool enabled; |
53 | bool report_change = 0; | ||
54 | 53 | ||
55 | mutex_lock(&wl->mutex); | 54 | mutex_lock(&wl->mutex); |
56 | if (unlikely(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)) { | 55 | if (unlikely(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)) { |
@@ -60,71 +59,64 @@ static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev) | |||
60 | enabled = b43legacy_is_hw_radio_enabled(dev); | 59 | enabled = b43legacy_is_hw_radio_enabled(dev); |
61 | if (unlikely(enabled != dev->radio_hw_enable)) { | 60 | if (unlikely(enabled != dev->radio_hw_enable)) { |
62 | dev->radio_hw_enable = enabled; | 61 | dev->radio_hw_enable = enabled; |
63 | report_change = 1; | ||
64 | b43legacyinfo(wl, "Radio hardware status changed to %s\n", | 62 | b43legacyinfo(wl, "Radio hardware status changed to %s\n", |
65 | enabled ? "ENABLED" : "DISABLED"); | 63 | enabled ? "ENABLED" : "DISABLED"); |
64 | enabled = !rfkill_set_hw_state(rfkill, !enabled); | ||
65 | if (enabled != dev->phy.radio_on) { | ||
66 | if (enabled) | ||
67 | b43legacy_radio_turn_on(dev); | ||
68 | else | ||
69 | b43legacy_radio_turn_off(dev, 0); | ||
70 | } | ||
66 | } | 71 | } |
67 | mutex_unlock(&wl->mutex); | 72 | mutex_unlock(&wl->mutex); |
68 | |||
69 | /* send the radio switch event to the system - note both a key press | ||
70 | * and a release are required */ | ||
71 | if (unlikely(report_change)) { | ||
72 | input_report_key(poll_dev->input, KEY_WLAN, 1); | ||
73 | input_report_key(poll_dev->input, KEY_WLAN, 0); | ||
74 | } | ||
75 | } | 73 | } |
76 | 74 | ||
77 | /* Called when the RFKILL toggled in software. | 75 | /* Called when the RFKILL toggled in software. |
78 | * This is called without locking. */ | 76 | * This is called without locking. */ |
79 | static int b43legacy_rfkill_soft_toggle(void *data, enum rfkill_state state) | 77 | static int b43legacy_rfkill_soft_set(void *data, bool blocked) |
80 | { | 78 | { |
81 | struct b43legacy_wldev *dev = data; | 79 | struct b43legacy_wldev *dev = data; |
82 | struct b43legacy_wl *wl = dev->wl; | 80 | struct b43legacy_wl *wl = dev->wl; |
83 | int err = -EBUSY; | 81 | int ret = -EINVAL; |
84 | 82 | ||
85 | if (!wl->rfkill.registered) | 83 | if (!wl->rfkill.registered) |
86 | return 0; | 84 | return -EINVAL; |
87 | 85 | ||
88 | mutex_lock(&wl->mutex); | 86 | mutex_lock(&wl->mutex); |
89 | if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) | 87 | if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) |
90 | goto out_unlock; | 88 | goto out_unlock; |
91 | err = 0; | 89 | |
92 | switch (state) { | 90 | if (!dev->radio_hw_enable) |
93 | case RFKILL_STATE_UNBLOCKED: | 91 | goto out_unlock; |
94 | if (!dev->radio_hw_enable) { | 92 | |
95 | /* No luck. We can't toggle the hardware RF-kill | 93 | if (!blocked != dev->phy.radio_on) { |
96 | * button from software. */ | 94 | if (!blocked) |
97 | err = -EBUSY; | ||
98 | goto out_unlock; | ||
99 | } | ||
100 | if (!dev->phy.radio_on) | ||
101 | b43legacy_radio_turn_on(dev); | 95 | b43legacy_radio_turn_on(dev); |
102 | break; | 96 | else |
103 | case RFKILL_STATE_SOFT_BLOCKED: | ||
104 | if (dev->phy.radio_on) | ||
105 | b43legacy_radio_turn_off(dev, 0); | 97 | b43legacy_radio_turn_off(dev, 0); |
106 | break; | ||
107 | default: | ||
108 | b43legacywarn(wl, "Received unexpected rfkill state %d.\n", | ||
109 | state); | ||
110 | break; | ||
111 | } | 98 | } |
99 | ret = 0; | ||
112 | 100 | ||
113 | out_unlock: | 101 | out_unlock: |
114 | mutex_unlock(&wl->mutex); | 102 | mutex_unlock(&wl->mutex); |
115 | 103 | return ret; | |
116 | return err; | ||
117 | } | 104 | } |
118 | 105 | ||
119 | char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) | 106 | const char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) |
120 | { | 107 | { |
121 | struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); | 108 | struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); |
122 | 109 | ||
123 | if (!rfk->registered) | 110 | if (!rfk->registered) |
124 | return NULL; | 111 | return NULL; |
125 | return rfkill_get_led_name(rfk->rfkill); | 112 | return rfkill_get_led_trigger_name(rfk->rfkill); |
126 | } | 113 | } |
127 | 114 | ||
115 | static const struct rfkill_ops b43legacy_rfkill_ops = { | ||
116 | .set_block = b43legacy_rfkill_soft_set, | ||
117 | .poll = b43legacy_rfkill_poll, | ||
118 | }; | ||
119 | |||
128 | void b43legacy_rfkill_init(struct b43legacy_wldev *dev) | 120 | void b43legacy_rfkill_init(struct b43legacy_wldev *dev) |
129 | { | 121 | { |
130 | struct b43legacy_wl *wl = dev->wl; | 122 | struct b43legacy_wl *wl = dev->wl; |
@@ -133,60 +125,25 @@ void b43legacy_rfkill_init(struct b43legacy_wldev *dev) | |||
133 | 125 | ||
134 | rfk->registered = 0; | 126 | rfk->registered = 0; |
135 | 127 | ||
136 | rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN); | ||
137 | if (!rfk->rfkill) | ||
138 | goto out_error; | ||
139 | snprintf(rfk->name, sizeof(rfk->name), | 128 | snprintf(rfk->name, sizeof(rfk->name), |
140 | "b43legacy-%s", wiphy_name(wl->hw->wiphy)); | 129 | "b43legacy-%s", wiphy_name(wl->hw->wiphy)); |
141 | rfk->rfkill->name = rfk->name; | 130 | rfk->rfkill = rfkill_alloc(rfk->name, |
142 | rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; | 131 | dev->dev->dev, |
143 | rfk->rfkill->data = dev; | 132 | RFKILL_TYPE_WLAN, |
144 | rfk->rfkill->toggle_radio = b43legacy_rfkill_soft_toggle; | 133 | &b43legacy_rfkill_ops, dev); |
145 | 134 | if (!rfk->rfkill) | |
146 | rfk->poll_dev = input_allocate_polled_device(); | 135 | goto out_error; |
147 | if (!rfk->poll_dev) { | ||
148 | rfkill_free(rfk->rfkill); | ||
149 | goto err_freed_rfk; | ||
150 | } | ||
151 | |||
152 | rfk->poll_dev->private = dev; | ||
153 | rfk->poll_dev->poll = b43legacy_rfkill_poll; | ||
154 | rfk->poll_dev->poll_interval = 1000; /* msecs */ | ||
155 | |||
156 | rfk->poll_dev->input->name = rfk->name; | ||
157 | rfk->poll_dev->input->id.bustype = BUS_HOST; | ||
158 | rfk->poll_dev->input->id.vendor = dev->dev->bus->boardinfo.vendor; | ||
159 | rfk->poll_dev->input->evbit[0] = BIT(EV_KEY); | ||
160 | set_bit(KEY_WLAN, rfk->poll_dev->input->keybit); | ||
161 | 136 | ||
162 | err = rfkill_register(rfk->rfkill); | 137 | err = rfkill_register(rfk->rfkill); |
163 | if (err) | 138 | if (err) |
164 | goto err_free_polldev; | 139 | goto err_free; |
165 | |||
166 | #ifdef CONFIG_RFKILL_INPUT_MODULE | ||
167 | /* B43legacy RF-kill isn't useful without the rfkill-input subsystem. | ||
168 | * Try to load the module. */ | ||
169 | err = request_module("rfkill-input"); | ||
170 | if (err) | ||
171 | b43legacywarn(wl, "Failed to load the rfkill-input module." | ||
172 | "The built-in radio LED will not work.\n"); | ||
173 | #endif /* CONFIG_RFKILL_INPUT */ | ||
174 | |||
175 | err = input_register_polled_device(rfk->poll_dev); | ||
176 | if (err) | ||
177 | goto err_unreg_rfk; | ||
178 | 140 | ||
179 | rfk->registered = 1; | 141 | rfk->registered = 1; |
180 | 142 | ||
181 | return; | 143 | return; |
182 | err_unreg_rfk: | 144 | err_free: |
183 | rfkill_unregister(rfk->rfkill); | 145 | rfkill_destroy(rfk->rfkill); |
184 | err_free_polldev: | 146 | out_error: |
185 | input_free_polled_device(rfk->poll_dev); | ||
186 | rfk->poll_dev = NULL; | ||
187 | err_freed_rfk: | ||
188 | rfk->rfkill = NULL; | ||
189 | out_error: | ||
190 | rfk->registered = 0; | 147 | rfk->registered = 0; |
191 | b43legacywarn(wl, "RF-kill button init failed\n"); | 148 | b43legacywarn(wl, "RF-kill button init failed\n"); |
192 | } | 149 | } |
@@ -199,10 +156,8 @@ void b43legacy_rfkill_exit(struct b43legacy_wldev *dev) | |||
199 | return; | 156 | return; |
200 | rfk->registered = 0; | 157 | rfk->registered = 0; |
201 | 158 | ||
202 | input_unregister_polled_device(rfk->poll_dev); | ||
203 | rfkill_unregister(rfk->rfkill); | 159 | rfkill_unregister(rfk->rfkill); |
204 | input_free_polled_device(rfk->poll_dev); | 160 | rfkill_destroy(rfk->rfkill); |
205 | rfk->poll_dev = NULL; | ||
206 | rfk->rfkill = NULL; | 161 | rfk->rfkill = NULL; |
207 | } | 162 | } |
208 | 163 | ||
diff --git a/drivers/net/wireless/b43legacy/rfkill.h b/drivers/net/wireless/b43legacy/rfkill.h index 11150a8032f0..adffc503a6a1 100644 --- a/drivers/net/wireless/b43legacy/rfkill.h +++ b/drivers/net/wireless/b43legacy/rfkill.h | |||
@@ -6,16 +6,12 @@ struct b43legacy_wldev; | |||
6 | #ifdef CONFIG_B43LEGACY_RFKILL | 6 | #ifdef CONFIG_B43LEGACY_RFKILL |
7 | 7 | ||
8 | #include <linux/rfkill.h> | 8 | #include <linux/rfkill.h> |
9 | #include <linux/workqueue.h> | ||
10 | #include <linux/input-polldev.h> | ||
11 | 9 | ||
12 | 10 | ||
13 | 11 | ||
14 | struct b43legacy_rfkill { | 12 | struct b43legacy_rfkill { |
15 | /* The RFKILL subsystem data structure */ | 13 | /* The RFKILL subsystem data structure */ |
16 | struct rfkill *rfkill; | 14 | struct rfkill *rfkill; |
17 | /* The poll device for the RFKILL input button */ | ||
18 | struct input_polled_dev *poll_dev; | ||
19 | /* Did initialization succeed? Used for freeing. */ | 15 | /* Did initialization succeed? Used for freeing. */ |
20 | bool registered; | 16 | bool registered; |
21 | /* The unique name of this rfkill switch */ | 17 | /* The unique name of this rfkill switch */ |
@@ -27,7 +23,7 @@ struct b43legacy_rfkill { | |||
27 | void b43legacy_rfkill_init(struct b43legacy_wldev *dev); | 23 | void b43legacy_rfkill_init(struct b43legacy_wldev *dev); |
28 | void b43legacy_rfkill_exit(struct b43legacy_wldev *dev); | 24 | void b43legacy_rfkill_exit(struct b43legacy_wldev *dev); |
29 | 25 | ||
30 | char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev); | 26 | const char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev); |
31 | 27 | ||
32 | 28 | ||
33 | #else /* CONFIG_B43LEGACY_RFKILL */ | 29 | #else /* CONFIG_B43LEGACY_RFKILL */ |
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 8304f6406a17..6fe259fcfb8f 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig | |||
@@ -5,15 +5,14 @@ config IWLWIFI | |||
5 | select FW_LOADER | 5 | select FW_LOADER |
6 | select MAC80211_LEDS if IWLWIFI_LEDS | 6 | select MAC80211_LEDS if IWLWIFI_LEDS |
7 | select LEDS_CLASS if IWLWIFI_LEDS | 7 | select LEDS_CLASS if IWLWIFI_LEDS |
8 | select RFKILL if IWLWIFI_RFKILL | ||
9 | 8 | ||
10 | config IWLWIFI_LEDS | 9 | config IWLWIFI_LEDS |
11 | bool "Enable LED support in iwlagn and iwl3945 drivers" | 10 | bool "Enable LED support in iwlagn and iwl3945 drivers" |
12 | depends on IWLWIFI | 11 | depends on IWLWIFI |
13 | 12 | ||
14 | config IWLWIFI_RFKILL | 13 | config IWLWIFI_RFKILL |
15 | bool "Enable RF kill support in iwlagn and iwl3945 drivers" | 14 | def_bool y |
16 | depends on IWLWIFI | 15 | depends on IWLWIFI && RFKILL |
17 | 16 | ||
18 | config IWLWIFI_SPECTRUM_MEASUREMENT | 17 | config IWLWIFI_SPECTRUM_MEASUREMENT |
19 | bool "Enable Spectrum Measurement in iwlagn driver" | 18 | bool "Enable Spectrum Measurement in iwlagn driver" |
diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c index 65605ad44e4b..13149936fd26 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.c +++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.c | |||
@@ -36,42 +36,37 @@ | |||
36 | #include "iwl-core.h" | 36 | #include "iwl-core.h" |
37 | 37 | ||
38 | /* software rf-kill from user */ | 38 | /* software rf-kill from user */ |
39 | static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state) | 39 | static int iwl_rfkill_soft_rf_kill(void *data, bool blocked) |
40 | { | 40 | { |
41 | struct iwl_priv *priv = data; | 41 | struct iwl_priv *priv = data; |
42 | int err = 0; | ||
43 | 42 | ||
44 | if (!priv->rfkill) | 43 | if (!priv->rfkill) |
45 | return 0; | 44 | return -EINVAL; |
46 | 45 | ||
47 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 46 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
48 | return 0; | 47 | return 0; |
49 | 48 | ||
50 | IWL_DEBUG_RF_KILL(priv, "we received soft RFKILL set to state %d\n", state); | 49 | IWL_DEBUG_RF_KILL(priv, "received soft RFKILL: block=%d\n", blocked); |
50 | |||
51 | mutex_lock(&priv->mutex); | 51 | mutex_lock(&priv->mutex); |
52 | 52 | ||
53 | switch (state) { | 53 | if (iwl_is_rfkill_hw(priv)) |
54 | case RFKILL_STATE_UNBLOCKED: | 54 | goto out_unlock; |
55 | if (iwl_is_rfkill_hw(priv)) { | 55 | |
56 | err = -EBUSY; | 56 | if (!blocked) |
57 | goto out_unlock; | ||
58 | } | ||
59 | iwl_radio_kill_sw_enable_radio(priv); | 57 | iwl_radio_kill_sw_enable_radio(priv); |
60 | break; | 58 | else |
61 | case RFKILL_STATE_SOFT_BLOCKED: | ||
62 | iwl_radio_kill_sw_disable_radio(priv); | 59 | iwl_radio_kill_sw_disable_radio(priv); |
63 | break; | 60 | |
64 | default: | ||
65 | IWL_WARN(priv, "we received unexpected RFKILL state %d\n", | ||
66 | state); | ||
67 | break; | ||
68 | } | ||
69 | out_unlock: | 61 | out_unlock: |
70 | mutex_unlock(&priv->mutex); | 62 | mutex_unlock(&priv->mutex); |
71 | 63 | return 0; | |
72 | return err; | ||
73 | } | 64 | } |
74 | 65 | ||
66 | static const struct rfkill_ops iwl_rfkill_ops = { | ||
67 | .set_block = iwl_rfkill_soft_rf_kill, | ||
68 | }; | ||
69 | |||
75 | int iwl_rfkill_init(struct iwl_priv *priv) | 70 | int iwl_rfkill_init(struct iwl_priv *priv) |
76 | { | 71 | { |
77 | struct device *device = wiphy_dev(priv->hw->wiphy); | 72 | struct device *device = wiphy_dev(priv->hw->wiphy); |
@@ -80,21 +75,16 @@ int iwl_rfkill_init(struct iwl_priv *priv) | |||
80 | BUG_ON(device == NULL); | 75 | BUG_ON(device == NULL); |
81 | 76 | ||
82 | IWL_DEBUG_RF_KILL(priv, "Initializing RFKILL.\n"); | 77 | IWL_DEBUG_RF_KILL(priv, "Initializing RFKILL.\n"); |
83 | priv->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN); | 78 | priv->rfkill = rfkill_alloc(priv->cfg->name, |
79 | device, | ||
80 | RFKILL_TYPE_WLAN, | ||
81 | &iwl_rfkill_ops, priv); | ||
84 | if (!priv->rfkill) { | 82 | if (!priv->rfkill) { |
85 | IWL_ERR(priv, "Unable to allocate RFKILL device.\n"); | 83 | IWL_ERR(priv, "Unable to allocate RFKILL device.\n"); |
86 | ret = -ENOMEM; | 84 | ret = -ENOMEM; |
87 | goto error; | 85 | goto error; |
88 | } | 86 | } |
89 | 87 | ||
90 | priv->rfkill->name = priv->cfg->name; | ||
91 | priv->rfkill->data = priv; | ||
92 | priv->rfkill->state = RFKILL_STATE_UNBLOCKED; | ||
93 | priv->rfkill->toggle_radio = iwl_rfkill_soft_rf_kill; | ||
94 | |||
95 | priv->rfkill->dev.class->suspend = NULL; | ||
96 | priv->rfkill->dev.class->resume = NULL; | ||
97 | |||
98 | ret = rfkill_register(priv->rfkill); | 88 | ret = rfkill_register(priv->rfkill); |
99 | if (ret) { | 89 | if (ret) { |
100 | IWL_ERR(priv, "Unable to register RFKILL: %d\n", ret); | 90 | IWL_ERR(priv, "Unable to register RFKILL: %d\n", ret); |
@@ -102,11 +92,10 @@ int iwl_rfkill_init(struct iwl_priv *priv) | |||
102 | } | 92 | } |
103 | 93 | ||
104 | IWL_DEBUG_RF_KILL(priv, "RFKILL initialization complete.\n"); | 94 | IWL_DEBUG_RF_KILL(priv, "RFKILL initialization complete.\n"); |
105 | return ret; | 95 | return 0; |
106 | 96 | ||
107 | free_rfkill: | 97 | free_rfkill: |
108 | if (priv->rfkill != NULL) | 98 | rfkill_destroy(priv->rfkill); |
109 | rfkill_free(priv->rfkill); | ||
110 | priv->rfkill = NULL; | 99 | priv->rfkill = NULL; |
111 | 100 | ||
112 | error: | 101 | error: |
@@ -118,8 +107,10 @@ EXPORT_SYMBOL(iwl_rfkill_init); | |||
118 | void iwl_rfkill_unregister(struct iwl_priv *priv) | 107 | void iwl_rfkill_unregister(struct iwl_priv *priv) |
119 | { | 108 | { |
120 | 109 | ||
121 | if (priv->rfkill) | 110 | if (priv->rfkill) { |
122 | rfkill_unregister(priv->rfkill); | 111 | rfkill_unregister(priv->rfkill); |
112 | rfkill_destroy(priv->rfkill); | ||
113 | } | ||
123 | 114 | ||
124 | priv->rfkill = NULL; | 115 | priv->rfkill = NULL; |
125 | } | 116 | } |
@@ -131,14 +122,10 @@ void iwl_rfkill_set_hw_state(struct iwl_priv *priv) | |||
131 | if (!priv->rfkill) | 122 | if (!priv->rfkill) |
132 | return; | 123 | return; |
133 | 124 | ||
134 | if (iwl_is_rfkill_hw(priv)) { | 125 | if (rfkill_set_hw_state(priv->rfkill, |
135 | rfkill_force_state(priv->rfkill, RFKILL_STATE_HARD_BLOCKED); | 126 | !!iwl_is_rfkill_hw(priv))) |
136 | return; | 127 | iwl_radio_kill_sw_disable_radio(priv); |
137 | } | ||
138 | |||
139 | if (!iwl_is_rfkill_sw(priv)) | ||
140 | rfkill_force_state(priv->rfkill, RFKILL_STATE_UNBLOCKED); | ||
141 | else | 128 | else |
142 | rfkill_force_state(priv->rfkill, RFKILL_STATE_SOFT_BLOCKED); | 129 | iwl_radio_kill_sw_enable_radio(priv); |
143 | } | 130 | } |
144 | EXPORT_SYMBOL(iwl_rfkill_set_hw_state); | 131 | EXPORT_SYMBOL(iwl_rfkill_set_hw_state); |
diff --git a/drivers/net/wireless/iwmc3200wifi/rfkill.c b/drivers/net/wireless/iwmc3200wifi/rfkill.c index 4ca8b495f82d..8ee2c3c09a02 100644 --- a/drivers/net/wireless/iwmc3200wifi/rfkill.c +++ b/drivers/net/wireless/iwmc3200wifi/rfkill.c | |||
@@ -25,47 +25,42 @@ | |||
25 | 25 | ||
26 | #include "iwm.h" | 26 | #include "iwm.h" |
27 | 27 | ||
28 | static int iwm_rfkill_soft_toggle(void *data, enum rfkill_state state) | 28 | static int iwm_rfkill_set_block(void *data, bool blocked) |
29 | { | 29 | { |
30 | struct iwm_priv *iwm = data; | 30 | struct iwm_priv *iwm = data; |
31 | 31 | ||
32 | switch (state) { | 32 | if (!blocked) { |
33 | case RFKILL_STATE_UNBLOCKED: | ||
34 | if (test_bit(IWM_RADIO_RFKILL_HW, &iwm->radio)) | 33 | if (test_bit(IWM_RADIO_RFKILL_HW, &iwm->radio)) |
35 | return -EBUSY; | 34 | return -EBUSY; |
36 | 35 | ||
37 | if (test_and_clear_bit(IWM_RADIO_RFKILL_SW, &iwm->radio) && | 36 | if (test_and_clear_bit(IWM_RADIO_RFKILL_SW, &iwm->radio) && |
38 | (iwm_to_ndev(iwm)->flags & IFF_UP)) | 37 | (iwm_to_ndev(iwm)->flags & IFF_UP)) |
39 | iwm_up(iwm); | 38 | return iwm_up(iwm); |
40 | 39 | } else { | |
41 | break; | ||
42 | case RFKILL_STATE_SOFT_BLOCKED: | ||
43 | if (!test_and_set_bit(IWM_RADIO_RFKILL_SW, &iwm->radio)) | 40 | if (!test_and_set_bit(IWM_RADIO_RFKILL_SW, &iwm->radio)) |
44 | iwm_down(iwm); | 41 | return iwm_down(iwm); |
45 | |||
46 | break; | ||
47 | default: | ||
48 | break; | ||
49 | } | 42 | } |
50 | 43 | ||
51 | return 0; | 44 | return 0; |
52 | } | 45 | } |
53 | 46 | ||
47 | static const struct rfkill_ops iwm_rfkill_ops = { | ||
48 | .set_block = iwm_rfkill_set_block, | ||
49 | }; | ||
50 | |||
54 | int iwm_rfkill_init(struct iwm_priv *iwm) | 51 | int iwm_rfkill_init(struct iwm_priv *iwm) |
55 | { | 52 | { |
56 | int ret; | 53 | int ret; |
57 | 54 | ||
58 | iwm->rfkill = rfkill_allocate(iwm_to_dev(iwm), RFKILL_TYPE_WLAN); | 55 | iwm->rfkill = rfkill_alloc(KBUILD_MODNAME, |
56 | iwm_to_dev(iwm), | ||
57 | RFKILL_TYPE_WLAN, | ||
58 | &iwm_rfkill_ops, iwm); | ||
59 | if (!iwm->rfkill) { | 59 | if (!iwm->rfkill) { |
60 | IWM_ERR(iwm, "Unable to allocate rfkill device\n"); | 60 | IWM_ERR(iwm, "Unable to allocate rfkill device\n"); |
61 | return -ENOMEM; | 61 | return -ENOMEM; |
62 | } | 62 | } |
63 | 63 | ||
64 | iwm->rfkill->name = KBUILD_MODNAME; | ||
65 | iwm->rfkill->data = iwm; | ||
66 | iwm->rfkill->state = RFKILL_STATE_UNBLOCKED; | ||
67 | iwm->rfkill->toggle_radio = iwm_rfkill_soft_toggle; | ||
68 | |||
69 | ret = rfkill_register(iwm->rfkill); | 64 | ret = rfkill_register(iwm->rfkill); |
70 | if (ret) { | 65 | if (ret) { |
71 | IWM_ERR(iwm, "Failed to register rfkill device\n"); | 66 | IWM_ERR(iwm, "Failed to register rfkill device\n"); |
@@ -74,15 +69,15 @@ int iwm_rfkill_init(struct iwm_priv *iwm) | |||
74 | 69 | ||
75 | return 0; | 70 | return 0; |
76 | fail: | 71 | fail: |
77 | rfkill_free(iwm->rfkill); | 72 | rfkill_destroy(iwm->rfkill); |
78 | return ret; | 73 | return ret; |
79 | } | 74 | } |
80 | 75 | ||
81 | void iwm_rfkill_exit(struct iwm_priv *iwm) | 76 | void iwm_rfkill_exit(struct iwm_priv *iwm) |
82 | { | 77 | { |
83 | if (iwm->rfkill) | 78 | if (iwm->rfkill) { |
84 | rfkill_unregister(iwm->rfkill); | 79 | rfkill_unregister(iwm->rfkill); |
85 | 80 | rfkill_destroy(iwm->rfkill); | |
86 | rfkill_free(iwm->rfkill); | 81 | } |
87 | iwm->rfkill = NULL; | 82 | iwm->rfkill = NULL; |
88 | } | 83 | } |
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 284ebaca6e45..c682ac536415 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig | |||
@@ -21,7 +21,7 @@ config ACER_WMI | |||
21 | depends on NEW_LEDS | 21 | depends on NEW_LEDS |
22 | depends on BACKLIGHT_CLASS_DEVICE | 22 | depends on BACKLIGHT_CLASS_DEVICE |
23 | depends on SERIO_I8042 | 23 | depends on SERIO_I8042 |
24 | depends on RFKILL | 24 | depends on RFKILL || RFKILL = n |
25 | select ACPI_WMI | 25 | select ACPI_WMI |
26 | ---help--- | 26 | ---help--- |
27 | This is a driver for newer Acer (and Wistron) laptops. It adds | 27 | This is a driver for newer Acer (and Wistron) laptops. It adds |
@@ -60,7 +60,7 @@ config DELL_LAPTOP | |||
60 | depends on DCDBAS | 60 | depends on DCDBAS |
61 | depends on EXPERIMENTAL | 61 | depends on EXPERIMENTAL |
62 | depends on BACKLIGHT_CLASS_DEVICE | 62 | depends on BACKLIGHT_CLASS_DEVICE |
63 | depends on RFKILL | 63 | depends on RFKILL || RFKILL = n |
64 | depends on POWER_SUPPLY | 64 | depends on POWER_SUPPLY |
65 | default n | 65 | default n |
66 | ---help--- | 66 | ---help--- |
@@ -117,7 +117,7 @@ config HP_WMI | |||
117 | tristate "HP WMI extras" | 117 | tristate "HP WMI extras" |
118 | depends on ACPI_WMI | 118 | depends on ACPI_WMI |
119 | depends on INPUT | 119 | depends on INPUT |
120 | depends on RFKILL | 120 | depends on RFKILL || RFKILL = n |
121 | help | 121 | help |
122 | Say Y here if you want to support WMI-based hotkeys on HP laptops and | 122 | Say Y here if you want to support WMI-based hotkeys on HP laptops and |
123 | to read data from WMI such as docking or ambient light sensor state. | 123 | to read data from WMI such as docking or ambient light sensor state. |
@@ -196,14 +196,13 @@ config THINKPAD_ACPI | |||
196 | tristate "ThinkPad ACPI Laptop Extras" | 196 | tristate "ThinkPad ACPI Laptop Extras" |
197 | depends on ACPI | 197 | depends on ACPI |
198 | depends on INPUT | 198 | depends on INPUT |
199 | depends on RFKILL || RFKILL = n | ||
199 | select BACKLIGHT_LCD_SUPPORT | 200 | select BACKLIGHT_LCD_SUPPORT |
200 | select BACKLIGHT_CLASS_DEVICE | 201 | select BACKLIGHT_CLASS_DEVICE |
201 | select HWMON | 202 | select HWMON |
202 | select NVRAM | 203 | select NVRAM |
203 | select NEW_LEDS | 204 | select NEW_LEDS |
204 | select LEDS_CLASS | 205 | select LEDS_CLASS |
205 | select NET | ||
206 | select RFKILL | ||
207 | ---help--- | 206 | ---help--- |
208 | This is a driver for the IBM and Lenovo ThinkPad laptops. It adds | 207 | This is a driver for the IBM and Lenovo ThinkPad laptops. It adds |
209 | support for Fn-Fx key combinations, Bluetooth control, video | 208 | support for Fn-Fx key combinations, Bluetooth control, video |
@@ -338,9 +337,9 @@ config EEEPC_LAPTOP | |||
338 | depends on ACPI | 337 | depends on ACPI |
339 | depends on INPUT | 338 | depends on INPUT |
340 | depends on EXPERIMENTAL | 339 | depends on EXPERIMENTAL |
340 | depends on RFKILL || RFKILL = n | ||
341 | select BACKLIGHT_CLASS_DEVICE | 341 | select BACKLIGHT_CLASS_DEVICE |
342 | select HWMON | 342 | select HWMON |
343 | select RFKILL | ||
344 | ---help--- | 343 | ---help--- |
345 | This driver supports the Fn-Fx keys on Eee PC laptops. | 344 | This driver supports the Fn-Fx keys on Eee PC laptops. |
346 | It also adds the ability to switch camera/wlan on/off. | 345 | It also adds the ability to switch camera/wlan on/off. |
@@ -405,9 +404,8 @@ config ACPI_TOSHIBA | |||
405 | tristate "Toshiba Laptop Extras" | 404 | tristate "Toshiba Laptop Extras" |
406 | depends on ACPI | 405 | depends on ACPI |
407 | depends on INPUT | 406 | depends on INPUT |
407 | depends on RFKILL || RFKILL = n | ||
408 | select INPUT_POLLDEV | 408 | select INPUT_POLLDEV |
409 | select NET | ||
410 | select RFKILL | ||
411 | select BACKLIGHT_CLASS_DEVICE | 409 | select BACKLIGHT_CLASS_DEVICE |
412 | ---help--- | 410 | ---help--- |
413 | This driver adds support for access to certain system settings | 411 | This driver adds support for access to certain system settings |
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 62d02b3c998e..b618fa51db2d 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c | |||
@@ -958,58 +958,50 @@ static void acer_rfkill_update(struct work_struct *ignored) | |||
958 | 958 | ||
959 | status = get_u32(&state, ACER_CAP_WIRELESS); | 959 | status = get_u32(&state, ACER_CAP_WIRELESS); |
960 | if (ACPI_SUCCESS(status)) | 960 | if (ACPI_SUCCESS(status)) |
961 | rfkill_force_state(wireless_rfkill, state ? | 961 | rfkill_set_sw_state(wireless_rfkill, !!state); |
962 | RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED); | ||
963 | 962 | ||
964 | if (has_cap(ACER_CAP_BLUETOOTH)) { | 963 | if (has_cap(ACER_CAP_BLUETOOTH)) { |
965 | status = get_u32(&state, ACER_CAP_BLUETOOTH); | 964 | status = get_u32(&state, ACER_CAP_BLUETOOTH); |
966 | if (ACPI_SUCCESS(status)) | 965 | if (ACPI_SUCCESS(status)) |
967 | rfkill_force_state(bluetooth_rfkill, state ? | 966 | rfkill_set_sw_state(bluetooth_rfkill, !!state); |
968 | RFKILL_STATE_UNBLOCKED : | ||
969 | RFKILL_STATE_SOFT_BLOCKED); | ||
970 | } | 967 | } |
971 | 968 | ||
972 | schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); | 969 | schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); |
973 | } | 970 | } |
974 | 971 | ||
975 | static int acer_rfkill_set(void *data, enum rfkill_state state) | 972 | static int acer_rfkill_set(void *data, bool blocked) |
976 | { | 973 | { |
977 | acpi_status status; | 974 | acpi_status status; |
978 | u32 *cap = data; | 975 | u32 cap = (unsigned long)data; |
979 | status = set_u32((u32) (state == RFKILL_STATE_UNBLOCKED), *cap); | 976 | status = set_u32(!!blocked, cap); |
980 | if (ACPI_FAILURE(status)) | 977 | if (ACPI_FAILURE(status)) |
981 | return -ENODEV; | 978 | return -ENODEV; |
982 | return 0; | 979 | return 0; |
983 | } | 980 | } |
984 | 981 | ||
985 | static struct rfkill * acer_rfkill_register(struct device *dev, | 982 | static const struct rfkill_ops acer_rfkill_ops = { |
986 | enum rfkill_type type, char *name, u32 cap) | 983 | .set_block = acer_rfkill_set, |
984 | }; | ||
985 | |||
986 | static struct rfkill *acer_rfkill_register(struct device *dev, | ||
987 | enum rfkill_type type, | ||
988 | char *name, u32 cap) | ||
987 | { | 989 | { |
988 | int err; | 990 | int err; |
989 | u32 state; | 991 | u32 state; |
990 | u32 *data; | ||
991 | struct rfkill *rfkill_dev; | 992 | struct rfkill *rfkill_dev; |
992 | 993 | ||
993 | rfkill_dev = rfkill_allocate(dev, type); | 994 | rfkill_dev = rfkill_alloc(name, dev, type, |
995 | &acer_rfkill_ops, | ||
996 | (void *)(unsigned long)cap); | ||
994 | if (!rfkill_dev) | 997 | if (!rfkill_dev) |
995 | return ERR_PTR(-ENOMEM); | 998 | return ERR_PTR(-ENOMEM); |
996 | rfkill_dev->name = name; | ||
997 | get_u32(&state, cap); | 999 | get_u32(&state, cap); |
998 | rfkill_dev->state = state ? RFKILL_STATE_UNBLOCKED : | 1000 | rfkill_set_sw_state(rfkill_dev, !state); |
999 | RFKILL_STATE_SOFT_BLOCKED; | ||
1000 | data = kzalloc(sizeof(u32), GFP_KERNEL); | ||
1001 | if (!data) { | ||
1002 | rfkill_free(rfkill_dev); | ||
1003 | return ERR_PTR(-ENOMEM); | ||
1004 | } | ||
1005 | *data = cap; | ||
1006 | rfkill_dev->data = data; | ||
1007 | rfkill_dev->toggle_radio = acer_rfkill_set; | ||
1008 | 1001 | ||
1009 | err = rfkill_register(rfkill_dev); | 1002 | err = rfkill_register(rfkill_dev); |
1010 | if (err) { | 1003 | if (err) { |
1011 | kfree(rfkill_dev->data); | 1004 | rfkill_destroy(rfkill_dev); |
1012 | rfkill_free(rfkill_dev); | ||
1013 | return ERR_PTR(err); | 1005 | return ERR_PTR(err); |
1014 | } | 1006 | } |
1015 | return rfkill_dev; | 1007 | return rfkill_dev; |
@@ -1027,8 +1019,8 @@ static int acer_rfkill_init(struct device *dev) | |||
1027 | RFKILL_TYPE_BLUETOOTH, "acer-bluetooth", | 1019 | RFKILL_TYPE_BLUETOOTH, "acer-bluetooth", |
1028 | ACER_CAP_BLUETOOTH); | 1020 | ACER_CAP_BLUETOOTH); |
1029 | if (IS_ERR(bluetooth_rfkill)) { | 1021 | if (IS_ERR(bluetooth_rfkill)) { |
1030 | kfree(wireless_rfkill->data); | ||
1031 | rfkill_unregister(wireless_rfkill); | 1022 | rfkill_unregister(wireless_rfkill); |
1023 | rfkill_destroy(wireless_rfkill); | ||
1032 | return PTR_ERR(bluetooth_rfkill); | 1024 | return PTR_ERR(bluetooth_rfkill); |
1033 | } | 1025 | } |
1034 | } | 1026 | } |
@@ -1041,11 +1033,13 @@ static int acer_rfkill_init(struct device *dev) | |||
1041 | static void acer_rfkill_exit(void) | 1033 | static void acer_rfkill_exit(void) |
1042 | { | 1034 | { |
1043 | cancel_delayed_work_sync(&acer_rfkill_work); | 1035 | cancel_delayed_work_sync(&acer_rfkill_work); |
1044 | kfree(wireless_rfkill->data); | 1036 | |
1045 | rfkill_unregister(wireless_rfkill); | 1037 | rfkill_unregister(wireless_rfkill); |
1038 | rfkill_destroy(wireless_rfkill); | ||
1039 | |||
1046 | if (has_cap(ACER_CAP_BLUETOOTH)) { | 1040 | if (has_cap(ACER_CAP_BLUETOOTH)) { |
1047 | kfree(bluetooth_rfkill->data); | ||
1048 | rfkill_unregister(bluetooth_rfkill); | 1041 | rfkill_unregister(bluetooth_rfkill); |
1042 | rfkill_destroy(bluetooth_rfkill); | ||
1049 | } | 1043 | } |
1050 | return; | 1044 | return; |
1051 | } | 1045 | } |
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index af9f43021172..2faf0e14f05a 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c | |||
@@ -174,10 +174,11 @@ dell_send_request(struct calling_interface_buffer *buffer, int class, | |||
174 | result[3]: NVRAM format version number | 174 | result[3]: NVRAM format version number |
175 | */ | 175 | */ |
176 | 176 | ||
177 | static int dell_rfkill_set(int radio, enum rfkill_state state) | 177 | static int dell_rfkill_set(void *data, bool blocked) |
178 | { | 178 | { |
179 | struct calling_interface_buffer buffer; | 179 | struct calling_interface_buffer buffer; |
180 | int disable = (state == RFKILL_STATE_UNBLOCKED) ? 0 : 1; | 180 | int disable = blocked ? 0 : 1; |
181 | unsigned long radio = (unsigned long)data; | ||
181 | 182 | ||
182 | memset(&buffer, 0, sizeof(struct calling_interface_buffer)); | 183 | memset(&buffer, 0, sizeof(struct calling_interface_buffer)); |
183 | buffer.input[0] = (1 | (radio<<8) | (disable << 16)); | 184 | buffer.input[0] = (1 | (radio<<8) | (disable << 16)); |
@@ -186,56 +187,24 @@ static int dell_rfkill_set(int radio, enum rfkill_state state) | |||
186 | return 0; | 187 | return 0; |
187 | } | 188 | } |
188 | 189 | ||
189 | static int dell_wifi_set(void *data, enum rfkill_state state) | 190 | static void dell_rfkill_query(struct rfkill *rfkill, void *data) |
190 | { | ||
191 | return dell_rfkill_set(1, state); | ||
192 | } | ||
193 | |||
194 | static int dell_bluetooth_set(void *data, enum rfkill_state state) | ||
195 | { | ||
196 | return dell_rfkill_set(2, state); | ||
197 | } | ||
198 | |||
199 | static int dell_wwan_set(void *data, enum rfkill_state state) | ||
200 | { | ||
201 | return dell_rfkill_set(3, state); | ||
202 | } | ||
203 | |||
204 | static int dell_rfkill_get(int bit, enum rfkill_state *state) | ||
205 | { | 191 | { |
206 | struct calling_interface_buffer buffer; | 192 | struct calling_interface_buffer buffer; |
207 | int status; | 193 | int status; |
208 | int new_state = RFKILL_STATE_HARD_BLOCKED; | 194 | int bit = (unsigned long)data + 16; |
209 | 195 | ||
210 | memset(&buffer, 0, sizeof(struct calling_interface_buffer)); | 196 | memset(&buffer, 0, sizeof(struct calling_interface_buffer)); |
211 | dell_send_request(&buffer, 17, 11); | 197 | dell_send_request(&buffer, 17, 11); |
212 | status = buffer.output[1]; | 198 | status = buffer.output[1]; |
213 | 199 | ||
214 | if (status & (1<<16)) | 200 | if (status & BIT(bit)) |
215 | new_state = RFKILL_STATE_SOFT_BLOCKED; | 201 | rfkill_set_hw_state(rfkill, !!(status & BIT(16))); |
216 | |||
217 | if (status & (1<<bit)) | ||
218 | *state = new_state; | ||
219 | else | ||
220 | *state = RFKILL_STATE_UNBLOCKED; | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static int dell_wifi_get(void *data, enum rfkill_state *state) | ||
226 | { | ||
227 | return dell_rfkill_get(17, state); | ||
228 | } | ||
229 | |||
230 | static int dell_bluetooth_get(void *data, enum rfkill_state *state) | ||
231 | { | ||
232 | return dell_rfkill_get(18, state); | ||
233 | } | 202 | } |
234 | 203 | ||
235 | static int dell_wwan_get(void *data, enum rfkill_state *state) | 204 | static const struct rfkill_ops dell_rfkill_ops = { |
236 | { | 205 | .set_block = dell_rfkill_set, |
237 | return dell_rfkill_get(19, state); | 206 | .query = dell_rfkill_query, |
238 | } | 207 | }; |
239 | 208 | ||
240 | static int dell_setup_rfkill(void) | 209 | static int dell_setup_rfkill(void) |
241 | { | 210 | { |
@@ -248,36 +217,37 @@ static int dell_setup_rfkill(void) | |||
248 | status = buffer.output[1]; | 217 | status = buffer.output[1]; |
249 | 218 | ||
250 | if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) { | 219 | if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) { |
251 | wifi_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_WLAN); | 220 | wifi_rfkill = rfkill_alloc("dell-wifi", NULL, RFKILL_TYPE_WLAN, |
252 | if (!wifi_rfkill) | 221 | &dell_rfkill_ops, (void *) 1); |
222 | if (!wifi_rfkill) { | ||
223 | ret = -ENOMEM; | ||
253 | goto err_wifi; | 224 | goto err_wifi; |
254 | wifi_rfkill->name = "dell-wifi"; | 225 | } |
255 | wifi_rfkill->toggle_radio = dell_wifi_set; | ||
256 | wifi_rfkill->get_state = dell_wifi_get; | ||
257 | ret = rfkill_register(wifi_rfkill); | 226 | ret = rfkill_register(wifi_rfkill); |
258 | if (ret) | 227 | if (ret) |
259 | goto err_wifi; | 228 | goto err_wifi; |
260 | } | 229 | } |
261 | 230 | ||
262 | if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) { | 231 | if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) { |
263 | bluetooth_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_BLUETOOTH); | 232 | bluetooth_rfkill = rfkill_alloc("dell-bluetooth", NULL, |
264 | if (!bluetooth_rfkill) | 233 | RFKILL_TYPE_BLUETOOTH, |
234 | &dell_rfkill_ops, (void *) 2); | ||
235 | if (!bluetooth_rfkill) { | ||
236 | ret = -ENOMEM; | ||
265 | goto err_bluetooth; | 237 | goto err_bluetooth; |
266 | bluetooth_rfkill->name = "dell-bluetooth"; | 238 | } |
267 | bluetooth_rfkill->toggle_radio = dell_bluetooth_set; | ||
268 | bluetooth_rfkill->get_state = dell_bluetooth_get; | ||
269 | ret = rfkill_register(bluetooth_rfkill); | 239 | ret = rfkill_register(bluetooth_rfkill); |
270 | if (ret) | 240 | if (ret) |
271 | goto err_bluetooth; | 241 | goto err_bluetooth; |
272 | } | 242 | } |
273 | 243 | ||
274 | if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) { | 244 | if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) { |
275 | wwan_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_WWAN); | 245 | wwan_rfkill = rfkill_alloc("dell-wwan", NULL, RFKILL_TYPE_WWAN, |
276 | if (!wwan_rfkill) | 246 | &dell_rfkill_ops, (void *) 3); |
247 | if (!wwan_rfkill) { | ||
248 | ret = -ENOMEM; | ||
277 | goto err_wwan; | 249 | goto err_wwan; |
278 | wwan_rfkill->name = "dell-wwan"; | 250 | } |
279 | wwan_rfkill->toggle_radio = dell_wwan_set; | ||
280 | wwan_rfkill->get_state = dell_wwan_get; | ||
281 | ret = rfkill_register(wwan_rfkill); | 251 | ret = rfkill_register(wwan_rfkill); |
282 | if (ret) | 252 | if (ret) |
283 | goto err_wwan; | 253 | goto err_wwan; |
@@ -285,22 +255,15 @@ static int dell_setup_rfkill(void) | |||
285 | 255 | ||
286 | return 0; | 256 | return 0; |
287 | err_wwan: | 257 | err_wwan: |
288 | if (wwan_rfkill) | 258 | rfkill_destroy(wwan_rfkill); |
289 | rfkill_free(wwan_rfkill); | 259 | if (bluetooth_rfkill) |
290 | if (bluetooth_rfkill) { | ||
291 | rfkill_unregister(bluetooth_rfkill); | 260 | rfkill_unregister(bluetooth_rfkill); |
292 | bluetooth_rfkill = NULL; | ||
293 | } | ||
294 | err_bluetooth: | 261 | err_bluetooth: |
295 | if (bluetooth_rfkill) | 262 | rfkill_destroy(bluetooth_rfkill); |
296 | rfkill_free(bluetooth_rfkill); | 263 | if (wifi_rfkill) |
297 | if (wifi_rfkill) { | ||
298 | rfkill_unregister(wifi_rfkill); | 264 | rfkill_unregister(wifi_rfkill); |
299 | wifi_rfkill = NULL; | ||
300 | } | ||
301 | err_wifi: | 265 | err_wifi: |
302 | if (wifi_rfkill) | 266 | rfkill_destroy(wifi_rfkill); |
303 | rfkill_free(wifi_rfkill); | ||
304 | 267 | ||
305 | return ret; | 268 | return ret; |
306 | } | 269 | } |
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 353a898c3693..1208d0cedd15 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c | |||
@@ -299,39 +299,22 @@ static int update_bl_status(struct backlight_device *bd) | |||
299 | * Rfkill helpers | 299 | * Rfkill helpers |
300 | */ | 300 | */ |
301 | 301 | ||
302 | static int eeepc_wlan_rfkill_set(void *data, enum rfkill_state state) | 302 | static bool eeepc_wlan_rfkill_blocked(void) |
303 | { | ||
304 | if (state == RFKILL_STATE_SOFT_BLOCKED) | ||
305 | return set_acpi(CM_ASL_WLAN, 0); | ||
306 | else | ||
307 | return set_acpi(CM_ASL_WLAN, 1); | ||
308 | } | ||
309 | |||
310 | static int eeepc_wlan_rfkill_state(void *data, enum rfkill_state *state) | ||
311 | { | 303 | { |
312 | if (get_acpi(CM_ASL_WLAN) == 1) | 304 | if (get_acpi(CM_ASL_WLAN) == 1) |
313 | *state = RFKILL_STATE_UNBLOCKED; | 305 | return false; |
314 | else | 306 | return true; |
315 | *state = RFKILL_STATE_SOFT_BLOCKED; | ||
316 | return 0; | ||
317 | } | 307 | } |
318 | 308 | ||
319 | static int eeepc_bluetooth_rfkill_set(void *data, enum rfkill_state state) | 309 | static int eeepc_rfkill_set(void *data, bool blocked) |
320 | { | 310 | { |
321 | if (state == RFKILL_STATE_SOFT_BLOCKED) | 311 | unsigned long asl = (unsigned long)data; |
322 | return set_acpi(CM_ASL_BLUETOOTH, 0); | 312 | return set_acpi(asl, !blocked); |
323 | else | ||
324 | return set_acpi(CM_ASL_BLUETOOTH, 1); | ||
325 | } | 313 | } |
326 | 314 | ||
327 | static int eeepc_bluetooth_rfkill_state(void *data, enum rfkill_state *state) | 315 | static const struct rfkill_ops eeepc_rfkill_ops = { |
328 | { | 316 | .set_block = eeepc_rfkill_set, |
329 | if (get_acpi(CM_ASL_BLUETOOTH) == 1) | 317 | }; |
330 | *state = RFKILL_STATE_UNBLOCKED; | ||
331 | else | ||
332 | *state = RFKILL_STATE_SOFT_BLOCKED; | ||
333 | return 0; | ||
334 | } | ||
335 | 318 | ||
336 | /* | 319 | /* |
337 | * Sys helpers | 320 | * Sys helpers |
@@ -531,9 +514,9 @@ static int notify_brn(void) | |||
531 | 514 | ||
532 | static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) | 515 | static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) |
533 | { | 516 | { |
534 | enum rfkill_state state; | ||
535 | struct pci_dev *dev; | 517 | struct pci_dev *dev; |
536 | struct pci_bus *bus = pci_find_bus(0, 1); | 518 | struct pci_bus *bus = pci_find_bus(0, 1); |
519 | bool blocked; | ||
537 | 520 | ||
538 | if (event != ACPI_NOTIFY_BUS_CHECK) | 521 | if (event != ACPI_NOTIFY_BUS_CHECK) |
539 | return; | 522 | return; |
@@ -543,9 +526,8 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) | |||
543 | return; | 526 | return; |
544 | } | 527 | } |
545 | 528 | ||
546 | eeepc_wlan_rfkill_state(ehotk->eeepc_wlan_rfkill, &state); | 529 | blocked = eeepc_wlan_rfkill_blocked(); |
547 | 530 | if (!blocked) { | |
548 | if (state == RFKILL_STATE_UNBLOCKED) { | ||
549 | dev = pci_get_slot(bus, 0); | 531 | dev = pci_get_slot(bus, 0); |
550 | if (dev) { | 532 | if (dev) { |
551 | /* Device already present */ | 533 | /* Device already present */ |
@@ -566,7 +548,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) | |||
566 | } | 548 | } |
567 | } | 549 | } |
568 | 550 | ||
569 | rfkill_force_state(ehotk->eeepc_wlan_rfkill, state); | 551 | rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill, blocked); |
570 | } | 552 | } |
571 | 553 | ||
572 | static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data) | 554 | static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data) |
@@ -684,26 +666,17 @@ static int eeepc_hotk_add(struct acpi_device *device) | |||
684 | eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7"); | 666 | eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7"); |
685 | 667 | ||
686 | if (get_acpi(CM_ASL_WLAN) != -1) { | 668 | if (get_acpi(CM_ASL_WLAN) != -1) { |
687 | ehotk->eeepc_wlan_rfkill = rfkill_allocate(&device->dev, | 669 | ehotk->eeepc_wlan_rfkill = rfkill_alloc("eeepc-wlan", |
688 | RFKILL_TYPE_WLAN); | 670 | &device->dev, |
671 | RFKILL_TYPE_WLAN, | ||
672 | &eeepc_rfkill_ops, | ||
673 | (void *)CM_ASL_WLAN); | ||
689 | 674 | ||
690 | if (!ehotk->eeepc_wlan_rfkill) | 675 | if (!ehotk->eeepc_wlan_rfkill) |
691 | goto wlan_fail; | 676 | goto wlan_fail; |
692 | 677 | ||
693 | ehotk->eeepc_wlan_rfkill->name = "eeepc-wlan"; | 678 | rfkill_set_global_sw_state(RFKILL_TYPE_WLAN, |
694 | ehotk->eeepc_wlan_rfkill->toggle_radio = eeepc_wlan_rfkill_set; | 679 | get_acpi(CM_ASL_WLAN) != 1); |
695 | ehotk->eeepc_wlan_rfkill->get_state = eeepc_wlan_rfkill_state; | ||
696 | if (get_acpi(CM_ASL_WLAN) == 1) { | ||
697 | ehotk->eeepc_wlan_rfkill->state = | ||
698 | RFKILL_STATE_UNBLOCKED; | ||
699 | rfkill_set_default(RFKILL_TYPE_WLAN, | ||
700 | RFKILL_STATE_UNBLOCKED); | ||
701 | } else { | ||
702 | ehotk->eeepc_wlan_rfkill->state = | ||
703 | RFKILL_STATE_SOFT_BLOCKED; | ||
704 | rfkill_set_default(RFKILL_TYPE_WLAN, | ||
705 | RFKILL_STATE_SOFT_BLOCKED); | ||
706 | } | ||
707 | result = rfkill_register(ehotk->eeepc_wlan_rfkill); | 680 | result = rfkill_register(ehotk->eeepc_wlan_rfkill); |
708 | if (result) | 681 | if (result) |
709 | goto wlan_fail; | 682 | goto wlan_fail; |
@@ -711,28 +684,17 @@ static int eeepc_hotk_add(struct acpi_device *device) | |||
711 | 684 | ||
712 | if (get_acpi(CM_ASL_BLUETOOTH) != -1) { | 685 | if (get_acpi(CM_ASL_BLUETOOTH) != -1) { |
713 | ehotk->eeepc_bluetooth_rfkill = | 686 | ehotk->eeepc_bluetooth_rfkill = |
714 | rfkill_allocate(&device->dev, RFKILL_TYPE_BLUETOOTH); | 687 | rfkill_alloc("eeepc-bluetooth", |
688 | &device->dev, | ||
689 | RFKILL_TYPE_BLUETOOTH, | ||
690 | &eeepc_rfkill_ops, | ||
691 | (void *)CM_ASL_BLUETOOTH); | ||
715 | 692 | ||
716 | if (!ehotk->eeepc_bluetooth_rfkill) | 693 | if (!ehotk->eeepc_bluetooth_rfkill) |
717 | goto bluetooth_fail; | 694 | goto bluetooth_fail; |
718 | 695 | ||
719 | ehotk->eeepc_bluetooth_rfkill->name = "eeepc-bluetooth"; | 696 | rfkill_set_global_sw_state(RFKILL_TYPE_BLUETOOTH, |
720 | ehotk->eeepc_bluetooth_rfkill->toggle_radio = | 697 | get_acpi(CM_ASL_BLUETOOTH) != 1); |
721 | eeepc_bluetooth_rfkill_set; | ||
722 | ehotk->eeepc_bluetooth_rfkill->get_state = | ||
723 | eeepc_bluetooth_rfkill_state; | ||
724 | if (get_acpi(CM_ASL_BLUETOOTH) == 1) { | ||
725 | ehotk->eeepc_bluetooth_rfkill->state = | ||
726 | RFKILL_STATE_UNBLOCKED; | ||
727 | rfkill_set_default(RFKILL_TYPE_BLUETOOTH, | ||
728 | RFKILL_STATE_UNBLOCKED); | ||
729 | } else { | ||
730 | ehotk->eeepc_bluetooth_rfkill->state = | ||
731 | RFKILL_STATE_SOFT_BLOCKED; | ||
732 | rfkill_set_default(RFKILL_TYPE_BLUETOOTH, | ||
733 | RFKILL_STATE_SOFT_BLOCKED); | ||
734 | } | ||
735 | |||
736 | result = rfkill_register(ehotk->eeepc_bluetooth_rfkill); | 698 | result = rfkill_register(ehotk->eeepc_bluetooth_rfkill); |
737 | if (result) | 699 | if (result) |
738 | goto bluetooth_fail; | 700 | goto bluetooth_fail; |
@@ -741,13 +703,10 @@ static int eeepc_hotk_add(struct acpi_device *device) | |||
741 | return 0; | 703 | return 0; |
742 | 704 | ||
743 | bluetooth_fail: | 705 | bluetooth_fail: |
744 | if (ehotk->eeepc_bluetooth_rfkill) | 706 | rfkill_destroy(ehotk->eeepc_bluetooth_rfkill); |
745 | rfkill_free(ehotk->eeepc_bluetooth_rfkill); | ||
746 | rfkill_unregister(ehotk->eeepc_wlan_rfkill); | 707 | rfkill_unregister(ehotk->eeepc_wlan_rfkill); |
747 | ehotk->eeepc_wlan_rfkill = NULL; | ||
748 | wlan_fail: | 708 | wlan_fail: |
749 | if (ehotk->eeepc_wlan_rfkill) | 709 | rfkill_destroy(ehotk->eeepc_wlan_rfkill); |
750 | rfkill_free(ehotk->eeepc_wlan_rfkill); | ||
751 | eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); | 710 | eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); |
752 | eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); | 711 | eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); |
753 | ehotk_fail: | 712 | ehotk_fail: |
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index fe171fad12cf..8d931145cbfa 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c | |||
@@ -154,58 +154,46 @@ static int hp_wmi_dock_state(void) | |||
154 | return hp_wmi_perform_query(HPWMI_DOCK_QUERY, 0, 0); | 154 | return hp_wmi_perform_query(HPWMI_DOCK_QUERY, 0, 0); |
155 | } | 155 | } |
156 | 156 | ||
157 | static int hp_wmi_wifi_set(void *data, enum rfkill_state state) | 157 | static int hp_wmi_set_block(void *data, bool blocked) |
158 | { | 158 | { |
159 | if (state) | 159 | unsigned long b = (unsigned long) data; |
160 | return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x101); | 160 | int query = BIT(b + 8) | ((!!blocked) << b); |
161 | else | ||
162 | return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x100); | ||
163 | } | ||
164 | 161 | ||
165 | static int hp_wmi_bluetooth_set(void *data, enum rfkill_state state) | 162 | return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, query); |
166 | { | ||
167 | if (state) | ||
168 | return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x202); | ||
169 | else | ||
170 | return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x200); | ||
171 | } | 163 | } |
172 | 164 | ||
173 | static int hp_wmi_wwan_set(void *data, enum rfkill_state state) | 165 | static const struct rfkill_ops hp_wmi_rfkill_ops = { |
174 | { | 166 | .set_block = hp_wmi_set_block, |
175 | if (state) | 167 | }; |
176 | return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x404); | ||
177 | else | ||
178 | return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x400); | ||
179 | } | ||
180 | 168 | ||
181 | static int hp_wmi_wifi_state(void) | 169 | static bool hp_wmi_wifi_state(void) |
182 | { | 170 | { |
183 | int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); | 171 | int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); |
184 | 172 | ||
185 | if (wireless & 0x100) | 173 | if (wireless & 0x100) |
186 | return RFKILL_STATE_UNBLOCKED; | 174 | return false; |
187 | else | 175 | else |
188 | return RFKILL_STATE_SOFT_BLOCKED; | 176 | return true; |
189 | } | 177 | } |
190 | 178 | ||
191 | static int hp_wmi_bluetooth_state(void) | 179 | static bool hp_wmi_bluetooth_state(void) |
192 | { | 180 | { |
193 | int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); | 181 | int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); |
194 | 182 | ||
195 | if (wireless & 0x10000) | 183 | if (wireless & 0x10000) |
196 | return RFKILL_STATE_UNBLOCKED; | 184 | return false; |
197 | else | 185 | else |
198 | return RFKILL_STATE_SOFT_BLOCKED; | 186 | return true; |
199 | } | 187 | } |
200 | 188 | ||
201 | static int hp_wmi_wwan_state(void) | 189 | static bool hp_wmi_wwan_state(void) |
202 | { | 190 | { |
203 | int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); | 191 | int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); |
204 | 192 | ||
205 | if (wireless & 0x1000000) | 193 | if (wireless & 0x1000000) |
206 | return RFKILL_STATE_UNBLOCKED; | 194 | return false; |
207 | else | 195 | else |
208 | return RFKILL_STATE_SOFT_BLOCKED; | 196 | return true; |
209 | } | 197 | } |
210 | 198 | ||
211 | static ssize_t show_display(struct device *dev, struct device_attribute *attr, | 199 | static ssize_t show_display(struct device *dev, struct device_attribute *attr, |
@@ -347,14 +335,14 @@ static void hp_wmi_notify(u32 value, void *context) | |||
347 | } | 335 | } |
348 | } else if (eventcode == 0x5) { | 336 | } else if (eventcode == 0x5) { |
349 | if (wifi_rfkill) | 337 | if (wifi_rfkill) |
350 | rfkill_force_state(wifi_rfkill, | 338 | rfkill_set_sw_state(wifi_rfkill, |
351 | hp_wmi_wifi_state()); | 339 | hp_wmi_wifi_state()); |
352 | if (bluetooth_rfkill) | 340 | if (bluetooth_rfkill) |
353 | rfkill_force_state(bluetooth_rfkill, | 341 | rfkill_set_sw_state(bluetooth_rfkill, |
354 | hp_wmi_bluetooth_state()); | 342 | hp_wmi_bluetooth_state()); |
355 | if (wwan_rfkill) | 343 | if (wwan_rfkill) |
356 | rfkill_force_state(wwan_rfkill, | 344 | rfkill_set_sw_state(wwan_rfkill, |
357 | hp_wmi_wwan_state()); | 345 | hp_wmi_wwan_state()); |
358 | } else | 346 | } else |
359 | printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n", | 347 | printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n", |
360 | eventcode); | 348 | eventcode); |
@@ -430,31 +418,34 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) | |||
430 | goto add_sysfs_error; | 418 | goto add_sysfs_error; |
431 | 419 | ||
432 | if (wireless & 0x1) { | 420 | if (wireless & 0x1) { |
433 | wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN); | 421 | wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev, |
434 | wifi_rfkill->name = "hp-wifi"; | 422 | RFKILL_TYPE_WLAN, |
435 | wifi_rfkill->state = hp_wmi_wifi_state(); | 423 | &hp_wmi_rfkill_ops, |
436 | wifi_rfkill->toggle_radio = hp_wmi_wifi_set; | 424 | (void *) 0); |
425 | rfkill_set_sw_state(wifi_rfkill, hp_wmi_wifi_state()); | ||
437 | err = rfkill_register(wifi_rfkill); | 426 | err = rfkill_register(wifi_rfkill); |
438 | if (err) | 427 | if (err) |
439 | goto add_sysfs_error; | 428 | goto register_wifi_error; |
440 | } | 429 | } |
441 | 430 | ||
442 | if (wireless & 0x2) { | 431 | if (wireless & 0x2) { |
443 | bluetooth_rfkill = rfkill_allocate(&device->dev, | 432 | bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev, |
444 | RFKILL_TYPE_BLUETOOTH); | 433 | RFKILL_TYPE_BLUETOOTH, |
445 | bluetooth_rfkill->name = "hp-bluetooth"; | 434 | &hp_wmi_rfkill_ops, |
446 | bluetooth_rfkill->state = hp_wmi_bluetooth_state(); | 435 | (void *) 1); |
447 | bluetooth_rfkill->toggle_radio = hp_wmi_bluetooth_set; | 436 | rfkill_set_sw_state(bluetooth_rfkill, |
437 | hp_wmi_bluetooth_state()); | ||
448 | err = rfkill_register(bluetooth_rfkill); | 438 | err = rfkill_register(bluetooth_rfkill); |
449 | if (err) | 439 | if (err) |
450 | goto register_bluetooth_error; | 440 | goto register_bluetooth_error; |
451 | } | 441 | } |
452 | 442 | ||
453 | if (wireless & 0x4) { | 443 | if (wireless & 0x4) { |
454 | wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN); | 444 | wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev, |
455 | wwan_rfkill->name = "hp-wwan"; | 445 | RFKILL_TYPE_WWAN, |
456 | wwan_rfkill->state = hp_wmi_wwan_state(); | 446 | &hp_wmi_rfkill_ops, |
457 | wwan_rfkill->toggle_radio = hp_wmi_wwan_set; | 447 | (void *) 2); |
448 | rfkill_set_sw_state(wwan_rfkill, hp_wmi_wwan_state()); | ||
458 | err = rfkill_register(wwan_rfkill); | 449 | err = rfkill_register(wwan_rfkill); |
459 | if (err) | 450 | if (err) |
460 | goto register_wwan_err; | 451 | goto register_wwan_err; |
@@ -462,11 +453,15 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) | |||
462 | 453 | ||
463 | return 0; | 454 | return 0; |
464 | register_wwan_err: | 455 | register_wwan_err: |
456 | rfkill_destroy(wwan_rfkill); | ||
465 | if (bluetooth_rfkill) | 457 | if (bluetooth_rfkill) |
466 | rfkill_unregister(bluetooth_rfkill); | 458 | rfkill_unregister(bluetooth_rfkill); |
467 | register_bluetooth_error: | 459 | register_bluetooth_error: |
460 | rfkill_destroy(bluetooth_rfkill); | ||
468 | if (wifi_rfkill) | 461 | if (wifi_rfkill) |
469 | rfkill_unregister(wifi_rfkill); | 462 | rfkill_unregister(wifi_rfkill); |
463 | register_wifi_error: | ||
464 | rfkill_destroy(wifi_rfkill); | ||
470 | add_sysfs_error: | 465 | add_sysfs_error: |
471 | cleanup_sysfs(device); | 466 | cleanup_sysfs(device); |
472 | return err; | 467 | return err; |
@@ -476,12 +471,18 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device) | |||
476 | { | 471 | { |
477 | cleanup_sysfs(device); | 472 | cleanup_sysfs(device); |
478 | 473 | ||
479 | if (wifi_rfkill) | 474 | if (wifi_rfkill) { |
480 | rfkill_unregister(wifi_rfkill); | 475 | rfkill_unregister(wifi_rfkill); |
481 | if (bluetooth_rfkill) | 476 | rfkill_destroy(wifi_rfkill); |
477 | } | ||
478 | if (bluetooth_rfkill) { | ||
482 | rfkill_unregister(bluetooth_rfkill); | 479 | rfkill_unregister(bluetooth_rfkill); |
483 | if (wwan_rfkill) | 480 | rfkill_destroy(wifi_rfkill); |
481 | } | ||
482 | if (wwan_rfkill) { | ||
484 | rfkill_unregister(wwan_rfkill); | 483 | rfkill_unregister(wwan_rfkill); |
484 | rfkill_destroy(wwan_rfkill); | ||
485 | } | ||
485 | 486 | ||
486 | return 0; | 487 | return 0; |
487 | } | 488 | } |
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index f1963b05175b..aec0b27fd774 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c | |||
@@ -128,11 +128,11 @@ enum sony_nc_rfkill { | |||
128 | SONY_BLUETOOTH, | 128 | SONY_BLUETOOTH, |
129 | SONY_WWAN, | 129 | SONY_WWAN, |
130 | SONY_WIMAX, | 130 | SONY_WIMAX, |
131 | SONY_RFKILL_MAX, | 131 | N_SONY_RFKILL, |
132 | }; | 132 | }; |
133 | 133 | ||
134 | static struct rfkill *sony_rfkill_devices[SONY_RFKILL_MAX]; | 134 | static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL]; |
135 | static int sony_rfkill_address[SONY_RFKILL_MAX] = {0x300, 0x500, 0x700, 0x900}; | 135 | static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900}; |
136 | static void sony_nc_rfkill_update(void); | 136 | static void sony_nc_rfkill_update(void); |
137 | 137 | ||
138 | /*********** Input Devices ***********/ | 138 | /*********** Input Devices ***********/ |
@@ -1051,147 +1051,98 @@ static void sony_nc_rfkill_cleanup(void) | |||
1051 | { | 1051 | { |
1052 | int i; | 1052 | int i; |
1053 | 1053 | ||
1054 | for (i = 0; i < SONY_RFKILL_MAX; i++) { | 1054 | for (i = 0; i < N_SONY_RFKILL; i++) { |
1055 | if (sony_rfkill_devices[i]) | 1055 | if (sony_rfkill_devices[i]) { |
1056 | rfkill_unregister(sony_rfkill_devices[i]); | 1056 | rfkill_unregister(sony_rfkill_devices[i]); |
1057 | rfkill_destroy(sony_rfkill_devices[i]); | ||
1058 | } | ||
1057 | } | 1059 | } |
1058 | } | 1060 | } |
1059 | 1061 | ||
1060 | static int sony_nc_rfkill_get(void *data, enum rfkill_state *state) | 1062 | static int sony_nc_rfkill_set(void *data, bool blocked) |
1061 | { | ||
1062 | int result; | ||
1063 | int argument = sony_rfkill_address[(long) data]; | ||
1064 | |||
1065 | sony_call_snc_handle(0x124, 0x200, &result); | ||
1066 | if (result & 0x1) { | ||
1067 | sony_call_snc_handle(0x124, argument, &result); | ||
1068 | if (result & 0xf) | ||
1069 | *state = RFKILL_STATE_UNBLOCKED; | ||
1070 | else | ||
1071 | *state = RFKILL_STATE_SOFT_BLOCKED; | ||
1072 | } else { | ||
1073 | *state = RFKILL_STATE_HARD_BLOCKED; | ||
1074 | } | ||
1075 | |||
1076 | return 0; | ||
1077 | } | ||
1078 | |||
1079 | static int sony_nc_rfkill_set(void *data, enum rfkill_state state) | ||
1080 | { | 1063 | { |
1081 | int result; | 1064 | int result; |
1082 | int argument = sony_rfkill_address[(long) data] + 0x100; | 1065 | int argument = sony_rfkill_address[(long) data] + 0x100; |
1083 | 1066 | ||
1084 | if (state == RFKILL_STATE_UNBLOCKED) | 1067 | if (!blocked) |
1085 | argument |= 0xff0000; | 1068 | argument |= 0xff0000; |
1086 | 1069 | ||
1087 | return sony_call_snc_handle(0x124, argument, &result); | 1070 | return sony_call_snc_handle(0x124, argument, &result); |
1088 | } | 1071 | } |
1089 | 1072 | ||
1090 | static int sony_nc_setup_wifi_rfkill(struct acpi_device *device) | 1073 | static const struct rfkill_ops sony_rfkill_ops = { |
1091 | { | 1074 | .set_block = sony_nc_rfkill_set, |
1092 | int err = 0; | 1075 | }; |
1093 | struct rfkill *sony_wifi_rfkill; | ||
1094 | |||
1095 | sony_wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN); | ||
1096 | if (!sony_wifi_rfkill) | ||
1097 | return -1; | ||
1098 | sony_wifi_rfkill->name = "sony-wifi"; | ||
1099 | sony_wifi_rfkill->toggle_radio = sony_nc_rfkill_set; | ||
1100 | sony_wifi_rfkill->get_state = sony_nc_rfkill_get; | ||
1101 | sony_wifi_rfkill->data = (void *)SONY_WIFI; | ||
1102 | err = rfkill_register(sony_wifi_rfkill); | ||
1103 | if (err) | ||
1104 | rfkill_free(sony_wifi_rfkill); | ||
1105 | else { | ||
1106 | sony_rfkill_devices[SONY_WIFI] = sony_wifi_rfkill; | ||
1107 | sony_nc_rfkill_set(sony_wifi_rfkill->data, | ||
1108 | RFKILL_STATE_UNBLOCKED); | ||
1109 | } | ||
1110 | return err; | ||
1111 | } | ||
1112 | 1076 | ||
1113 | static int sony_nc_setup_bluetooth_rfkill(struct acpi_device *device) | 1077 | static int sony_nc_setup_rfkill(struct acpi_device *device, |
1078 | enum sony_nc_rfkill nc_type) | ||
1114 | { | 1079 | { |
1115 | int err = 0; | 1080 | int err = 0; |
1116 | struct rfkill *sony_bluetooth_rfkill; | 1081 | struct rfkill *rfk; |
1117 | 1082 | enum rfkill_type type; | |
1118 | sony_bluetooth_rfkill = rfkill_allocate(&device->dev, | 1083 | const char *name; |
1119 | RFKILL_TYPE_BLUETOOTH); | 1084 | |
1120 | if (!sony_bluetooth_rfkill) | 1085 | switch (nc_type) { |
1121 | return -1; | 1086 | case SONY_WIFI: |
1122 | sony_bluetooth_rfkill->name = "sony-bluetooth"; | 1087 | type = RFKILL_TYPE_WLAN; |
1123 | sony_bluetooth_rfkill->toggle_radio = sony_nc_rfkill_set; | 1088 | name = "sony-wifi"; |
1124 | sony_bluetooth_rfkill->get_state = sony_nc_rfkill_get; | 1089 | break; |
1125 | sony_bluetooth_rfkill->data = (void *)SONY_BLUETOOTH; | 1090 | case SONY_BLUETOOTH: |
1126 | err = rfkill_register(sony_bluetooth_rfkill); | 1091 | type = RFKILL_TYPE_BLUETOOTH; |
1127 | if (err) | 1092 | name = "sony-bluetooth"; |
1128 | rfkill_free(sony_bluetooth_rfkill); | 1093 | break; |
1129 | else { | 1094 | case SONY_WWAN: |
1130 | sony_rfkill_devices[SONY_BLUETOOTH] = sony_bluetooth_rfkill; | 1095 | type = RFKILL_TYPE_WWAN; |
1131 | sony_nc_rfkill_set(sony_bluetooth_rfkill->data, | 1096 | name = "sony-wwan"; |
1132 | RFKILL_STATE_UNBLOCKED); | 1097 | break; |
1098 | case SONY_WIMAX: | ||
1099 | type = RFKILL_TYPE_WIMAX; | ||
1100 | name = "sony-wimax"; | ||
1101 | break; | ||
1102 | default: | ||
1103 | return -EINVAL; | ||
1133 | } | 1104 | } |
1134 | return err; | ||
1135 | } | ||
1136 | 1105 | ||
1137 | static int sony_nc_setup_wwan_rfkill(struct acpi_device *device) | 1106 | rfk = rfkill_alloc(name, &device->dev, type, |
1138 | { | 1107 | &sony_rfkill_ops, (void *)nc_type); |
1139 | int err = 0; | 1108 | if (!rfk) |
1140 | struct rfkill *sony_wwan_rfkill; | 1109 | return -ENOMEM; |
1141 | 1110 | ||
1142 | sony_wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN); | 1111 | err = rfkill_register(rfk); |
1143 | if (!sony_wwan_rfkill) | 1112 | if (err) { |
1144 | return -1; | 1113 | rfkill_destroy(rfk); |
1145 | sony_wwan_rfkill->name = "sony-wwan"; | 1114 | return err; |
1146 | sony_wwan_rfkill->toggle_radio = sony_nc_rfkill_set; | ||
1147 | sony_wwan_rfkill->get_state = sony_nc_rfkill_get; | ||
1148 | sony_wwan_rfkill->data = (void *)SONY_WWAN; | ||
1149 | err = rfkill_register(sony_wwan_rfkill); | ||
1150 | if (err) | ||
1151 | rfkill_free(sony_wwan_rfkill); | ||
1152 | else { | ||
1153 | sony_rfkill_devices[SONY_WWAN] = sony_wwan_rfkill; | ||
1154 | sony_nc_rfkill_set(sony_wwan_rfkill->data, | ||
1155 | RFKILL_STATE_UNBLOCKED); | ||
1156 | } | 1115 | } |
1116 | sony_rfkill_devices[nc_type] = rfk; | ||
1117 | sony_nc_rfkill_set((void *)nc_type, false); | ||
1157 | return err; | 1118 | return err; |
1158 | } | 1119 | } |
1159 | 1120 | ||
1160 | static int sony_nc_setup_wimax_rfkill(struct acpi_device *device) | 1121 | static void sony_nc_rfkill_update() |
1161 | { | 1122 | { |
1162 | int err = 0; | 1123 | enum sony_nc_rfkill i; |
1163 | struct rfkill *sony_wimax_rfkill; | 1124 | int result; |
1125 | bool hwblock; | ||
1164 | 1126 | ||
1165 | sony_wimax_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WIMAX); | 1127 | sony_call_snc_handle(0x124, 0x200, &result); |
1166 | if (!sony_wimax_rfkill) | 1128 | hwblock = !(result & 0x1); |
1167 | return -1; | ||
1168 | sony_wimax_rfkill->name = "sony-wimax"; | ||
1169 | sony_wimax_rfkill->toggle_radio = sony_nc_rfkill_set; | ||
1170 | sony_wimax_rfkill->get_state = sony_nc_rfkill_get; | ||
1171 | sony_wimax_rfkill->data = (void *)SONY_WIMAX; | ||
1172 | err = rfkill_register(sony_wimax_rfkill); | ||
1173 | if (err) | ||
1174 | rfkill_free(sony_wimax_rfkill); | ||
1175 | else { | ||
1176 | sony_rfkill_devices[SONY_WIMAX] = sony_wimax_rfkill; | ||
1177 | sony_nc_rfkill_set(sony_wimax_rfkill->data, | ||
1178 | RFKILL_STATE_UNBLOCKED); | ||
1179 | } | ||
1180 | return err; | ||
1181 | } | ||
1182 | 1129 | ||
1183 | static void sony_nc_rfkill_update() | 1130 | for (i = 0; i < N_SONY_RFKILL; i++) { |
1184 | { | 1131 | int argument = sony_rfkill_address[i]; |
1185 | int i; | ||
1186 | enum rfkill_state state; | ||
1187 | 1132 | ||
1188 | for (i = 0; i < SONY_RFKILL_MAX; i++) { | 1133 | if (!sony_rfkill_devices[i]) |
1189 | if (sony_rfkill_devices[i]) { | 1134 | continue; |
1190 | sony_rfkill_devices[i]-> | 1135 | |
1191 | get_state(sony_rfkill_devices[i]->data, | 1136 | if (hwblock) { |
1192 | &state); | 1137 | if (rfkill_set_hw_state(sony_rfkill_devices[i], true)) |
1193 | rfkill_force_state(sony_rfkill_devices[i], state); | 1138 | sony_nc_rfkill_set(sony_rfkill_devices[i], |
1139 | true); | ||
1140 | continue; | ||
1194 | } | 1141 | } |
1142 | |||
1143 | sony_call_snc_handle(0x124, argument, &result); | ||
1144 | rfkill_set_states(sony_rfkill_devices[i], | ||
1145 | !(result & 0xf), false); | ||
1195 | } | 1146 | } |
1196 | } | 1147 | } |
1197 | 1148 | ||
@@ -1210,13 +1161,13 @@ static int sony_nc_rfkill_setup(struct acpi_device *device) | |||
1210 | } | 1161 | } |
1211 | 1162 | ||
1212 | if (result & 0x1) | 1163 | if (result & 0x1) |
1213 | sony_nc_setup_wifi_rfkill(device); | 1164 | sony_nc_setup_rfkill(device, SONY_WIFI); |
1214 | if (result & 0x2) | 1165 | if (result & 0x2) |
1215 | sony_nc_setup_bluetooth_rfkill(device); | 1166 | sony_nc_setup_rfkill(device, SONY_BLUETOOTH); |
1216 | if (result & 0x1c) | 1167 | if (result & 0x1c) |
1217 | sony_nc_setup_wwan_rfkill(device); | 1168 | sony_nc_setup_rfkill(device, SONY_WWAN); |
1218 | if (result & 0x20) | 1169 | if (result & 0x20) |
1219 | sony_nc_setup_wimax_rfkill(device); | 1170 | sony_nc_setup_rfkill(device, SONY_WIMAX); |
1220 | 1171 | ||
1221 | return 0; | 1172 | return 0; |
1222 | } | 1173 | } |
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 912be65b6261..cfcafa4e9473 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c | |||
@@ -166,13 +166,6 @@ enum { | |||
166 | 166 | ||
167 | #define TPACPI_MAX_ACPI_ARGS 3 | 167 | #define TPACPI_MAX_ACPI_ARGS 3 |
168 | 168 | ||
169 | /* rfkill switches */ | ||
170 | enum { | ||
171 | TPACPI_RFK_BLUETOOTH_SW_ID = 0, | ||
172 | TPACPI_RFK_WWAN_SW_ID, | ||
173 | TPACPI_RFK_UWB_SW_ID, | ||
174 | }; | ||
175 | |||
176 | /* printk headers */ | 169 | /* printk headers */ |
177 | #define TPACPI_LOG TPACPI_FILE ": " | 170 | #define TPACPI_LOG TPACPI_FILE ": " |
178 | #define TPACPI_EMERG KERN_EMERG TPACPI_LOG | 171 | #define TPACPI_EMERG KERN_EMERG TPACPI_LOG |
@@ -1005,67 +998,237 @@ static int __init tpacpi_check_std_acpi_brightness_support(void) | |||
1005 | return 0; | 998 | return 0; |
1006 | } | 999 | } |
1007 | 1000 | ||
1008 | static int __init tpacpi_new_rfkill(const unsigned int id, | 1001 | static void printk_deprecated_attribute(const char * const what, |
1009 | struct rfkill **rfk, | 1002 | const char * const details) |
1003 | { | ||
1004 | tpacpi_log_usertask("deprecated sysfs attribute"); | ||
1005 | printk(TPACPI_WARN "WARNING: sysfs attribute %s is deprecated and " | ||
1006 | "will be removed. %s\n", | ||
1007 | what, details); | ||
1008 | } | ||
1009 | |||
1010 | /************************************************************************* | ||
1011 | * rfkill and radio control support helpers | ||
1012 | */ | ||
1013 | |||
1014 | /* | ||
1015 | * ThinkPad-ACPI firmware handling model: | ||
1016 | * | ||
1017 | * WLSW (master wireless switch) is event-driven, and is common to all | ||
1018 | * firmware-controlled radios. It cannot be controlled, just monitored, | ||
1019 | * as expected. It overrides all radio state in firmware | ||
1020 | * | ||
1021 | * The kernel, a masked-off hotkey, and WLSW can change the radio state | ||
1022 | * (TODO: verify how WLSW interacts with the returned radio state). | ||
1023 | * | ||
1024 | * The only time there are shadow radio state changes, is when | ||
1025 | * masked-off hotkeys are used. | ||
1026 | */ | ||
1027 | |||
1028 | /* | ||
1029 | * Internal driver API for radio state: | ||
1030 | * | ||
1031 | * int: < 0 = error, otherwise enum tpacpi_rfkill_state | ||
1032 | * bool: true means radio blocked (off) | ||
1033 | */ | ||
1034 | enum tpacpi_rfkill_state { | ||
1035 | TPACPI_RFK_RADIO_OFF = 0, | ||
1036 | TPACPI_RFK_RADIO_ON | ||
1037 | }; | ||
1038 | |||
1039 | /* rfkill switches */ | ||
1040 | enum tpacpi_rfk_id { | ||
1041 | TPACPI_RFK_BLUETOOTH_SW_ID = 0, | ||
1042 | TPACPI_RFK_WWAN_SW_ID, | ||
1043 | TPACPI_RFK_UWB_SW_ID, | ||
1044 | TPACPI_RFK_SW_MAX | ||
1045 | }; | ||
1046 | |||
1047 | static const char *tpacpi_rfkill_names[] = { | ||
1048 | [TPACPI_RFK_BLUETOOTH_SW_ID] = "bluetooth", | ||
1049 | [TPACPI_RFK_WWAN_SW_ID] = "wwan", | ||
1050 | [TPACPI_RFK_UWB_SW_ID] = "uwb", | ||
1051 | [TPACPI_RFK_SW_MAX] = NULL | ||
1052 | }; | ||
1053 | |||
1054 | /* ThinkPad-ACPI rfkill subdriver */ | ||
1055 | struct tpacpi_rfk { | ||
1056 | struct rfkill *rfkill; | ||
1057 | enum tpacpi_rfk_id id; | ||
1058 | const struct tpacpi_rfk_ops *ops; | ||
1059 | }; | ||
1060 | |||
1061 | struct tpacpi_rfk_ops { | ||
1062 | /* firmware interface */ | ||
1063 | int (*get_status)(void); | ||
1064 | int (*set_status)(const enum tpacpi_rfkill_state); | ||
1065 | }; | ||
1066 | |||
1067 | static struct tpacpi_rfk *tpacpi_rfkill_switches[TPACPI_RFK_SW_MAX]; | ||
1068 | |||
1069 | /* Query FW and update rfkill sw state for a given rfkill switch */ | ||
1070 | static int tpacpi_rfk_update_swstate(const struct tpacpi_rfk *tp_rfk) | ||
1071 | { | ||
1072 | int status; | ||
1073 | |||
1074 | if (!tp_rfk) | ||
1075 | return -ENODEV; | ||
1076 | |||
1077 | status = (tp_rfk->ops->get_status)(); | ||
1078 | if (status < 0) | ||
1079 | return status; | ||
1080 | |||
1081 | rfkill_set_sw_state(tp_rfk->rfkill, | ||
1082 | (status == TPACPI_RFK_RADIO_OFF)); | ||
1083 | |||
1084 | return status; | ||
1085 | } | ||
1086 | |||
1087 | /* Query FW and update rfkill sw state for all rfkill switches */ | ||
1088 | static void tpacpi_rfk_update_swstate_all(void) | ||
1089 | { | ||
1090 | unsigned int i; | ||
1091 | |||
1092 | for (i = 0; i < TPACPI_RFK_SW_MAX; i++) | ||
1093 | tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[i]); | ||
1094 | } | ||
1095 | |||
1096 | /* | ||
1097 | * Sync the HW-blocking state of all rfkill switches, | ||
1098 | * do notice it causes the rfkill core to schedule uevents | ||
1099 | */ | ||
1100 | static void tpacpi_rfk_update_hwblock_state(bool blocked) | ||
1101 | { | ||
1102 | unsigned int i; | ||
1103 | struct tpacpi_rfk *tp_rfk; | ||
1104 | |||
1105 | for (i = 0; i < TPACPI_RFK_SW_MAX; i++) { | ||
1106 | tp_rfk = tpacpi_rfkill_switches[i]; | ||
1107 | if (tp_rfk) { | ||
1108 | if (rfkill_set_hw_state(tp_rfk->rfkill, | ||
1109 | blocked)) { | ||
1110 | /* ignore -- we track sw block */ | ||
1111 | } | ||
1112 | } | ||
1113 | } | ||
1114 | } | ||
1115 | |||
1116 | /* Call to get the WLSW state from the firmware */ | ||
1117 | static int hotkey_get_wlsw(void); | ||
1118 | |||
1119 | /* Call to query WLSW state and update all rfkill switches */ | ||
1120 | static bool tpacpi_rfk_check_hwblock_state(void) | ||
1121 | { | ||
1122 | int res = hotkey_get_wlsw(); | ||
1123 | int hw_blocked; | ||
1124 | |||
1125 | /* When unknown or unsupported, we have to assume it is unblocked */ | ||
1126 | if (res < 0) | ||
1127 | return false; | ||
1128 | |||
1129 | hw_blocked = (res == TPACPI_RFK_RADIO_OFF); | ||
1130 | tpacpi_rfk_update_hwblock_state(hw_blocked); | ||
1131 | |||
1132 | return hw_blocked; | ||
1133 | } | ||
1134 | |||
1135 | static int tpacpi_rfk_hook_set_block(void *data, bool blocked) | ||
1136 | { | ||
1137 | struct tpacpi_rfk *tp_rfk = data; | ||
1138 | int res; | ||
1139 | |||
1140 | dbg_printk(TPACPI_DBG_RFKILL, | ||
1141 | "request to change radio state to %s\n", | ||
1142 | blocked ? "blocked" : "unblocked"); | ||
1143 | |||
1144 | /* try to set radio state */ | ||
1145 | res = (tp_rfk->ops->set_status)(blocked ? | ||
1146 | TPACPI_RFK_RADIO_OFF : TPACPI_RFK_RADIO_ON); | ||
1147 | |||
1148 | /* and update the rfkill core with whatever the FW really did */ | ||
1149 | tpacpi_rfk_update_swstate(tp_rfk); | ||
1150 | |||
1151 | return (res < 0) ? res : 0; | ||
1152 | } | ||
1153 | |||
1154 | static const struct rfkill_ops tpacpi_rfk_rfkill_ops = { | ||
1155 | .set_block = tpacpi_rfk_hook_set_block, | ||
1156 | }; | ||
1157 | |||
1158 | static int __init tpacpi_new_rfkill(const enum tpacpi_rfk_id id, | ||
1159 | const struct tpacpi_rfk_ops *tp_rfkops, | ||
1010 | const enum rfkill_type rfktype, | 1160 | const enum rfkill_type rfktype, |
1011 | const char *name, | 1161 | const char *name, |
1012 | const bool set_default, | 1162 | const bool set_default) |
1013 | int (*toggle_radio)(void *, enum rfkill_state), | ||
1014 | int (*get_state)(void *, enum rfkill_state *)) | ||
1015 | { | 1163 | { |
1164 | struct tpacpi_rfk *atp_rfk; | ||
1016 | int res; | 1165 | int res; |
1017 | enum rfkill_state initial_state = RFKILL_STATE_SOFT_BLOCKED; | 1166 | bool initial_sw_state = false; |
1167 | int initial_sw_status; | ||
1018 | 1168 | ||
1019 | res = get_state(NULL, &initial_state); | 1169 | BUG_ON(id >= TPACPI_RFK_SW_MAX || tpacpi_rfkill_switches[id]); |
1020 | if (res < 0) { | 1170 | |
1171 | initial_sw_status = (tp_rfkops->get_status)(); | ||
1172 | if (initial_sw_status < 0) { | ||
1021 | printk(TPACPI_ERR | 1173 | printk(TPACPI_ERR |
1022 | "failed to read initial state for %s, error %d; " | 1174 | "failed to read initial state for %s, error %d; " |
1023 | "will turn radio off\n", name, res); | 1175 | "will turn radio off\n", name, initial_sw_status); |
1024 | } else if (set_default) { | 1176 | } else { |
1025 | /* try to set the initial state as the default for the rfkill | 1177 | initial_sw_state = (initial_sw_status == TPACPI_RFK_RADIO_OFF); |
1026 | * type, since we ask the firmware to preserve it across S5 in | 1178 | if (set_default) { |
1027 | * NVRAM */ | 1179 | /* try to set the initial state as the default for the |
1028 | if (rfkill_set_default(rfktype, | 1180 | * rfkill type, since we ask the firmware to preserve |
1029 | (initial_state == RFKILL_STATE_UNBLOCKED) ? | 1181 | * it across S5 in NVRAM */ |
1030 | RFKILL_STATE_UNBLOCKED : | 1182 | rfkill_set_global_sw_state(rfktype, initial_sw_state); |
1031 | RFKILL_STATE_SOFT_BLOCKED) == -EPERM) | 1183 | } |
1032 | vdbg_printk(TPACPI_DBG_RFKILL, | 1184 | } |
1033 | "Default state for %s cannot be changed\n", | 1185 | |
1034 | name); | 1186 | atp_rfk = kzalloc(sizeof(struct tpacpi_rfk), GFP_KERNEL); |
1035 | } | 1187 | if (atp_rfk) |
1036 | 1188 | atp_rfk->rfkill = rfkill_alloc(name, | |
1037 | *rfk = rfkill_allocate(&tpacpi_pdev->dev, rfktype); | 1189 | &tpacpi_pdev->dev, |
1038 | if (!*rfk) { | 1190 | rfktype, |
1191 | &tpacpi_rfk_rfkill_ops, | ||
1192 | atp_rfk); | ||
1193 | if (!atp_rfk || !atp_rfk->rfkill) { | ||
1039 | printk(TPACPI_ERR | 1194 | printk(TPACPI_ERR |
1040 | "failed to allocate memory for rfkill class\n"); | 1195 | "failed to allocate memory for rfkill class\n"); |
1196 | kfree(atp_rfk); | ||
1041 | return -ENOMEM; | 1197 | return -ENOMEM; |
1042 | } | 1198 | } |
1043 | 1199 | ||
1044 | (*rfk)->name = name; | 1200 | atp_rfk->id = id; |
1045 | (*rfk)->get_state = get_state; | 1201 | atp_rfk->ops = tp_rfkops; |
1046 | (*rfk)->toggle_radio = toggle_radio; | 1202 | |
1047 | (*rfk)->state = initial_state; | 1203 | rfkill_set_states(atp_rfk->rfkill, initial_sw_state, |
1204 | tpacpi_rfk_check_hwblock_state()); | ||
1048 | 1205 | ||
1049 | res = rfkill_register(*rfk); | 1206 | res = rfkill_register(atp_rfk->rfkill); |
1050 | if (res < 0) { | 1207 | if (res < 0) { |
1051 | printk(TPACPI_ERR | 1208 | printk(TPACPI_ERR |
1052 | "failed to register %s rfkill switch: %d\n", | 1209 | "failed to register %s rfkill switch: %d\n", |
1053 | name, res); | 1210 | name, res); |
1054 | rfkill_free(*rfk); | 1211 | rfkill_destroy(atp_rfk->rfkill); |
1055 | *rfk = NULL; | 1212 | kfree(atp_rfk); |
1056 | return res; | 1213 | return res; |
1057 | } | 1214 | } |
1058 | 1215 | ||
1216 | tpacpi_rfkill_switches[id] = atp_rfk; | ||
1059 | return 0; | 1217 | return 0; |
1060 | } | 1218 | } |
1061 | 1219 | ||
1062 | static void printk_deprecated_attribute(const char * const what, | 1220 | static void tpacpi_destroy_rfkill(const enum tpacpi_rfk_id id) |
1063 | const char * const details) | ||
1064 | { | 1221 | { |
1065 | tpacpi_log_usertask("deprecated sysfs attribute"); | 1222 | struct tpacpi_rfk *tp_rfk; |
1066 | printk(TPACPI_WARN "WARNING: sysfs attribute %s is deprecated and " | 1223 | |
1067 | "will be removed. %s\n", | 1224 | BUG_ON(id >= TPACPI_RFK_SW_MAX); |
1068 | what, details); | 1225 | |
1226 | tp_rfk = tpacpi_rfkill_switches[id]; | ||
1227 | if (tp_rfk) { | ||
1228 | rfkill_unregister(tp_rfk->rfkill); | ||
1229 | tpacpi_rfkill_switches[id] = NULL; | ||
1230 | kfree(tp_rfk); | ||
1231 | } | ||
1069 | } | 1232 | } |
1070 | 1233 | ||
1071 | static void printk_deprecated_rfkill_attribute(const char * const what) | 1234 | static void printk_deprecated_rfkill_attribute(const char * const what) |
@@ -1074,6 +1237,112 @@ static void printk_deprecated_rfkill_attribute(const char * const what) | |||
1074 | "Please switch to generic rfkill before year 2010"); | 1237 | "Please switch to generic rfkill before year 2010"); |
1075 | } | 1238 | } |
1076 | 1239 | ||
1240 | /* sysfs <radio> enable ------------------------------------------------ */ | ||
1241 | static ssize_t tpacpi_rfk_sysfs_enable_show(const enum tpacpi_rfk_id id, | ||
1242 | struct device_attribute *attr, | ||
1243 | char *buf) | ||
1244 | { | ||
1245 | int status; | ||
1246 | |||
1247 | printk_deprecated_rfkill_attribute(attr->attr.name); | ||
1248 | |||
1249 | /* This is in the ABI... */ | ||
1250 | if (tpacpi_rfk_check_hwblock_state()) { | ||
1251 | status = TPACPI_RFK_RADIO_OFF; | ||
1252 | } else { | ||
1253 | status = tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[id]); | ||
1254 | if (status < 0) | ||
1255 | return status; | ||
1256 | } | ||
1257 | |||
1258 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
1259 | (status == TPACPI_RFK_RADIO_ON) ? 1 : 0); | ||
1260 | } | ||
1261 | |||
1262 | static ssize_t tpacpi_rfk_sysfs_enable_store(const enum tpacpi_rfk_id id, | ||
1263 | struct device_attribute *attr, | ||
1264 | const char *buf, size_t count) | ||
1265 | { | ||
1266 | unsigned long t; | ||
1267 | int res; | ||
1268 | |||
1269 | printk_deprecated_rfkill_attribute(attr->attr.name); | ||
1270 | |||
1271 | if (parse_strtoul(buf, 1, &t)) | ||
1272 | return -EINVAL; | ||
1273 | |||
1274 | tpacpi_disclose_usertask(attr->attr.name, "set to %ld\n", t); | ||
1275 | |||
1276 | /* This is in the ABI... */ | ||
1277 | if (tpacpi_rfk_check_hwblock_state() && !!t) | ||
1278 | return -EPERM; | ||
1279 | |||
1280 | res = tpacpi_rfkill_switches[id]->ops->set_status((!!t) ? | ||
1281 | TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF); | ||
1282 | tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[id]); | ||
1283 | |||
1284 | return (res < 0) ? res : count; | ||
1285 | } | ||
1286 | |||
1287 | /* procfs -------------------------------------------------------------- */ | ||
1288 | static int tpacpi_rfk_procfs_read(const enum tpacpi_rfk_id id, char *p) | ||
1289 | { | ||
1290 | int len = 0; | ||
1291 | |||
1292 | if (id >= TPACPI_RFK_SW_MAX) | ||
1293 | len += sprintf(p + len, "status:\t\tnot supported\n"); | ||
1294 | else { | ||
1295 | int status; | ||
1296 | |||
1297 | /* This is in the ABI... */ | ||
1298 | if (tpacpi_rfk_check_hwblock_state()) { | ||
1299 | status = TPACPI_RFK_RADIO_OFF; | ||
1300 | } else { | ||
1301 | status = tpacpi_rfk_update_swstate( | ||
1302 | tpacpi_rfkill_switches[id]); | ||
1303 | if (status < 0) | ||
1304 | return status; | ||
1305 | } | ||
1306 | |||
1307 | len += sprintf(p + len, "status:\t\t%s\n", | ||
1308 | (status == TPACPI_RFK_RADIO_ON) ? | ||
1309 | "enabled" : "disabled"); | ||
1310 | len += sprintf(p + len, "commands:\tenable, disable\n"); | ||
1311 | } | ||
1312 | |||
1313 | return len; | ||
1314 | } | ||
1315 | |||
1316 | static int tpacpi_rfk_procfs_write(const enum tpacpi_rfk_id id, char *buf) | ||
1317 | { | ||
1318 | char *cmd; | ||
1319 | int status = -1; | ||
1320 | int res = 0; | ||
1321 | |||
1322 | if (id >= TPACPI_RFK_SW_MAX) | ||
1323 | return -ENODEV; | ||
1324 | |||
1325 | while ((cmd = next_cmd(&buf))) { | ||
1326 | if (strlencmp(cmd, "enable") == 0) | ||
1327 | status = TPACPI_RFK_RADIO_ON; | ||
1328 | else if (strlencmp(cmd, "disable") == 0) | ||
1329 | status = TPACPI_RFK_RADIO_OFF; | ||
1330 | else | ||
1331 | return -EINVAL; | ||
1332 | } | ||
1333 | |||
1334 | if (status != -1) { | ||
1335 | tpacpi_disclose_usertask("procfs", "attempt to %s %s\n", | ||
1336 | (status == TPACPI_RFK_RADIO_ON) ? | ||
1337 | "enable" : "disable", | ||
1338 | tpacpi_rfkill_names[id]); | ||
1339 | res = (tpacpi_rfkill_switches[id]->ops->set_status)(status); | ||
1340 | tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[id]); | ||
1341 | } | ||
1342 | |||
1343 | return res; | ||
1344 | } | ||
1345 | |||
1077 | /************************************************************************* | 1346 | /************************************************************************* |
1078 | * thinkpad-acpi driver attributes | 1347 | * thinkpad-acpi driver attributes |
1079 | */ | 1348 | */ |
@@ -1127,8 +1396,6 @@ static DRIVER_ATTR(version, S_IRUGO, | |||
1127 | 1396 | ||
1128 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | 1397 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES |
1129 | 1398 | ||
1130 | static void tpacpi_send_radiosw_update(void); | ||
1131 | |||
1132 | /* wlsw_emulstate ------------------------------------------------------ */ | 1399 | /* wlsw_emulstate ------------------------------------------------------ */ |
1133 | static ssize_t tpacpi_driver_wlsw_emulstate_show(struct device_driver *drv, | 1400 | static ssize_t tpacpi_driver_wlsw_emulstate_show(struct device_driver *drv, |
1134 | char *buf) | 1401 | char *buf) |
@@ -1144,11 +1411,10 @@ static ssize_t tpacpi_driver_wlsw_emulstate_store(struct device_driver *drv, | |||
1144 | if (parse_strtoul(buf, 1, &t)) | 1411 | if (parse_strtoul(buf, 1, &t)) |
1145 | return -EINVAL; | 1412 | return -EINVAL; |
1146 | 1413 | ||
1147 | if (tpacpi_wlsw_emulstate != t) { | 1414 | if (tpacpi_wlsw_emulstate != !!t) { |
1148 | tpacpi_wlsw_emulstate = !!t; | ||
1149 | tpacpi_send_radiosw_update(); | ||
1150 | } else | ||
1151 | tpacpi_wlsw_emulstate = !!t; | 1415 | tpacpi_wlsw_emulstate = !!t; |
1416 | tpacpi_rfk_update_hwblock_state(!t); /* negative logic */ | ||
1417 | } | ||
1152 | 1418 | ||
1153 | return count; | 1419 | return count; |
1154 | } | 1420 | } |
@@ -1463,17 +1729,23 @@ static struct attribute_set *hotkey_dev_attributes; | |||
1463 | /* HKEY.MHKG() return bits */ | 1729 | /* HKEY.MHKG() return bits */ |
1464 | #define TP_HOTKEY_TABLET_MASK (1 << 3) | 1730 | #define TP_HOTKEY_TABLET_MASK (1 << 3) |
1465 | 1731 | ||
1466 | static int hotkey_get_wlsw(int *status) | 1732 | static int hotkey_get_wlsw(void) |
1467 | { | 1733 | { |
1734 | int status; | ||
1735 | |||
1736 | if (!tp_features.hotkey_wlsw) | ||
1737 | return -ENODEV; | ||
1738 | |||
1468 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | 1739 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES |
1469 | if (dbg_wlswemul) { | 1740 | if (dbg_wlswemul) |
1470 | *status = !!tpacpi_wlsw_emulstate; | 1741 | return (tpacpi_wlsw_emulstate) ? |
1471 | return 0; | 1742 | TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; |
1472 | } | ||
1473 | #endif | 1743 | #endif |
1474 | if (!acpi_evalf(hkey_handle, status, "WLSW", "d")) | 1744 | |
1745 | if (!acpi_evalf(hkey_handle, &status, "WLSW", "d")) | ||
1475 | return -EIO; | 1746 | return -EIO; |
1476 | return 0; | 1747 | |
1748 | return (status) ? TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; | ||
1477 | } | 1749 | } |
1478 | 1750 | ||
1479 | static int hotkey_get_tablet_mode(int *status) | 1751 | static int hotkey_get_tablet_mode(int *status) |
@@ -2107,12 +2379,16 @@ static ssize_t hotkey_radio_sw_show(struct device *dev, | |||
2107 | struct device_attribute *attr, | 2379 | struct device_attribute *attr, |
2108 | char *buf) | 2380 | char *buf) |
2109 | { | 2381 | { |
2110 | int res, s; | 2382 | int res; |
2111 | res = hotkey_get_wlsw(&s); | 2383 | res = hotkey_get_wlsw(); |
2112 | if (res < 0) | 2384 | if (res < 0) |
2113 | return res; | 2385 | return res; |
2114 | 2386 | ||
2115 | return snprintf(buf, PAGE_SIZE, "%d\n", !!s); | 2387 | /* Opportunistic update */ |
2388 | tpacpi_rfk_update_hwblock_state((res == TPACPI_RFK_RADIO_OFF)); | ||
2389 | |||
2390 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
2391 | (res == TPACPI_RFK_RADIO_OFF) ? 0 : 1); | ||
2116 | } | 2392 | } |
2117 | 2393 | ||
2118 | static struct device_attribute dev_attr_hotkey_radio_sw = | 2394 | static struct device_attribute dev_attr_hotkey_radio_sw = |
@@ -2223,30 +2499,52 @@ static struct attribute *hotkey_mask_attributes[] __initdata = { | |||
2223 | &dev_attr_hotkey_wakeup_hotunplug_complete.attr, | 2499 | &dev_attr_hotkey_wakeup_hotunplug_complete.attr, |
2224 | }; | 2500 | }; |
2225 | 2501 | ||
2226 | static void bluetooth_update_rfk(void); | 2502 | /* |
2227 | static void wan_update_rfk(void); | 2503 | * Sync both the hw and sw blocking state of all switches |
2228 | static void uwb_update_rfk(void); | 2504 | */ |
2229 | static void tpacpi_send_radiosw_update(void) | 2505 | static void tpacpi_send_radiosw_update(void) |
2230 | { | 2506 | { |
2231 | int wlsw; | 2507 | int wlsw; |
2232 | 2508 | ||
2233 | /* Sync these BEFORE sending any rfkill events */ | 2509 | /* |
2234 | if (tp_features.bluetooth) | 2510 | * We must sync all rfkill controllers *before* issuing any |
2235 | bluetooth_update_rfk(); | 2511 | * rfkill input events, or we will race the rfkill core input |
2236 | if (tp_features.wan) | 2512 | * handler. |
2237 | wan_update_rfk(); | 2513 | * |
2238 | if (tp_features.uwb) | 2514 | * tpacpi_inputdev_send_mutex works as a syncronization point |
2239 | uwb_update_rfk(); | 2515 | * for the above. |
2516 | * | ||
2517 | * We optimize to avoid numerous calls to hotkey_get_wlsw. | ||
2518 | */ | ||
2240 | 2519 | ||
2241 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) { | 2520 | wlsw = hotkey_get_wlsw(); |
2521 | |||
2522 | /* Sync hw blocking state first if it is hw-blocked */ | ||
2523 | if (wlsw == TPACPI_RFK_RADIO_OFF) | ||
2524 | tpacpi_rfk_update_hwblock_state(true); | ||
2525 | |||
2526 | /* Sync sw blocking state */ | ||
2527 | tpacpi_rfk_update_swstate_all(); | ||
2528 | |||
2529 | /* Sync hw blocking state last if it is hw-unblocked */ | ||
2530 | if (wlsw == TPACPI_RFK_RADIO_ON) | ||
2531 | tpacpi_rfk_update_hwblock_state(false); | ||
2532 | |||
2533 | /* Issue rfkill input event for WLSW switch */ | ||
2534 | if (!(wlsw < 0)) { | ||
2242 | mutex_lock(&tpacpi_inputdev_send_mutex); | 2535 | mutex_lock(&tpacpi_inputdev_send_mutex); |
2243 | 2536 | ||
2244 | input_report_switch(tpacpi_inputdev, | 2537 | input_report_switch(tpacpi_inputdev, |
2245 | SW_RFKILL_ALL, !!wlsw); | 2538 | SW_RFKILL_ALL, (wlsw > 0)); |
2246 | input_sync(tpacpi_inputdev); | 2539 | input_sync(tpacpi_inputdev); |
2247 | 2540 | ||
2248 | mutex_unlock(&tpacpi_inputdev_send_mutex); | 2541 | mutex_unlock(&tpacpi_inputdev_send_mutex); |
2249 | } | 2542 | } |
2543 | |||
2544 | /* | ||
2545 | * this can be unconditional, as we will poll state again | ||
2546 | * if userspace uses the notify to read data | ||
2547 | */ | ||
2250 | hotkey_radio_sw_notify_change(); | 2548 | hotkey_radio_sw_notify_change(); |
2251 | } | 2549 | } |
2252 | 2550 | ||
@@ -3056,8 +3354,6 @@ enum { | |||
3056 | 3354 | ||
3057 | #define TPACPI_RFK_BLUETOOTH_SW_NAME "tpacpi_bluetooth_sw" | 3355 | #define TPACPI_RFK_BLUETOOTH_SW_NAME "tpacpi_bluetooth_sw" |
3058 | 3356 | ||
3059 | static struct rfkill *tpacpi_bluetooth_rfkill; | ||
3060 | |||
3061 | static void bluetooth_suspend(pm_message_t state) | 3357 | static void bluetooth_suspend(pm_message_t state) |
3062 | { | 3358 | { |
3063 | /* Try to make sure radio will resume powered off */ | 3359 | /* Try to make sure radio will resume powered off */ |
@@ -3067,83 +3363,47 @@ static void bluetooth_suspend(pm_message_t state) | |||
3067 | "bluetooth power down on resume request failed\n"); | 3363 | "bluetooth power down on resume request failed\n"); |
3068 | } | 3364 | } |
3069 | 3365 | ||
3070 | static int bluetooth_get_radiosw(void) | 3366 | static int bluetooth_get_status(void) |
3071 | { | 3367 | { |
3072 | int status; | 3368 | int status; |
3073 | 3369 | ||
3074 | if (!tp_features.bluetooth) | ||
3075 | return -ENODEV; | ||
3076 | |||
3077 | /* WLSW overrides bluetooth in firmware/hardware, reflect that */ | ||
3078 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) | ||
3079 | return RFKILL_STATE_HARD_BLOCKED; | ||
3080 | |||
3081 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | 3370 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES |
3082 | if (dbg_bluetoothemul) | 3371 | if (dbg_bluetoothemul) |
3083 | return (tpacpi_bluetooth_emulstate) ? | 3372 | return (tpacpi_bluetooth_emulstate) ? |
3084 | RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; | 3373 | TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; |
3085 | #endif | 3374 | #endif |
3086 | 3375 | ||
3087 | if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) | 3376 | if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) |
3088 | return -EIO; | 3377 | return -EIO; |
3089 | 3378 | ||
3090 | return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0) ? | 3379 | return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0) ? |
3091 | RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; | 3380 | TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; |
3092 | } | 3381 | } |
3093 | 3382 | ||
3094 | static void bluetooth_update_rfk(void) | 3383 | static int bluetooth_set_status(enum tpacpi_rfkill_state state) |
3095 | { | 3384 | { |
3096 | int status; | 3385 | int status; |
3097 | 3386 | ||
3098 | if (!tpacpi_bluetooth_rfkill) | ||
3099 | return; | ||
3100 | |||
3101 | status = bluetooth_get_radiosw(); | ||
3102 | if (status < 0) | ||
3103 | return; | ||
3104 | rfkill_force_state(tpacpi_bluetooth_rfkill, status); | ||
3105 | |||
3106 | vdbg_printk(TPACPI_DBG_RFKILL, | 3387 | vdbg_printk(TPACPI_DBG_RFKILL, |
3107 | "forced rfkill state to %d\n", | 3388 | "will attempt to %s bluetooth\n", |
3108 | status); | 3389 | (state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable"); |
3109 | } | ||
3110 | |||
3111 | static int bluetooth_set_radiosw(int radio_on, int update_rfk) | ||
3112 | { | ||
3113 | int status; | ||
3114 | |||
3115 | if (!tp_features.bluetooth) | ||
3116 | return -ENODEV; | ||
3117 | |||
3118 | /* WLSW overrides bluetooth in firmware/hardware, but there is no | ||
3119 | * reason to risk weird behaviour. */ | ||
3120 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status | ||
3121 | && radio_on) | ||
3122 | return -EPERM; | ||
3123 | |||
3124 | vdbg_printk(TPACPI_DBG_RFKILL, | ||
3125 | "will %s bluetooth\n", radio_on ? "enable" : "disable"); | ||
3126 | 3390 | ||
3127 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | 3391 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES |
3128 | if (dbg_bluetoothemul) { | 3392 | if (dbg_bluetoothemul) { |
3129 | tpacpi_bluetooth_emulstate = !!radio_on; | 3393 | tpacpi_bluetooth_emulstate = (state == TPACPI_RFK_RADIO_ON); |
3130 | if (update_rfk) | ||
3131 | bluetooth_update_rfk(); | ||
3132 | return 0; | 3394 | return 0; |
3133 | } | 3395 | } |
3134 | #endif | 3396 | #endif |
3135 | 3397 | ||
3136 | /* We make sure to keep TP_ACPI_BLUETOOTH_RESUMECTRL off */ | 3398 | /* We make sure to keep TP_ACPI_BLUETOOTH_RESUMECTRL off */ |
3137 | if (radio_on) | 3399 | if (state == TPACPI_RFK_RADIO_ON) |
3138 | status = TP_ACPI_BLUETOOTH_RADIOSSW; | 3400 | status = TP_ACPI_BLUETOOTH_RADIOSSW; |
3139 | else | 3401 | else |
3140 | status = 0; | 3402 | status = 0; |
3403 | |||
3141 | if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) | 3404 | if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) |
3142 | return -EIO; | 3405 | return -EIO; |
3143 | 3406 | ||
3144 | if (update_rfk) | ||
3145 | bluetooth_update_rfk(); | ||
3146 | |||
3147 | return 0; | 3407 | return 0; |
3148 | } | 3408 | } |
3149 | 3409 | ||
@@ -3152,35 +3412,16 @@ static ssize_t bluetooth_enable_show(struct device *dev, | |||
3152 | struct device_attribute *attr, | 3412 | struct device_attribute *attr, |
3153 | char *buf) | 3413 | char *buf) |
3154 | { | 3414 | { |
3155 | int status; | 3415 | return tpacpi_rfk_sysfs_enable_show(TPACPI_RFK_BLUETOOTH_SW_ID, |
3156 | 3416 | attr, buf); | |
3157 | printk_deprecated_rfkill_attribute("bluetooth_enable"); | ||
3158 | |||
3159 | status = bluetooth_get_radiosw(); | ||
3160 | if (status < 0) | ||
3161 | return status; | ||
3162 | |||
3163 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
3164 | (status == RFKILL_STATE_UNBLOCKED) ? 1 : 0); | ||
3165 | } | 3417 | } |
3166 | 3418 | ||
3167 | static ssize_t bluetooth_enable_store(struct device *dev, | 3419 | static ssize_t bluetooth_enable_store(struct device *dev, |
3168 | struct device_attribute *attr, | 3420 | struct device_attribute *attr, |
3169 | const char *buf, size_t count) | 3421 | const char *buf, size_t count) |
3170 | { | 3422 | { |
3171 | unsigned long t; | 3423 | return tpacpi_rfk_sysfs_enable_store(TPACPI_RFK_BLUETOOTH_SW_ID, |
3172 | int res; | 3424 | attr, buf, count); |
3173 | |||
3174 | printk_deprecated_rfkill_attribute("bluetooth_enable"); | ||
3175 | |||
3176 | if (parse_strtoul(buf, 1, &t)) | ||
3177 | return -EINVAL; | ||
3178 | |||
3179 | tpacpi_disclose_usertask("bluetooth_enable", "set to %ld\n", t); | ||
3180 | |||
3181 | res = bluetooth_set_radiosw(t, 1); | ||
3182 | |||
3183 | return (res) ? res : count; | ||
3184 | } | 3425 | } |
3185 | 3426 | ||
3186 | static struct device_attribute dev_attr_bluetooth_enable = | 3427 | static struct device_attribute dev_attr_bluetooth_enable = |
@@ -3198,23 +3439,10 @@ static const struct attribute_group bluetooth_attr_group = { | |||
3198 | .attrs = bluetooth_attributes, | 3439 | .attrs = bluetooth_attributes, |
3199 | }; | 3440 | }; |
3200 | 3441 | ||
3201 | static int tpacpi_bluetooth_rfk_get(void *data, enum rfkill_state *state) | 3442 | static const struct tpacpi_rfk_ops bluetooth_tprfk_ops = { |
3202 | { | 3443 | .get_status = bluetooth_get_status, |
3203 | int bts = bluetooth_get_radiosw(); | 3444 | .set_status = bluetooth_set_status, |
3204 | 3445 | }; | |
3205 | if (bts < 0) | ||
3206 | return bts; | ||
3207 | |||
3208 | *state = bts; | ||
3209 | return 0; | ||
3210 | } | ||
3211 | |||
3212 | static int tpacpi_bluetooth_rfk_set(void *data, enum rfkill_state state) | ||
3213 | { | ||
3214 | dbg_printk(TPACPI_DBG_RFKILL, | ||
3215 | "request to change radio state to %d\n", state); | ||
3216 | return bluetooth_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); | ||
3217 | } | ||
3218 | 3446 | ||
3219 | static void bluetooth_shutdown(void) | 3447 | static void bluetooth_shutdown(void) |
3220 | { | 3448 | { |
@@ -3230,13 +3458,12 @@ static void bluetooth_shutdown(void) | |||
3230 | 3458 | ||
3231 | static void bluetooth_exit(void) | 3459 | static void bluetooth_exit(void) |
3232 | { | 3460 | { |
3233 | bluetooth_shutdown(); | ||
3234 | |||
3235 | if (tpacpi_bluetooth_rfkill) | ||
3236 | rfkill_unregister(tpacpi_bluetooth_rfkill); | ||
3237 | |||
3238 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, | 3461 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, |
3239 | &bluetooth_attr_group); | 3462 | &bluetooth_attr_group); |
3463 | |||
3464 | tpacpi_destroy_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID); | ||
3465 | |||
3466 | bluetooth_shutdown(); | ||
3240 | } | 3467 | } |
3241 | 3468 | ||
3242 | static int __init bluetooth_init(struct ibm_init_struct *iibm) | 3469 | static int __init bluetooth_init(struct ibm_init_struct *iibm) |
@@ -3277,20 +3504,18 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) | |||
3277 | if (!tp_features.bluetooth) | 3504 | if (!tp_features.bluetooth) |
3278 | return 1; | 3505 | return 1; |
3279 | 3506 | ||
3280 | res = sysfs_create_group(&tpacpi_pdev->dev.kobj, | ||
3281 | &bluetooth_attr_group); | ||
3282 | if (res) | ||
3283 | return res; | ||
3284 | |||
3285 | res = tpacpi_new_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID, | 3507 | res = tpacpi_new_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID, |
3286 | &tpacpi_bluetooth_rfkill, | 3508 | &bluetooth_tprfk_ops, |
3287 | RFKILL_TYPE_BLUETOOTH, | 3509 | RFKILL_TYPE_BLUETOOTH, |
3288 | TPACPI_RFK_BLUETOOTH_SW_NAME, | 3510 | TPACPI_RFK_BLUETOOTH_SW_NAME, |
3289 | true, | 3511 | true); |
3290 | tpacpi_bluetooth_rfk_set, | 3512 | if (res) |
3291 | tpacpi_bluetooth_rfk_get); | 3513 | return res; |
3514 | |||
3515 | res = sysfs_create_group(&tpacpi_pdev->dev.kobj, | ||
3516 | &bluetooth_attr_group); | ||
3292 | if (res) { | 3517 | if (res) { |
3293 | bluetooth_exit(); | 3518 | tpacpi_destroy_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID); |
3294 | return res; | 3519 | return res; |
3295 | } | 3520 | } |
3296 | 3521 | ||
@@ -3300,46 +3525,12 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) | |||
3300 | /* procfs -------------------------------------------------------------- */ | 3525 | /* procfs -------------------------------------------------------------- */ |
3301 | static int bluetooth_read(char *p) | 3526 | static int bluetooth_read(char *p) |
3302 | { | 3527 | { |
3303 | int len = 0; | 3528 | return tpacpi_rfk_procfs_read(TPACPI_RFK_BLUETOOTH_SW_ID, p); |
3304 | int status = bluetooth_get_radiosw(); | ||
3305 | |||
3306 | if (!tp_features.bluetooth) | ||
3307 | len += sprintf(p + len, "status:\t\tnot supported\n"); | ||
3308 | else { | ||
3309 | len += sprintf(p + len, "status:\t\t%s\n", | ||
3310 | (status == RFKILL_STATE_UNBLOCKED) ? | ||
3311 | "enabled" : "disabled"); | ||
3312 | len += sprintf(p + len, "commands:\tenable, disable\n"); | ||
3313 | } | ||
3314 | |||
3315 | return len; | ||
3316 | } | 3529 | } |
3317 | 3530 | ||
3318 | static int bluetooth_write(char *buf) | 3531 | static int bluetooth_write(char *buf) |
3319 | { | 3532 | { |
3320 | char *cmd; | 3533 | return tpacpi_rfk_procfs_write(TPACPI_RFK_BLUETOOTH_SW_ID, buf); |
3321 | int state = -1; | ||
3322 | |||
3323 | if (!tp_features.bluetooth) | ||
3324 | return -ENODEV; | ||
3325 | |||
3326 | while ((cmd = next_cmd(&buf))) { | ||
3327 | if (strlencmp(cmd, "enable") == 0) { | ||
3328 | state = 1; | ||
3329 | } else if (strlencmp(cmd, "disable") == 0) { | ||
3330 | state = 0; | ||
3331 | } else | ||
3332 | return -EINVAL; | ||
3333 | } | ||
3334 | |||
3335 | if (state != -1) { | ||
3336 | tpacpi_disclose_usertask("procfs bluetooth", | ||
3337 | "attempt to %s\n", | ||
3338 | state ? "enable" : "disable"); | ||
3339 | bluetooth_set_radiosw(state, 1); | ||
3340 | } | ||
3341 | |||
3342 | return 0; | ||
3343 | } | 3534 | } |
3344 | 3535 | ||
3345 | static struct ibm_struct bluetooth_driver_data = { | 3536 | static struct ibm_struct bluetooth_driver_data = { |
@@ -3365,8 +3556,6 @@ enum { | |||
3365 | 3556 | ||
3366 | #define TPACPI_RFK_WWAN_SW_NAME "tpacpi_wwan_sw" | 3557 | #define TPACPI_RFK_WWAN_SW_NAME "tpacpi_wwan_sw" |
3367 | 3558 | ||
3368 | static struct rfkill *tpacpi_wan_rfkill; | ||
3369 | |||
3370 | static void wan_suspend(pm_message_t state) | 3559 | static void wan_suspend(pm_message_t state) |
3371 | { | 3560 | { |
3372 | /* Try to make sure radio will resume powered off */ | 3561 | /* Try to make sure radio will resume powered off */ |
@@ -3376,83 +3565,47 @@ static void wan_suspend(pm_message_t state) | |||
3376 | "WWAN power down on resume request failed\n"); | 3565 | "WWAN power down on resume request failed\n"); |
3377 | } | 3566 | } |
3378 | 3567 | ||
3379 | static int wan_get_radiosw(void) | 3568 | static int wan_get_status(void) |
3380 | { | 3569 | { |
3381 | int status; | 3570 | int status; |
3382 | 3571 | ||
3383 | if (!tp_features.wan) | ||
3384 | return -ENODEV; | ||
3385 | |||
3386 | /* WLSW overrides WWAN in firmware/hardware, reflect that */ | ||
3387 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) | ||
3388 | return RFKILL_STATE_HARD_BLOCKED; | ||
3389 | |||
3390 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | 3572 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES |
3391 | if (dbg_wwanemul) | 3573 | if (dbg_wwanemul) |
3392 | return (tpacpi_wwan_emulstate) ? | 3574 | return (tpacpi_wwan_emulstate) ? |
3393 | RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; | 3575 | TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; |
3394 | #endif | 3576 | #endif |
3395 | 3577 | ||
3396 | if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) | 3578 | if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) |
3397 | return -EIO; | 3579 | return -EIO; |
3398 | 3580 | ||
3399 | return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0) ? | 3581 | return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0) ? |
3400 | RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; | 3582 | TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; |
3401 | } | ||
3402 | |||
3403 | static void wan_update_rfk(void) | ||
3404 | { | ||
3405 | int status; | ||
3406 | |||
3407 | if (!tpacpi_wan_rfkill) | ||
3408 | return; | ||
3409 | |||
3410 | status = wan_get_radiosw(); | ||
3411 | if (status < 0) | ||
3412 | return; | ||
3413 | rfkill_force_state(tpacpi_wan_rfkill, status); | ||
3414 | |||
3415 | vdbg_printk(TPACPI_DBG_RFKILL, | ||
3416 | "forced rfkill state to %d\n", | ||
3417 | status); | ||
3418 | } | 3583 | } |
3419 | 3584 | ||
3420 | static int wan_set_radiosw(int radio_on, int update_rfk) | 3585 | static int wan_set_status(enum tpacpi_rfkill_state state) |
3421 | { | 3586 | { |
3422 | int status; | 3587 | int status; |
3423 | 3588 | ||
3424 | if (!tp_features.wan) | ||
3425 | return -ENODEV; | ||
3426 | |||
3427 | /* WLSW overrides bluetooth in firmware/hardware, but there is no | ||
3428 | * reason to risk weird behaviour. */ | ||
3429 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status | ||
3430 | && radio_on) | ||
3431 | return -EPERM; | ||
3432 | |||
3433 | vdbg_printk(TPACPI_DBG_RFKILL, | 3589 | vdbg_printk(TPACPI_DBG_RFKILL, |
3434 | "will %s WWAN\n", radio_on ? "enable" : "disable"); | 3590 | "will attempt to %s wwan\n", |
3591 | (state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable"); | ||
3435 | 3592 | ||
3436 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | 3593 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES |
3437 | if (dbg_wwanemul) { | 3594 | if (dbg_wwanemul) { |
3438 | tpacpi_wwan_emulstate = !!radio_on; | 3595 | tpacpi_wwan_emulstate = (state == TPACPI_RFK_RADIO_ON); |
3439 | if (update_rfk) | ||
3440 | wan_update_rfk(); | ||
3441 | return 0; | 3596 | return 0; |
3442 | } | 3597 | } |
3443 | #endif | 3598 | #endif |
3444 | 3599 | ||
3445 | /* We make sure to keep TP_ACPI_WANCARD_RESUMECTRL off */ | 3600 | /* We make sure to keep TP_ACPI_WANCARD_RESUMECTRL off */ |
3446 | if (radio_on) | 3601 | if (state == TPACPI_RFK_RADIO_ON) |
3447 | status = TP_ACPI_WANCARD_RADIOSSW; | 3602 | status = TP_ACPI_WANCARD_RADIOSSW; |
3448 | else | 3603 | else |
3449 | status = 0; | 3604 | status = 0; |
3605 | |||
3450 | if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) | 3606 | if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) |
3451 | return -EIO; | 3607 | return -EIO; |
3452 | 3608 | ||
3453 | if (update_rfk) | ||
3454 | wan_update_rfk(); | ||
3455 | |||
3456 | return 0; | 3609 | return 0; |
3457 | } | 3610 | } |
3458 | 3611 | ||
@@ -3461,35 +3614,16 @@ static ssize_t wan_enable_show(struct device *dev, | |||
3461 | struct device_attribute *attr, | 3614 | struct device_attribute *attr, |
3462 | char *buf) | 3615 | char *buf) |
3463 | { | 3616 | { |
3464 | int status; | 3617 | return tpacpi_rfk_sysfs_enable_show(TPACPI_RFK_WWAN_SW_ID, |
3465 | 3618 | attr, buf); | |
3466 | printk_deprecated_rfkill_attribute("wwan_enable"); | ||
3467 | |||
3468 | status = wan_get_radiosw(); | ||
3469 | if (status < 0) | ||
3470 | return status; | ||
3471 | |||
3472 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
3473 | (status == RFKILL_STATE_UNBLOCKED) ? 1 : 0); | ||
3474 | } | 3619 | } |
3475 | 3620 | ||
3476 | static ssize_t wan_enable_store(struct device *dev, | 3621 | static ssize_t wan_enable_store(struct device *dev, |
3477 | struct device_attribute *attr, | 3622 | struct device_attribute *attr, |
3478 | const char *buf, size_t count) | 3623 | const char *buf, size_t count) |
3479 | { | 3624 | { |
3480 | unsigned long t; | 3625 | return tpacpi_rfk_sysfs_enable_store(TPACPI_RFK_WWAN_SW_ID, |
3481 | int res; | 3626 | attr, buf, count); |
3482 | |||
3483 | printk_deprecated_rfkill_attribute("wwan_enable"); | ||
3484 | |||
3485 | if (parse_strtoul(buf, 1, &t)) | ||
3486 | return -EINVAL; | ||
3487 | |||
3488 | tpacpi_disclose_usertask("wwan_enable", "set to %ld\n", t); | ||
3489 | |||
3490 | res = wan_set_radiosw(t, 1); | ||
3491 | |||
3492 | return (res) ? res : count; | ||
3493 | } | 3627 | } |
3494 | 3628 | ||
3495 | static struct device_attribute dev_attr_wan_enable = | 3629 | static struct device_attribute dev_attr_wan_enable = |
@@ -3507,23 +3641,10 @@ static const struct attribute_group wan_attr_group = { | |||
3507 | .attrs = wan_attributes, | 3641 | .attrs = wan_attributes, |
3508 | }; | 3642 | }; |
3509 | 3643 | ||
3510 | static int tpacpi_wan_rfk_get(void *data, enum rfkill_state *state) | 3644 | static const struct tpacpi_rfk_ops wan_tprfk_ops = { |
3511 | { | 3645 | .get_status = wan_get_status, |
3512 | int wans = wan_get_radiosw(); | 3646 | .set_status = wan_set_status, |
3513 | 3647 | }; | |
3514 | if (wans < 0) | ||
3515 | return wans; | ||
3516 | |||
3517 | *state = wans; | ||
3518 | return 0; | ||
3519 | } | ||
3520 | |||
3521 | static int tpacpi_wan_rfk_set(void *data, enum rfkill_state state) | ||
3522 | { | ||
3523 | dbg_printk(TPACPI_DBG_RFKILL, | ||
3524 | "request to change radio state to %d\n", state); | ||
3525 | return wan_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); | ||
3526 | } | ||
3527 | 3648 | ||
3528 | static void wan_shutdown(void) | 3649 | static void wan_shutdown(void) |
3529 | { | 3650 | { |
@@ -3539,13 +3660,12 @@ static void wan_shutdown(void) | |||
3539 | 3660 | ||
3540 | static void wan_exit(void) | 3661 | static void wan_exit(void) |
3541 | { | 3662 | { |
3542 | wan_shutdown(); | ||
3543 | |||
3544 | if (tpacpi_wan_rfkill) | ||
3545 | rfkill_unregister(tpacpi_wan_rfkill); | ||
3546 | |||
3547 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, | 3663 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, |
3548 | &wan_attr_group); | 3664 | &wan_attr_group); |
3665 | |||
3666 | tpacpi_destroy_rfkill(TPACPI_RFK_WWAN_SW_ID); | ||
3667 | |||
3668 | wan_shutdown(); | ||
3549 | } | 3669 | } |
3550 | 3670 | ||
3551 | static int __init wan_init(struct ibm_init_struct *iibm) | 3671 | static int __init wan_init(struct ibm_init_struct *iibm) |
@@ -3584,20 +3704,19 @@ static int __init wan_init(struct ibm_init_struct *iibm) | |||
3584 | if (!tp_features.wan) | 3704 | if (!tp_features.wan) |
3585 | return 1; | 3705 | return 1; |
3586 | 3706 | ||
3587 | res = sysfs_create_group(&tpacpi_pdev->dev.kobj, | ||
3588 | &wan_attr_group); | ||
3589 | if (res) | ||
3590 | return res; | ||
3591 | |||
3592 | res = tpacpi_new_rfkill(TPACPI_RFK_WWAN_SW_ID, | 3707 | res = tpacpi_new_rfkill(TPACPI_RFK_WWAN_SW_ID, |
3593 | &tpacpi_wan_rfkill, | 3708 | &wan_tprfk_ops, |
3594 | RFKILL_TYPE_WWAN, | 3709 | RFKILL_TYPE_WWAN, |
3595 | TPACPI_RFK_WWAN_SW_NAME, | 3710 | TPACPI_RFK_WWAN_SW_NAME, |
3596 | true, | 3711 | true); |
3597 | tpacpi_wan_rfk_set, | 3712 | if (res) |
3598 | tpacpi_wan_rfk_get); | 3713 | return res; |
3714 | |||
3715 | res = sysfs_create_group(&tpacpi_pdev->dev.kobj, | ||
3716 | &wan_attr_group); | ||
3717 | |||
3599 | if (res) { | 3718 | if (res) { |
3600 | wan_exit(); | 3719 | tpacpi_destroy_rfkill(TPACPI_RFK_WWAN_SW_ID); |
3601 | return res; | 3720 | return res; |
3602 | } | 3721 | } |
3603 | 3722 | ||
@@ -3607,48 +3726,12 @@ static int __init wan_init(struct ibm_init_struct *iibm) | |||
3607 | /* procfs -------------------------------------------------------------- */ | 3726 | /* procfs -------------------------------------------------------------- */ |
3608 | static int wan_read(char *p) | 3727 | static int wan_read(char *p) |
3609 | { | 3728 | { |
3610 | int len = 0; | 3729 | return tpacpi_rfk_procfs_read(TPACPI_RFK_WWAN_SW_ID, p); |
3611 | int status = wan_get_radiosw(); | ||
3612 | |||
3613 | tpacpi_disclose_usertask("procfs wan", "read"); | ||
3614 | |||
3615 | if (!tp_features.wan) | ||
3616 | len += sprintf(p + len, "status:\t\tnot supported\n"); | ||
3617 | else { | ||
3618 | len += sprintf(p + len, "status:\t\t%s\n", | ||
3619 | (status == RFKILL_STATE_UNBLOCKED) ? | ||
3620 | "enabled" : "disabled"); | ||
3621 | len += sprintf(p + len, "commands:\tenable, disable\n"); | ||
3622 | } | ||
3623 | |||
3624 | return len; | ||
3625 | } | 3730 | } |
3626 | 3731 | ||
3627 | static int wan_write(char *buf) | 3732 | static int wan_write(char *buf) |
3628 | { | 3733 | { |
3629 | char *cmd; | 3734 | return tpacpi_rfk_procfs_write(TPACPI_RFK_WWAN_SW_ID, buf); |
3630 | int state = -1; | ||
3631 | |||
3632 | if (!tp_features.wan) | ||
3633 | return -ENODEV; | ||
3634 | |||
3635 | while ((cmd = next_cmd(&buf))) { | ||
3636 | if (strlencmp(cmd, "enable") == 0) { | ||
3637 | state = 1; | ||
3638 | } else if (strlencmp(cmd, "disable") == 0) { | ||
3639 | state = 0; | ||
3640 | } else | ||
3641 | return -EINVAL; | ||
3642 | } | ||
3643 | |||
3644 | if (state != -1) { | ||
3645 | tpacpi_disclose_usertask("procfs wan", | ||
3646 | "attempt to %s\n", | ||
3647 | state ? "enable" : "disable"); | ||
3648 | wan_set_radiosw(state, 1); | ||
3649 | } | ||
3650 | |||
3651 | return 0; | ||
3652 | } | 3735 | } |
3653 | 3736 | ||
3654 | static struct ibm_struct wan_driver_data = { | 3737 | static struct ibm_struct wan_driver_data = { |
@@ -3672,108 +3755,59 @@ enum { | |||
3672 | 3755 | ||
3673 | #define TPACPI_RFK_UWB_SW_NAME "tpacpi_uwb_sw" | 3756 | #define TPACPI_RFK_UWB_SW_NAME "tpacpi_uwb_sw" |
3674 | 3757 | ||
3675 | static struct rfkill *tpacpi_uwb_rfkill; | 3758 | static int uwb_get_status(void) |
3676 | |||
3677 | static int uwb_get_radiosw(void) | ||
3678 | { | 3759 | { |
3679 | int status; | 3760 | int status; |
3680 | 3761 | ||
3681 | if (!tp_features.uwb) | ||
3682 | return -ENODEV; | ||
3683 | |||
3684 | /* WLSW overrides UWB in firmware/hardware, reflect that */ | ||
3685 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) | ||
3686 | return RFKILL_STATE_HARD_BLOCKED; | ||
3687 | |||
3688 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | 3762 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES |
3689 | if (dbg_uwbemul) | 3763 | if (dbg_uwbemul) |
3690 | return (tpacpi_uwb_emulstate) ? | 3764 | return (tpacpi_uwb_emulstate) ? |
3691 | RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; | 3765 | TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; |
3692 | #endif | 3766 | #endif |
3693 | 3767 | ||
3694 | if (!acpi_evalf(hkey_handle, &status, "GUWB", "d")) | 3768 | if (!acpi_evalf(hkey_handle, &status, "GUWB", "d")) |
3695 | return -EIO; | 3769 | return -EIO; |
3696 | 3770 | ||
3697 | return ((status & TP_ACPI_UWB_RADIOSSW) != 0) ? | 3771 | return ((status & TP_ACPI_UWB_RADIOSSW) != 0) ? |
3698 | RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; | 3772 | TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; |
3699 | } | 3773 | } |
3700 | 3774 | ||
3701 | static void uwb_update_rfk(void) | 3775 | static int uwb_set_status(enum tpacpi_rfkill_state state) |
3702 | { | 3776 | { |
3703 | int status; | 3777 | int status; |
3704 | 3778 | ||
3705 | if (!tpacpi_uwb_rfkill) | ||
3706 | return; | ||
3707 | |||
3708 | status = uwb_get_radiosw(); | ||
3709 | if (status < 0) | ||
3710 | return; | ||
3711 | rfkill_force_state(tpacpi_uwb_rfkill, status); | ||
3712 | |||
3713 | vdbg_printk(TPACPI_DBG_RFKILL, | 3779 | vdbg_printk(TPACPI_DBG_RFKILL, |
3714 | "forced rfkill state to %d\n", | 3780 | "will attempt to %s UWB\n", |
3715 | status); | 3781 | (state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable"); |
3716 | } | ||
3717 | |||
3718 | static int uwb_set_radiosw(int radio_on, int update_rfk) | ||
3719 | { | ||
3720 | int status; | ||
3721 | |||
3722 | if (!tp_features.uwb) | ||
3723 | return -ENODEV; | ||
3724 | |||
3725 | /* WLSW overrides UWB in firmware/hardware, but there is no | ||
3726 | * reason to risk weird behaviour. */ | ||
3727 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status | ||
3728 | && radio_on) | ||
3729 | return -EPERM; | ||
3730 | |||
3731 | vdbg_printk(TPACPI_DBG_RFKILL, | ||
3732 | "will %s UWB\n", radio_on ? "enable" : "disable"); | ||
3733 | 3782 | ||
3734 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | 3783 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES |
3735 | if (dbg_uwbemul) { | 3784 | if (dbg_uwbemul) { |
3736 | tpacpi_uwb_emulstate = !!radio_on; | 3785 | tpacpi_uwb_emulstate = (state == TPACPI_RFK_RADIO_ON); |
3737 | if (update_rfk) | ||
3738 | uwb_update_rfk(); | ||
3739 | return 0; | 3786 | return 0; |
3740 | } | 3787 | } |
3741 | #endif | 3788 | #endif |
3742 | 3789 | ||
3743 | status = (radio_on) ? TP_ACPI_UWB_RADIOSSW : 0; | 3790 | if (state == TPACPI_RFK_RADIO_ON) |
3791 | status = TP_ACPI_UWB_RADIOSSW; | ||
3792 | else | ||
3793 | status = 0; | ||
3794 | |||
3744 | if (!acpi_evalf(hkey_handle, NULL, "SUWB", "vd", status)) | 3795 | if (!acpi_evalf(hkey_handle, NULL, "SUWB", "vd", status)) |
3745 | return -EIO; | 3796 | return -EIO; |
3746 | 3797 | ||
3747 | if (update_rfk) | ||
3748 | uwb_update_rfk(); | ||
3749 | |||
3750 | return 0; | 3798 | return 0; |
3751 | } | 3799 | } |
3752 | 3800 | ||
3753 | /* --------------------------------------------------------------------- */ | 3801 | /* --------------------------------------------------------------------- */ |
3754 | 3802 | ||
3755 | static int tpacpi_uwb_rfk_get(void *data, enum rfkill_state *state) | 3803 | static const struct tpacpi_rfk_ops uwb_tprfk_ops = { |
3756 | { | 3804 | .get_status = uwb_get_status, |
3757 | int uwbs = uwb_get_radiosw(); | 3805 | .set_status = uwb_set_status, |
3758 | 3806 | }; | |
3759 | if (uwbs < 0) | ||
3760 | return uwbs; | ||
3761 | |||
3762 | *state = uwbs; | ||
3763 | return 0; | ||
3764 | } | ||
3765 | |||
3766 | static int tpacpi_uwb_rfk_set(void *data, enum rfkill_state state) | ||
3767 | { | ||
3768 | dbg_printk(TPACPI_DBG_RFKILL, | ||
3769 | "request to change radio state to %d\n", state); | ||
3770 | return uwb_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); | ||
3771 | } | ||
3772 | 3807 | ||
3773 | static void uwb_exit(void) | 3808 | static void uwb_exit(void) |
3774 | { | 3809 | { |
3775 | if (tpacpi_uwb_rfkill) | 3810 | tpacpi_destroy_rfkill(TPACPI_RFK_UWB_SW_ID); |
3776 | rfkill_unregister(tpacpi_uwb_rfkill); | ||
3777 | } | 3811 | } |
3778 | 3812 | ||
3779 | static int __init uwb_init(struct ibm_init_struct *iibm) | 3813 | static int __init uwb_init(struct ibm_init_struct *iibm) |
@@ -3813,13 +3847,10 @@ static int __init uwb_init(struct ibm_init_struct *iibm) | |||
3813 | return 1; | 3847 | return 1; |
3814 | 3848 | ||
3815 | res = tpacpi_new_rfkill(TPACPI_RFK_UWB_SW_ID, | 3849 | res = tpacpi_new_rfkill(TPACPI_RFK_UWB_SW_ID, |
3816 | &tpacpi_uwb_rfkill, | 3850 | &uwb_tprfk_ops, |
3817 | RFKILL_TYPE_UWB, | 3851 | RFKILL_TYPE_UWB, |
3818 | TPACPI_RFK_UWB_SW_NAME, | 3852 | TPACPI_RFK_UWB_SW_NAME, |
3819 | false, | 3853 | false); |
3820 | tpacpi_uwb_rfk_set, | ||
3821 | tpacpi_uwb_rfk_get); | ||
3822 | |||
3823 | return res; | 3854 | return res; |
3824 | } | 3855 | } |
3825 | 3856 | ||
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 4345089f5171..81d31ea507d1 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c | |||
@@ -45,7 +45,6 @@ | |||
45 | #include <linux/backlight.h> | 45 | #include <linux/backlight.h> |
46 | #include <linux/platform_device.h> | 46 | #include <linux/platform_device.h> |
47 | #include <linux/rfkill.h> | 47 | #include <linux/rfkill.h> |
48 | #include <linux/input-polldev.h> | ||
49 | 48 | ||
50 | #include <asm/uaccess.h> | 49 | #include <asm/uaccess.h> |
51 | 50 | ||
@@ -250,21 +249,15 @@ static acpi_status hci_read2(u32 reg, u32 *out1, u32 *out2, u32 *result) | |||
250 | 249 | ||
251 | struct toshiba_acpi_dev { | 250 | struct toshiba_acpi_dev { |
252 | struct platform_device *p_dev; | 251 | struct platform_device *p_dev; |
253 | struct rfkill *rfk_dev; | 252 | struct rfkill *bt_rfk; |
254 | struct input_polled_dev *poll_dev; | ||
255 | 253 | ||
256 | const char *bt_name; | 254 | const char *bt_name; |
257 | const char *rfk_name; | ||
258 | |||
259 | bool last_rfk_state; | ||
260 | 255 | ||
261 | struct mutex mutex; | 256 | struct mutex mutex; |
262 | }; | 257 | }; |
263 | 258 | ||
264 | static struct toshiba_acpi_dev toshiba_acpi = { | 259 | static struct toshiba_acpi_dev toshiba_acpi = { |
265 | .bt_name = "Toshiba Bluetooth", | 260 | .bt_name = "Toshiba Bluetooth", |
266 | .rfk_name = "Toshiba RFKill Switch", | ||
267 | .last_rfk_state = false, | ||
268 | }; | 261 | }; |
269 | 262 | ||
270 | /* Bluetooth rfkill handlers */ | 263 | /* Bluetooth rfkill handlers */ |
@@ -283,21 +276,6 @@ static u32 hci_get_bt_present(bool *present) | |||
283 | return hci_result; | 276 | return hci_result; |
284 | } | 277 | } |
285 | 278 | ||
286 | static u32 hci_get_bt_on(bool *on) | ||
287 | { | ||
288 | u32 hci_result; | ||
289 | u32 value, value2; | ||
290 | |||
291 | value = 0; | ||
292 | value2 = 0x0001; | ||
293 | hci_read2(HCI_WIRELESS, &value, &value2, &hci_result); | ||
294 | if (hci_result == HCI_SUCCESS) | ||
295 | *on = (value & HCI_WIRELESS_BT_POWER) && | ||
296 | (value & HCI_WIRELESS_BT_ATTACH); | ||
297 | |||
298 | return hci_result; | ||
299 | } | ||
300 | |||
301 | static u32 hci_get_radio_state(bool *radio_state) | 279 | static u32 hci_get_radio_state(bool *radio_state) |
302 | { | 280 | { |
303 | u32 hci_result; | 281 | u32 hci_result; |
@@ -311,70 +289,67 @@ static u32 hci_get_radio_state(bool *radio_state) | |||
311 | return hci_result; | 289 | return hci_result; |
312 | } | 290 | } |
313 | 291 | ||
314 | static int bt_rfkill_toggle_radio(void *data, enum rfkill_state state) | 292 | static int bt_rfkill_set_block(void *data, bool blocked) |
315 | { | 293 | { |
294 | struct toshiba_acpi_dev *dev = data; | ||
316 | u32 result1, result2; | 295 | u32 result1, result2; |
317 | u32 value; | 296 | u32 value; |
297 | int err; | ||
318 | bool radio_state; | 298 | bool radio_state; |
319 | struct toshiba_acpi_dev *dev = data; | ||
320 | 299 | ||
321 | value = (state == RFKILL_STATE_UNBLOCKED); | 300 | value = (blocked == false); |
322 | 301 | ||
323 | if (hci_get_radio_state(&radio_state) != HCI_SUCCESS) | 302 | mutex_lock(&dev->mutex); |
324 | return -EFAULT; | 303 | if (hci_get_radio_state(&radio_state) != HCI_SUCCESS) { |
304 | err = -EBUSY; | ||
305 | goto out; | ||
306 | } | ||
325 | 307 | ||
326 | switch (state) { | 308 | if (!radio_state) { |
327 | case RFKILL_STATE_UNBLOCKED: | 309 | err = 0; |
328 | if (!radio_state) | 310 | goto out; |
329 | return -EPERM; | ||
330 | break; | ||
331 | case RFKILL_STATE_SOFT_BLOCKED: | ||
332 | break; | ||
333 | default: | ||
334 | return -EINVAL; | ||
335 | } | 311 | } |
336 | 312 | ||
337 | mutex_lock(&dev->mutex); | ||
338 | hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER, &result1); | 313 | hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER, &result1); |
339 | hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH, &result2); | 314 | hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH, &result2); |
340 | mutex_unlock(&dev->mutex); | ||
341 | 315 | ||
342 | if (result1 != HCI_SUCCESS || result2 != HCI_SUCCESS) | 316 | if (result1 != HCI_SUCCESS || result2 != HCI_SUCCESS) |
343 | return -EFAULT; | 317 | err = -EBUSY; |
344 | 318 | else | |
345 | return 0; | 319 | err = 0; |
320 | out: | ||
321 | mutex_unlock(&dev->mutex); | ||
322 | return err; | ||
346 | } | 323 | } |
347 | 324 | ||
348 | static void bt_poll_rfkill(struct input_polled_dev *poll_dev) | 325 | static void bt_rfkill_poll(struct rfkill *rfkill, void *data) |
349 | { | 326 | { |
350 | bool state_changed; | ||
351 | bool new_rfk_state; | 327 | bool new_rfk_state; |
352 | bool value; | 328 | bool value; |
353 | u32 hci_result; | 329 | u32 hci_result; |
354 | struct toshiba_acpi_dev *dev = poll_dev->private; | 330 | struct toshiba_acpi_dev *dev = data; |
331 | |||
332 | mutex_lock(&dev->mutex); | ||
355 | 333 | ||
356 | hci_result = hci_get_radio_state(&value); | 334 | hci_result = hci_get_radio_state(&value); |
357 | if (hci_result != HCI_SUCCESS) | 335 | if (hci_result != HCI_SUCCESS) { |
358 | return; /* Can't do anything useful */ | 336 | /* Can't do anything useful */ |
337 | mutex_unlock(&dev->mutex); | ||
338 | } | ||
359 | 339 | ||
360 | new_rfk_state = value; | 340 | new_rfk_state = value; |
361 | 341 | ||
362 | mutex_lock(&dev->mutex); | ||
363 | state_changed = new_rfk_state != dev->last_rfk_state; | ||
364 | dev->last_rfk_state = new_rfk_state; | ||
365 | mutex_unlock(&dev->mutex); | 342 | mutex_unlock(&dev->mutex); |
366 | 343 | ||
367 | if (unlikely(state_changed)) { | 344 | if (rfkill_set_hw_state(rfkill, !new_rfk_state)) |
368 | rfkill_force_state(dev->rfk_dev, | 345 | bt_rfkill_set_block(data, true); |
369 | new_rfk_state ? | ||
370 | RFKILL_STATE_SOFT_BLOCKED : | ||
371 | RFKILL_STATE_HARD_BLOCKED); | ||
372 | input_report_switch(poll_dev->input, SW_RFKILL_ALL, | ||
373 | new_rfk_state); | ||
374 | input_sync(poll_dev->input); | ||
375 | } | ||
376 | } | 346 | } |
377 | 347 | ||
348 | static const struct rfkill_ops toshiba_rfk_ops = { | ||
349 | .set_block = bt_rfkill_set_block, | ||
350 | .poll = bt_rfkill_poll, | ||
351 | }; | ||
352 | |||
378 | static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ; | 353 | static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ; |
379 | static struct backlight_device *toshiba_backlight_device; | 354 | static struct backlight_device *toshiba_backlight_device; |
380 | static int force_fan; | 355 | static int force_fan; |
@@ -702,14 +677,11 @@ static struct backlight_ops toshiba_backlight_data = { | |||
702 | 677 | ||
703 | static void toshiba_acpi_exit(void) | 678 | static void toshiba_acpi_exit(void) |
704 | { | 679 | { |
705 | if (toshiba_acpi.poll_dev) { | 680 | if (toshiba_acpi.bt_rfk) { |
706 | input_unregister_polled_device(toshiba_acpi.poll_dev); | 681 | rfkill_unregister(toshiba_acpi.bt_rfk); |
707 | input_free_polled_device(toshiba_acpi.poll_dev); | 682 | rfkill_destroy(toshiba_acpi.bt_rfk); |
708 | } | 683 | } |
709 | 684 | ||
710 | if (toshiba_acpi.rfk_dev) | ||
711 | rfkill_unregister(toshiba_acpi.rfk_dev); | ||
712 | |||
713 | if (toshiba_backlight_device) | 685 | if (toshiba_backlight_device) |
714 | backlight_device_unregister(toshiba_backlight_device); | 686 | backlight_device_unregister(toshiba_backlight_device); |
715 | 687 | ||
@@ -728,8 +700,6 @@ static int __init toshiba_acpi_init(void) | |||
728 | acpi_status status = AE_OK; | 700 | acpi_status status = AE_OK; |
729 | u32 hci_result; | 701 | u32 hci_result; |
730 | bool bt_present; | 702 | bool bt_present; |
731 | bool bt_on; | ||
732 | bool radio_on; | ||
733 | int ret = 0; | 703 | int ret = 0; |
734 | 704 | ||
735 | if (acpi_disabled) | 705 | if (acpi_disabled) |
@@ -793,60 +763,21 @@ static int __init toshiba_acpi_init(void) | |||
793 | 763 | ||
794 | /* Register rfkill switch for Bluetooth */ | 764 | /* Register rfkill switch for Bluetooth */ |
795 | if (hci_get_bt_present(&bt_present) == HCI_SUCCESS && bt_present) { | 765 | if (hci_get_bt_present(&bt_present) == HCI_SUCCESS && bt_present) { |
796 | toshiba_acpi.rfk_dev = rfkill_allocate(&toshiba_acpi.p_dev->dev, | 766 | toshiba_acpi.bt_rfk = rfkill_alloc(toshiba_acpi.bt_name, |
797 | RFKILL_TYPE_BLUETOOTH); | 767 | &toshiba_acpi.p_dev->dev, |
798 | if (!toshiba_acpi.rfk_dev) { | 768 | RFKILL_TYPE_BLUETOOTH, |
769 | &toshiba_rfk_ops, | ||
770 | &toshiba_acpi); | ||
771 | if (!toshiba_acpi.bt_rfk) { | ||
799 | printk(MY_ERR "unable to allocate rfkill device\n"); | 772 | printk(MY_ERR "unable to allocate rfkill device\n"); |
800 | toshiba_acpi_exit(); | 773 | toshiba_acpi_exit(); |
801 | return -ENOMEM; | 774 | return -ENOMEM; |
802 | } | 775 | } |
803 | 776 | ||
804 | toshiba_acpi.rfk_dev->name = toshiba_acpi.bt_name; | 777 | ret = rfkill_register(toshiba_acpi.bt_rfk); |
805 | toshiba_acpi.rfk_dev->toggle_radio = bt_rfkill_toggle_radio; | ||
806 | toshiba_acpi.rfk_dev->data = &toshiba_acpi; | ||
807 | |||
808 | if (hci_get_bt_on(&bt_on) == HCI_SUCCESS && bt_on) { | ||
809 | toshiba_acpi.rfk_dev->state = RFKILL_STATE_UNBLOCKED; | ||
810 | } else if (hci_get_radio_state(&radio_on) == HCI_SUCCESS && | ||
811 | radio_on) { | ||
812 | toshiba_acpi.rfk_dev->state = RFKILL_STATE_SOFT_BLOCKED; | ||
813 | } else { | ||
814 | toshiba_acpi.rfk_dev->state = RFKILL_STATE_HARD_BLOCKED; | ||
815 | } | ||
816 | |||
817 | ret = rfkill_register(toshiba_acpi.rfk_dev); | ||
818 | if (ret) { | 778 | if (ret) { |
819 | printk(MY_ERR "unable to register rfkill device\n"); | 779 | printk(MY_ERR "unable to register rfkill device\n"); |
820 | toshiba_acpi_exit(); | 780 | rfkill_destroy(toshiba_acpi.bt_rfk); |
821 | return -ENOMEM; | ||
822 | } | ||
823 | |||
824 | /* Register input device for kill switch */ | ||
825 | toshiba_acpi.poll_dev = input_allocate_polled_device(); | ||
826 | if (!toshiba_acpi.poll_dev) { | ||
827 | printk(MY_ERR | ||
828 | "unable to allocate kill-switch input device\n"); | ||
829 | toshiba_acpi_exit(); | ||
830 | return -ENOMEM; | ||
831 | } | ||
832 | toshiba_acpi.poll_dev->private = &toshiba_acpi; | ||
833 | toshiba_acpi.poll_dev->poll = bt_poll_rfkill; | ||
834 | toshiba_acpi.poll_dev->poll_interval = 1000; /* msecs */ | ||
835 | |||
836 | toshiba_acpi.poll_dev->input->name = toshiba_acpi.rfk_name; | ||
837 | toshiba_acpi.poll_dev->input->id.bustype = BUS_HOST; | ||
838 | /* Toshiba USB ID */ | ||
839 | toshiba_acpi.poll_dev->input->id.vendor = 0x0930; | ||
840 | set_bit(EV_SW, toshiba_acpi.poll_dev->input->evbit); | ||
841 | set_bit(SW_RFKILL_ALL, toshiba_acpi.poll_dev->input->swbit); | ||
842 | input_report_switch(toshiba_acpi.poll_dev->input, | ||
843 | SW_RFKILL_ALL, TRUE); | ||
844 | input_sync(toshiba_acpi.poll_dev->input); | ||
845 | |||
846 | ret = input_register_polled_device(toshiba_acpi.poll_dev); | ||
847 | if (ret) { | ||
848 | printk(MY_ERR | ||
849 | "unable to register kill-switch input device\n"); | ||
850 | toshiba_acpi_exit(); | 781 | toshiba_acpi_exit(); |
851 | return ret; | 782 | return ret; |
852 | } | 783 | } |