void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) { clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); /* * Disable radio. */ rt2x00lib_disable_radio(rt2x00dev); /* * Stop all work. */ cancel_work_sync(&rt2x00dev->intf_work); cancel_work_sync(&rt2x00dev->rxdone_work); cancel_work_sync(&rt2x00dev->txdone_work); /* * Free the tx status fifo. */ kfifo_free(&rt2x00dev->txstatus_fifo); /* * Kill the tx status tasklet. */ tasklet_kill(&rt2x00dev->txstatus_tasklet); /* * Uninitialize device. */ rt2x00lib_uninitialize(rt2x00dev); /* * Free extra components */ rt2x00debug_deregister(rt2x00dev); rt2x00leds_unregister(rt2x00dev); /* * Free ieee80211_hw memory. */ rt2x00lib_remove_hw(rt2x00dev); /* * Free firmware image. */ rt2x00lib_free_firmware(rt2x00dev); /* * Free queue structures. */ rt2x00queue_free(rt2x00dev); }
int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state) { int retval; NOTICE(rt2x00dev, "Going to sleep.\n"); __clear_bit(DEVICE_PRESENT, &rt2x00dev->flags); /* * Only continue if mac80211 has open interfaces. */ if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags)) goto exit; __set_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags); /* * Disable radio. */ rt2x00lib_stop(rt2x00dev); rt2x00lib_uninitialize(rt2x00dev); /* * Suspend/disable extra components. */ rt2x00leds_suspend(rt2x00dev); rt2x00debug_deregister(rt2x00dev); exit: /* * Set device mode to sleep for power management, * on some hardware this call seems to consistently fail. * From the specifications it is hard to tell why it fails, * and if this is a "bad thing". * Overall it is safe to just ignore the failure and * continue suspending. The only downside is that the * device will not be in optimal power save mode, but with * the radio and the other components already disabled the * device is as good as disabled. */ retval = rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_SLEEP); if (retval) WARNING(rt2x00dev, "Device failed to enter sleep state, " "continue suspending.\n"); return 0; }
int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state) { NOTICE(rt2x00dev, "Going to sleep.\n"); /* * Prevent mac80211 from accessing driver while suspended. */ if (!test_and_clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) return 0; /* * Cleanup as much as possible. */ rt2x00lib_uninitialize(rt2x00dev); /* * Suspend/disable extra components. */ rt2x00leds_suspend(rt2x00dev); rt2x00debug_deregister(rt2x00dev); /* * Set device mode to sleep for power management, * on some hardware this call seems to consistently fail. * From the specifications it is hard to tell why it fails, * and if this is a "bad thing". * Overall it is safe to just ignore the failure and * continue suspending. The only downside is that the * device will not be in optimal power save mode, but with * the radio and the other components already disabled the * device is as good as disabled. */ if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_SLEEP)) WARNING(rt2x00dev, "Device failed to enter sleep state, " "continue suspending.\n"); return 0; }
void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) { __clear_bit(DEVICE_PRESENT, &rt2x00dev->flags); /* * Disable radio. */ rt2x00lib_disable_radio(rt2x00dev); /* * Uninitialize device. */ rt2x00lib_uninitialize(rt2x00dev); /* * Free extra components */ rt2x00debug_deregister(rt2x00dev); rt2x00rfkill_free(rt2x00dev); rt2x00leds_unregister(rt2x00dev); /* * Free ieee80211_hw memory. */ rt2x00lib_remove_hw(rt2x00dev); /* * Free firmware image. */ rt2x00lib_free_firmware(rt2x00dev); /* * Free queue structures. */ rt2x00queue_free(rt2x00dev); }
void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) { clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); /* * Disable radio. */ rt2x00lib_disable_radio(rt2x00dev); /* * Stop all work. */ cancel_work_sync(&rt2x00dev->intf_work); cancel_delayed_work_sync(&rt2x00dev->autowakeup_work); cancel_work_sync(&rt2x00dev->sleep_work); if (rt2x00_is_usb(rt2x00dev)) { hrtimer_cancel(&rt2x00dev->txstatus_timer); cancel_work_sync(&rt2x00dev->rxdone_work); cancel_work_sync(&rt2x00dev->txdone_work); } if (rt2x00dev->workqueue) destroy_workqueue(rt2x00dev->workqueue); /* * Free the tx status fifo. */ kfifo_free(&rt2x00dev->txstatus_fifo); /* * Kill the tx status tasklet. */ tasklet_kill(&rt2x00dev->txstatus_tasklet); tasklet_kill(&rt2x00dev->pretbtt_tasklet); tasklet_kill(&rt2x00dev->tbtt_tasklet); tasklet_kill(&rt2x00dev->rxdone_tasklet); tasklet_kill(&rt2x00dev->autowake_tasklet); /* * Uninitialize device. */ rt2x00lib_uninitialize(rt2x00dev); /* * Free extra components */ rt2x00debug_deregister(rt2x00dev); rt2x00leds_unregister(rt2x00dev); /* * Free ieee80211_hw memory. */ rt2x00lib_remove_hw(rt2x00dev); /* * Free firmware image. */ rt2x00lib_free_firmware(rt2x00dev); /* * Free queue structures. */ rt2x00queue_free(rt2x00dev); /* * Free the driver data. */ if (rt2x00dev->drv_data) kfree(rt2x00dev->drv_data); }
int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) { int retval; NOTICE(rt2x00dev, "Waking up.\n"); /* * Restore/enable extra components. */ rt2x00debug_register(rt2x00dev); rt2x00leds_resume(rt2x00dev); /* * Only continue if mac80211 had open interfaces. */ if (!__test_and_clear_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags)) return 0; /* * Reinitialize device and all active interfaces. */ retval = rt2x00lib_start(rt2x00dev); if (retval) goto exit; /* * Reconfigure device. */ retval = rt2x00mac_config(rt2x00dev->hw, &rt2x00dev->hw->conf); if (retval) goto exit; /* * Iterator over each active interface to * reconfigure the hardware. */ ieee80211_iterate_active_interfaces(rt2x00dev->hw, rt2x00lib_resume_intf, rt2x00dev); /* * We are ready again to receive requests from mac80211. */ __set_bit(DEVICE_PRESENT, &rt2x00dev->flags); /* * It is possible that during that mac80211 has attempted * to send frames while we were suspending or resuming. * In that case we have disabled the TX queue and should * now enable it again */ ieee80211_wake_queues(rt2x00dev->hw); /* * During interface iteration we might have changed the * delayed_flags, time to handles the event by calling * the work handler directly. */ rt2x00lib_intf_scheduled(&rt2x00dev->intf_work); return 0; exit: rt2x00lib_disable_radio(rt2x00dev); rt2x00lib_uninitialize(rt2x00dev); rt2x00debug_deregister(rt2x00dev); return retval; }
void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) { const struct rt2x00debug *debug = rt2x00dev->ops->debugfs; struct rt2x00debug_intf *intf; intf = kzalloc(sizeof(struct rt2x00debug_intf), GFP_KERNEL); if (!intf) return; intf->debug = debug; intf->rt2x00dev = rt2x00dev; rt2x00dev->debugfs_intf = intf; intf->driver_folder = debugfs_create_dir(DRIVER_NAME, NULL); if (IS_ERR(intf->driver_folder)) goto exit; intf->driver_entry = rt2x00debug_create_file_driver("driver", intf, &intf->driver_blob); if (IS_ERR(intf->driver_entry)) goto exit; intf->chipset_entry = rt2x00debug_create_file_chipset("chipset", intf, &intf->chipset_blob); if (IS_ERR(intf->chipset_entry)) goto exit; #define RT2X00DEBUGFS_CREATE_ENTRY(__intf, __name) \ ({ \ (__intf)->__name##_off_entry = \ debugfs_create_u32(__stringify(__name) "_offset", \ S_IRUGO | S_IWUSR, \ (__intf)->driver_folder, \ &(__intf)->offset_##__name); \ if (IS_ERR((__intf)->__name##_off_entry)) \ goto exit; \ \ (__intf)->__name##_val_entry = \ debugfs_create_file(__stringify(__name) "_value", \ S_IRUGO | S_IWUSR, \ (__intf)->driver_folder, \ (__intf), &rt2x00debug_fop_##__name);\ if (IS_ERR((__intf)->__name##_val_entry)) \ goto exit; \ }) RT2X00DEBUGFS_CREATE_ENTRY(intf, csr); RT2X00DEBUGFS_CREATE_ENTRY(intf, eeprom); RT2X00DEBUGFS_CREATE_ENTRY(intf, bbp); RT2X00DEBUGFS_CREATE_ENTRY(intf, rf); #undef RT2X00DEBUGFS_CREATE_ENTRY return; exit: rt2x00debug_deregister(rt2x00dev); return; }