]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/firewire/fw-card.c
Merge branch 'r8169-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/romieu...
[linux-2.6-omap-h63xx.git] / drivers / firewire / fw-card.c
index 1332b66ae0b395fd485c9ec9671db33e1289f72a..bbd73a406e537106a2eeda4ba4a2ba1a543b030d 100644 (file)
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-#include <linux/module.h>
-#include <linux/errno.h>
+#include <linux/completion.h>
+#include <linux/crc-itu-t.h>
 #include <linux/delay.h>
 #include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kref.h>
+#include <linux/module.h>
 #include <linux/mutex.h>
-#include <linux/crc-itu-t.h>
+
 #include "fw-transaction.h"
 #include "fw-topology.h"
 #include "fw-device.h"
@@ -396,7 +399,6 @@ fw_card_initialize(struct fw_card *card, const struct fw_card_driver *driver,
 {
        static atomic_t index = ATOMIC_INIT(-1);
 
-       atomic_set(&card->device_count, 0);
        card->index = atomic_inc_return(&index);
        card->driver = driver;
        card->device = device;
@@ -405,6 +407,8 @@ fw_card_initialize(struct fw_card *card, const struct fw_card_driver *driver,
        card->color = 0;
        card->broadcast_channel = BROADCAST_CHANNEL_INITIAL;
 
+       kref_init(&card->kref);
+       init_completion(&card->done);
        INIT_LIST_HEAD(&card->transaction_list);
        spin_lock_init(&card->lock);
        setup_timer(&card->flush_timer,
@@ -506,6 +510,14 @@ static struct fw_card_driver dummy_driver = {
        .enable_phys_dma = dummy_enable_phys_dma,
 };
 
+void
+fw_card_release(struct kref *kref)
+{
+       struct fw_card *card = container_of(kref, struct fw_card, kref);
+
+       complete(&card->done);
+}
+
 void
 fw_core_remove_card(struct fw_card *card)
 {
@@ -521,15 +533,13 @@ fw_core_remove_card(struct fw_card *card)
        card->driver = &dummy_driver;
 
        fw_destroy_nodes(card);
-       /*
-        * Wait for all device workqueue jobs to finish.  Otherwise the
-        * firewire-core module could be unloaded before the jobs ran.
-        */
-       while (atomic_read(&card->device_count) > 0)
-               msleep(100);
+
+       /* Wait for all users, especially device workqueue jobs, to finish. */
+       fw_card_put(card);
+       wait_for_completion(&card->done);
 
        cancel_delayed_work_sync(&card->work);
-       fw_flush_transactions(card);
+       WARN_ON(!list_empty(&card->transaction_list));
        del_timer_sync(&card->flush_timer);
 }
 EXPORT_SYMBOL(fw_core_remove_card);