On Sunday, 13 of January 2008, Alan Stern wrote:
> On Sun, 13 Jan 2008, Michael Buesch wrote:
> 
> > > Besides, if you're going to register the device right back again during 
> > > the subsequent resume, then why go to the trouble of unregistering it 
> > > during suspend?  Why not just leave it registered the whole time and 
> > > avoid all the complication (and excess meaningless uevents)?
> > 
> > Well, because not doing it complicates code :)
> > Currently suspend/resume calls the same code as init/exit.
> > The b43 init/exit code is really complicated, compared to other
> > drivers, due to dozens of hardware versions. So I just avoided
> > having yet other codepaths for suspend/resume. But I will add
> > a flag to the device structure that's used to avoid unregistering stuff.
> 
> Instead of adding an extra flag you should refactor the code.  Have a
> common "enable" subroutine that can be called for both init and resume,
> and a common "disable" subroutine that can be called for both exit and
> suspend.  Then the method routines themselves will contain only the
> portions unique to their particular functions, making them shorter and
> simpler.

Well, it doesn't seem to be that easy.

I tried to fix the issue myself and finally obtained the appended, apparently
working, patch (against 2.6.24-rc8-mm1).  Well, it should have been a series
of patches against multiple subsystems, but I thought it would be instructive
to put everything needed into one bigger patch for starters.

Greetings,
Rafael

---
 drivers/base/power/main.c       |    1 
 drivers/base/power/power.h      |    1 
 drivers/char/hw_random/core.c   |   10 ++++-----
 drivers/char/misc.c             |   13 ++++++++----
 drivers/leds/led-class.c        |   13 ++++++++----
 drivers/net/wireless/b43/leds.c |   17 +++++++++------
 drivers/net/wireless/b43/leds.h |   14 +++++++++++--
 drivers/net/wireless/b43/main.c |   43 +++++++++++++++++++++++++++++-----------
 include/linux/device.h          |    6 +++++
 include/linux/hw_random.h       |   10 ++++++++-
 include/linux/leds.h            |   10 ++++++++-
 include/linux/miscdevice.h      |   10 ++++++++-
 12 files changed, 111 insertions(+), 37 deletions(-)

Index: linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/main.c
===================================================================
--- linux-2.6.24-rc8-mm1.orig/drivers/net/wireless/b43/main.c
+++ linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/main.c
@@ -2470,10 +2470,15 @@ static int b43_rng_read(struct hwrng *rn
        return (sizeof(u16));
 }
 
-static void b43_rng_exit(struct b43_wl *wl)
+static void __b43_rng_exit(struct b43_wl *wl, bool suspended)
 {
        if (wl->rng_initialized)
-               hwrng_unregister(&wl->rng);
+               __hwrng_unregister(&wl->rng, suspended);
+}
+
+static void b43_rng_exit(struct b43_wl *wl)
+{
+       __b43_rng_exit(wl, false);
 }
 
 static int b43_rng_init(struct b43_wl *wl)
@@ -3289,7 +3294,7 @@ static void b43_set_retry_limits(struct 
 
 /* Shutdown a wireless core */
 /* Locking: wl->mutex */
-static void b43_wireless_core_exit(struct b43_wldev *dev)
+static void __b43_wireless_core_exit(struct b43_wldev *dev, bool no_suspend)
 {
        struct b43_phy *phy = &dev->phy;
 
@@ -3298,8 +3303,10 @@ static void b43_wireless_core_exit(struc
                return;
        b43_set_status(dev, B43_STAT_UNINIT);
 
-       b43_leds_exit(dev);
-       b43_rng_exit(dev->wl);
+       if (no_suspend) {
+               b43_leds_exit(dev);
+               b43_rng_exit(dev->wl);
+       }
        b43_pio_free(dev);
        b43_dma_free(dev);
        b43_chip_exit(dev);
@@ -3313,8 +3320,13 @@ static void b43_wireless_core_exit(struc
        ssb_bus_may_powerdown(dev->dev->bus);
 }
 
+static void b43_wireless_core_exit(struct b43_wldev *dev)
+{
+       __b43_wireless_core_exit(dev, true);
+}
+
 /* Initialize a wireless core */
-static int b43_wireless_core_init(struct b43_wldev *dev)
+static int __b43_wireless_core_init(struct b43_wldev *dev, bool no_suspend)
 {
        struct b43_wl *wl = dev->wl;
        struct ssb_bus *bus = dev->dev->bus;
@@ -3420,11 +3432,13 @@ static int b43_wireless_core_init(struct
        memset(wl->mac_addr, 0, ETH_ALEN);
        b43_upload_card_macaddress(dev);
        b43_security_init(dev);
-       b43_rng_init(wl);
+       if (no_suspend)
+               b43_rng_init(wl);
 
        b43_set_status(dev, B43_STAT_INITIALIZED);
 
-       b43_leds_init(dev);
+       if (no_suspend)
+               b43_leds_init(dev);
 out:
        return err;
 
@@ -3442,6 +3456,11 @@ out:
        return err;
 }
 
+static int b43_wireless_core_init(struct b43_wldev *dev)
+{
+       return __b43_wireless_core_init(dev, true);
+}
+
 static int b43_op_add_interface(struct ieee80211_hw *hw,
                                struct ieee80211_if_init_conf *conf)
 {
@@ -4028,7 +4047,7 @@ static int b43_suspend(struct ssb_device
        if (wldev->suspend_init_status >= B43_STAT_STARTED)
                b43_wireless_core_stop(wldev);
        if (wldev->suspend_init_status >= B43_STAT_INITIALIZED)
-               b43_wireless_core_exit(wldev);
+               __b43_wireless_core_exit(wldev, false);
        mutex_unlock(&wl->mutex);
 
        b43dbg(wl, "Device suspended.\n");
@@ -4046,7 +4065,7 @@ static int b43_resume(struct ssb_device 
 
        mutex_lock(&wl->mutex);
        if (wldev->suspend_init_status >= B43_STAT_INITIALIZED) {
-               err = b43_wireless_core_init(wldev);
+               err = __b43_wireless_core_init(wldev, false);
                if (err) {
                        b43err(wl, "Resume failed at core init\n");
                        goto out;
@@ -4055,7 +4074,9 @@ static int b43_resume(struct ssb_device 
        if (wldev->suspend_init_status >= B43_STAT_STARTED) {
                err = b43_wireless_core_start(wldev);
                if (err) {
-                       b43_wireless_core_exit(wldev);
+                       b43_leds_resume_exit(wldev);
+                       __b43_rng_exit(wldev->wl, true);
+                       __b43_wireless_core_exit(wldev, false);
                        b43err(wl, "Resume failed at core start\n");
                        goto out;
                }
Index: linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/leds.h
===================================================================
--- linux-2.6.24-rc8-mm1.orig/drivers/net/wireless/b43/leds.h
+++ linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/leds.h
@@ -43,8 +43,15 @@ enum b43_led_behaviour {
 };
 
 void b43_leds_init(struct b43_wldev *dev);
-void b43_leds_exit(struct b43_wldev *dev);
-
+void __b43_leds_exit(struct b43_wldev *dev, bool suspended);
+static inline void b43_leds_exit(struct b43_wldev *dev)
+{
+       __b43_leds_exit(dev, false);
+}
+static inline void b43_leds_resume_exit(struct b43_wldev *dev)
+{
+       __b43_leds_exit(dev, true);
+}
 
 #else /* CONFIG_B43_LEDS */
 /* LED support disabled */
@@ -59,6 +66,9 @@ static inline void b43_leds_init(struct 
 static inline void b43_leds_exit(struct b43_wldev *dev)
 {
 }
+static inline void b43_leds_resume_exit(struct b43_wldev *dev)
+{
+}
 #endif /* CONFIG_B43_LEDS */
 
 #endif /* B43_LEDS_H_ */
Index: linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/leds.c
===================================================================
--- linux-2.6.24-rc8-mm1.orig/drivers/net/wireless/b43/leds.c
+++ linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/leds.c
@@ -112,11 +112,14 @@ static int b43_register_led(struct b43_w
        return 0;
 }
 
-static void b43_unregister_led(struct b43_led *led)
+static void b43_unregister_led(struct b43_led *led, bool suspended)
 {
        if (!led->dev)
                return;
-       led_classdev_unregister(&led->led_dev);
+       if (suspended)
+               led_classdev_unregister_suspended(&led->led_dev);
+       else
+               led_classdev_unregister(&led->led_dev);
        b43_led_turn_off(led->dev, led->index, led->activelow);
        led->dev = NULL;
 }
@@ -230,10 +233,10 @@ void b43_leds_init(struct b43_wldev *dev
        }
 }
 
-void b43_leds_exit(struct b43_wldev *dev)
+void __b43_leds_exit(struct b43_wldev *dev, bool suspended)
 {
-       b43_unregister_led(&dev->led_tx);
-       b43_unregister_led(&dev->led_rx);
-       b43_unregister_led(&dev->led_assoc);
-       b43_unregister_led(&dev->led_radio);
+       b43_unregister_led(&dev->led_tx, suspended);
+       b43_unregister_led(&dev->led_rx, suspended);
+       b43_unregister_led(&dev->led_assoc, suspended);
+       b43_unregister_led(&dev->led_radio, suspended);
 }
Index: linux-2.6.24-rc8-mm1/drivers/leds/led-class.c
===================================================================
--- linux-2.6.24-rc8-mm1.orig/drivers/leds/led-class.c
+++ linux-2.6.24-rc8-mm1/drivers/leds/led-class.c
@@ -137,12 +137,14 @@ err_out:
 EXPORT_SYMBOL_GPL(led_classdev_register);
 
 /**
- * led_classdev_unregister - unregisters a object of led_properties class.
+ * __led_classdev_unregister - unregisters a object of led_properties class.
  * @led_cdev: the led device to unregister
+ * @suspended: indicates whether system-wide suspend or resume is in progress
  *
  * Unregisters a previously registered via led_classdev_register object.
  */
-void led_classdev_unregister(struct led_classdev *led_cdev)
+void __led_classdev_unregister(struct led_classdev *led_cdev,
+                                     bool suspended)
 {
        device_remove_file(led_cdev->dev, &dev_attr_brightness);
 #ifdef CONFIG_LEDS_TRIGGERS
@@ -153,13 +155,16 @@ void led_classdev_unregister(struct led_
        up_write(&led_cdev->trigger_lock);
 #endif
 
-       device_unregister(led_cdev->dev);
+       if (suspended)
+               device_pm_schedule_removal(led_cdev->dev);
+       else
+               device_unregister(led_cdev->dev);
 
        down_write(&leds_list_lock);
        list_del(&led_cdev->node);
        up_write(&leds_list_lock);
 }
-EXPORT_SYMBOL_GPL(led_classdev_unregister);
+EXPORT_SYMBOL_GPL(__led_classdev_unregister);
 
 static int __init leds_init(void)
 {
Index: linux-2.6.24-rc8-mm1/include/linux/leds.h
===================================================================
--- linux-2.6.24-rc8-mm1.orig/include/linux/leds.h
+++ linux-2.6.24-rc8-mm1/include/linux/leds.h
@@ -59,7 +59,15 @@ struct led_classdev {
 
 extern int led_classdev_register(struct device *parent,
                                 struct led_classdev *led_cdev);
-extern void led_classdev_unregister(struct led_classdev *led_cdev);
+extern void __led_classdev_unregister(struct led_classdev *led_cdev, bool sus);
+static inline void led_classdev_unregister(struct led_classdev *lcd)
+{
+       __led_classdev_unregister(lcd, false);
+}
+static inline void led_classdev_unregister_suspended(struct led_classdev *lcd)
+{
+       __led_classdev_unregister(lcd, true);
+}
 extern void led_classdev_suspend(struct led_classdev *led_cdev);
 extern void led_classdev_resume(struct led_classdev *led_cdev);
 
Index: linux-2.6.24-rc8-mm1/drivers/base/power/main.c
===================================================================
--- linux-2.6.24-rc8-mm1.orig/drivers/base/power/main.c
+++ linux-2.6.24-rc8-mm1/drivers/base/power/main.c
@@ -129,6 +129,7 @@ void device_pm_schedule_removal(struct d
        list_move_tail(&dev->power.entry, &dpm_destroy);
        mutex_unlock(&dpm_list_mtx);
 }
+EXPORT_SYMBOL_GPL(device_pm_schedule_removal);
 
 /**
  *     pm_sleep_lock - mutual exclusion for registration and suspend
Index: linux-2.6.24-rc8-mm1/include/linux/device.h
===================================================================
--- linux-2.6.24-rc8-mm1.orig/include/linux/device.h
+++ linux-2.6.24-rc8-mm1/include/linux/device.h
@@ -532,11 +532,17 @@ extern struct device *device_create(stru
 extern void device_destroy(struct class *cls, dev_t devt);
 #ifdef CONFIG_PM_SLEEP
 extern void destroy_suspended_device(struct class *cls, dev_t devt);
+extern void device_pm_schedule_removal(struct device *);
 #else /* !CONFIG_PM_SLEEP */
 static inline void destroy_suspended_device(struct class *cls, dev_t devt)
 {
        device_destroy(cls, devt);
 }
+
+static inline void device_pm_schedule_removal(struct device *dev)
+{
+       device_unregister(dev);
+}
 #endif /* !CONFIG_PM_SLEEP */
 
 /*
Index: linux-2.6.24-rc8-mm1/drivers/base/power/power.h
===================================================================
--- linux-2.6.24-rc8-mm1.orig/drivers/base/power/power.h
+++ linux-2.6.24-rc8-mm1/drivers/base/power/power.h
@@ -13,7 +13,6 @@ static inline struct device *to_device(s
 
 extern void device_pm_add(struct device *);
 extern void device_pm_remove(struct device *);
-extern void device_pm_schedule_removal(struct device *);
 extern int pm_sleep_lock(void);
 extern void pm_sleep_unlock(void);
 
Index: linux-2.6.24-rc8-mm1/drivers/char/misc.c
===================================================================
--- linux-2.6.24-rc8-mm1.orig/drivers/char/misc.c
+++ linux-2.6.24-rc8-mm1/drivers/char/misc.c
@@ -232,8 +232,9 @@ int misc_register(struct miscdevice * mi
 }
 
 /**
- *     misc_deregister - unregister a miscellaneous device
+ *     __misc_deregister - unregister a miscellaneous device
  *     @misc: device to unregister
+ *     @suspended: to be set if the function is used during suspend/resume
  *
  *     Unregister a miscellaneous device that was previously
  *     successfully registered with misc_register(). Success
@@ -241,7 +242,7 @@ int misc_register(struct miscdevice * mi
  *     indicates an error.
  */
 
-int misc_deregister(struct miscdevice * misc)
+int __misc_deregister(struct miscdevice *misc, bool suspended)
 {
        int i = misc->minor;
 
@@ -250,7 +251,11 @@ int misc_deregister(struct miscdevice * 
 
        mutex_lock(&misc_mtx);
        list_del(&misc->list);
-       device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));
+       if (suspended)
+               destroy_suspended_device(misc_class,
+                                       MKDEV(MISC_MAJOR, misc->minor));
+       else
+               device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));
        if (i < DYNAMIC_MINORS && i>0) {
                misc_minors[i>>3] &= ~(1 << (misc->minor & 7));
        }
@@ -259,7 +264,7 @@ int misc_deregister(struct miscdevice * 
 }
 
 EXPORT_SYMBOL(misc_register);
-EXPORT_SYMBOL(misc_deregister);
+EXPORT_SYMBOL(__misc_deregister);
 
 static int __init misc_init(void)
 {
Index: linux-2.6.24-rc8-mm1/include/linux/miscdevice.h
===================================================================
--- linux-2.6.24-rc8-mm1.orig/include/linux/miscdevice.h
+++ linux-2.6.24-rc8-mm1/include/linux/miscdevice.h
@@ -43,7 +43,15 @@ struct miscdevice  {
 };
 
 extern int misc_register(struct miscdevice * misc);
-extern int misc_deregister(struct miscdevice * misc);
+extern int __misc_deregister(struct miscdevice *misc, bool suspended);
+static inline int misc_deregister(struct miscdevice *misc)
+{
+       return __misc_deregister(misc, false);
+}
+static inline int misc_deregister_suspended(struct miscdevice *misc)
+{
+       return __misc_deregister(misc, true);
+}
 
 #define MODULE_ALIAS_MISCDEV(minor)                            \
        MODULE_ALIAS("char-major-" __stringify(MISC_MAJOR)      \
Index: linux-2.6.24-rc8-mm1/drivers/char/hw_random/core.c
===================================================================
--- linux-2.6.24-rc8-mm1.orig/drivers/char/hw_random/core.c
+++ linux-2.6.24-rc8-mm1/drivers/char/hw_random/core.c
@@ -234,11 +234,11 @@ static DEVICE_ATTR(rng_available, S_IRUG
                   NULL);
 
 
-static void unregister_miscdev(void)
+static void unregister_miscdev(bool suspended)
 {
        device_remove_file(rng_miscdev.this_device, &dev_attr_rng_available);
        device_remove_file(rng_miscdev.this_device, &dev_attr_rng_current);
-       misc_deregister(&rng_miscdev);
+       __misc_deregister(&rng_miscdev, suspended);
 }
 
 static int register_miscdev(void)
@@ -313,7 +313,7 @@ out:
 }
 EXPORT_SYMBOL_GPL(hwrng_register);
 
-void hwrng_unregister(struct hwrng *rng)
+void __hwrng_unregister(struct hwrng *rng, bool suspended)
 {
        int err;
 
@@ -332,11 +332,11 @@ void hwrng_unregister(struct hwrng *rng)
                }
        }
        if (list_empty(&rng_list))
-               unregister_miscdev();
+               unregister_miscdev(suspended);
 
        mutex_unlock(&rng_mutex);
 }
-EXPORT_SYMBOL_GPL(hwrng_unregister);
+EXPORT_SYMBOL_GPL(__hwrng_unregister);
 
 
 MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver");
Index: linux-2.6.24-rc8-mm1/include/linux/hw_random.h
===================================================================
--- linux-2.6.24-rc8-mm1.orig/include/linux/hw_random.h
+++ linux-2.6.24-rc8-mm1/include/linux/hw_random.h
@@ -44,7 +44,15 @@ struct hwrng {
 /** Register a new Hardware Random Number Generator driver. */
 extern int hwrng_register(struct hwrng *rng);
 /** Unregister a Hardware Random Number Generator driver. */
-extern void hwrng_unregister(struct hwrng *rng);
+extern void __hwrng_unregister(struct hwrng *rng, bool suspended);
+static inline void hwrng_unregister(struct hwrng *rng)
+{
+       __hwrng_unregister(rng, false);
+}
+static inline void hwrng_unregister_suspended(struct hwrng *rng)
+{
+       __hwrng_unregister(rng, true);
+}
 
 #endif /* __KERNEL__ */
 #endif /* LINUX_HWRANDOM_H_ */
_______________________________________________
Bcm43xx-dev mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/bcm43xx-dev

Reply via email to