firewire: Add device probing and sysfs integration.

Signed-off-by: Kristian Høgsberg <krh@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
diff --git a/drivers/firewire/fw-card.c b/drivers/firewire/fw-card.c
index d8abd70..7977390 100644
--- a/drivers/firewire/fw-card.c
+++ b/drivers/firewire/fw-card.c
@@ -24,6 +24,7 @@
 #include <linux/device.h>
 #include "fw-transaction.h"
 #include "fw-topology.h"
+#include "fw-device.h"
 
 /* The lib/crc16.c implementation uses the standard (0x8005)
  * polynomial, but we need the ITU-T (or CCITT) polynomial (0x1021).
@@ -186,6 +187,59 @@
 EXPORT_SYMBOL(fw_core_remove_descriptor);
 
 static void
+fw_card_irm_work(struct work_struct *work)
+{
+	struct fw_card *card =
+		container_of(work, struct fw_card, work.work);
+	struct fw_device *root;
+	unsigned long flags;
+	int new_irm_id, generation;
+
+	/* FIXME: This simple bus management unconditionally picks a
+	 * cycle master if the current root can't do it.  We need to
+	 * not do this if there is a bus manager already.  Also, some
+	 * hubs set the contender bit, which is bogus, so we should
+	 * probably do a little sanity check on the IRM (like, read
+	 * the bandwidth register) if it's not us. */
+
+	spin_lock_irqsave(&card->lock, flags);
+
+	generation = card->generation;
+	root = card->root_node->data;
+
+	if (root == NULL)
+		/* Either link_on is false, or we failed to read the
+		 * config rom.  In either case, pick another root. */
+		new_irm_id = card->local_node->node_id;
+	else if (root->state != FW_DEVICE_RUNNING)
+		/* If we haven't probed this device yet, bail out now
+		 * and let's try again once that's done. */
+		new_irm_id = -1;
+	else if (root->config_rom[2] & bib_cmc)
+		/* FIXME: I suppose we should set the cmstr bit in the
+		 * STATE_CLEAR register of this node, as described in
+		 * 1394-1995, 8.4.2.6.  Also, send out a force root
+		 * packet for this node. */
+		new_irm_id = -1;
+	else
+		/* Current root has an active link layer and we
+		 * successfully read the config rom, but it's not
+		 * cycle master capable. */
+		new_irm_id = card->local_node->node_id;
+
+	if (card->irm_retries++ > 5)
+		new_irm_id = -1;
+
+	spin_unlock_irqrestore(&card->lock, flags);
+
+	if (new_irm_id > 0) {
+		fw_notify("Trying to become root (card %d)\n", card->index);
+		fw_send_force_root(card, new_irm_id, generation);
+		fw_core_initiate_bus_reset(card, 1);
+	}
+}
+
+static void
 release_card(struct device *device)
 {
 	struct fw_card *card =
@@ -222,6 +276,8 @@
 
 	card->local_node = NULL;
 
+	INIT_DELAYED_WORK(&card->work, fw_card_irm_work);
+
 	card->card_device.bus     = &fw_bus_type;
 	card->card_device.release = release_card;
 	card->card_device.parent  = card->device;