|
@@ -16,12 +16,15 @@
|
|
|
* 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,12 +533,10 @@ 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);
|