firewire: Add a bus reset event type for fw-device-cdev.
authorKristian Høgsberg <krh@redhat.com>
Wed, 7 Mar 2007 17:12:41 +0000 (12:12 -0500)
committerStefan Richter <stefanr@s5r6.in-berlin.de>
Fri, 9 Mar 2007 21:03:08 +0000 (22:03 +0100)
Signed-off-by: Kristian Høgsberg <krh@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
drivers/firewire/fw-device-cdev.c
drivers/firewire/fw-device-cdev.h
drivers/firewire/fw-device.c
drivers/firewire/fw-device.h

index 33fe5768a078a1b40962858b01d247ebb2c5b979..9f3c96c7af29d0b144b8e0cccc8b195d27d35fae 100644 (file)
@@ -50,6 +50,11 @@ struct event {
        struct list_head link;
 };
 
+struct bus_reset {
+       struct event event;
+       struct fw_cdev_event_bus_reset reset;
+};
+
 struct response {
        struct event event;
        struct fw_transaction transaction;
@@ -75,6 +80,8 @@ struct client {
        struct fw_iso_context *iso_context;
        struct fw_iso_buffer buffer;
        unsigned long vm_start;
+
+       struct list_head link;
 };
 
 static inline void __user *
@@ -93,6 +100,7 @@ static int fw_device_op_open(struct inode *inode, struct file *file)
 {
        struct fw_device *device;
        struct client *client;
+       unsigned long flags;
 
        device = container_of(inode->i_cdev, struct fw_device, cdev);
 
@@ -110,6 +118,10 @@ static int fw_device_op_open(struct inode *inode, struct file *file)
 
        file->private_data = client;
 
+       spin_lock_irqsave(&device->card->lock, flags);
+       list_add_tail(&client->link, &device->client_list);
+       spin_unlock_irqrestore(&device->card->lock, flags);
+
        return 0;
 }
 
@@ -177,6 +189,45 @@ fw_device_op_read(struct file *file,
        return dequeue_event(client, buffer, count);
 }
 
+static void
+queue_bus_reset_event(struct client *client)
+{
+       struct bus_reset *bus_reset;
+       struct fw_device *device = client->device;
+       struct fw_card *card = device->card;
+
+       bus_reset = kzalloc(sizeof *bus_reset, GFP_ATOMIC);
+       if (bus_reset == NULL) {
+               fw_notify("Out of memory when allocating bus reset event\n");
+               return;
+       }
+
+       bus_reset->reset.type          = FW_CDEV_EVENT_BUS_RESET;
+       bus_reset->reset.node_id       = device->node_id;
+       bus_reset->reset.local_node_id = card->local_node->node_id;
+       bus_reset->reset.bm_node_id    = 0; /* FIXME: We don't track the BM. */
+       bus_reset->reset.irm_node_id   = card->irm_node->node_id;
+       bus_reset->reset.root_node_id  = card->root_node->node_id;
+       bus_reset->reset.generation    = card->generation;
+
+       queue_event(client, &bus_reset->event,
+                   &bus_reset->reset, sizeof bus_reset->reset, NULL, 0);
+}
+
+void fw_device_cdev_update(struct fw_device *device)
+{
+       struct fw_card *card = device->card;
+       struct client *c;
+       unsigned long flags;
+
+       spin_lock_irqsave(&card->lock, flags);
+
+       list_for_each_entry(c, &device->client_list, link)
+               queue_bus_reset_event(c);
+
+       spin_unlock_irqrestore(&card->lock, flags);
+}
+
 static int ioctl_config_rom(struct client *client, void __user *arg)
 {
        struct fw_cdev_get_config_rom rom;
@@ -633,6 +684,7 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
        struct client *client = file->private_data;
        struct address_handler *h, *next;
        struct request *r, *next_r;
+       unsigned long flags;
 
        if (client->buffer.pages)
                fw_iso_buffer_destroy(&client->buffer, client->device->card);
@@ -657,6 +709,10 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
        while (!list_empty(&client->event_list))
                dequeue_event(client, NULL, 0);
 
+       spin_lock_irqsave(&client->device->card->lock, flags);
+       list_del(&client->link);
+       spin_unlock_irqrestore(&client->device->card->lock, flags);
+
        fw_device_put(client->device);
        kfree(client);
 
index 739f54fe08cf5b885b24e22db03958026428befa..4f94471b80789d0529b5b6f0c77c514c28dd03d7 100644 (file)
 #define SCODE_1600                     0x4
 #define SCODE_3200                     0x5
 
-#define FW_CDEV_EVENT_RESPONSE         0x00
-#define FW_CDEV_EVENT_REQUEST          0x01
-#define FW_CDEV_EVENT_ISO_INTERRUPT    0x02
+#define FW_CDEV_EVENT_BUS_RESET                0x00
+#define FW_CDEV_EVENT_RESPONSE         0x01
+#define FW_CDEV_EVENT_REQUEST          0x02
+#define FW_CDEV_EVENT_ISO_INTERRUPT    0x03
 
 /* The 'closure' fields are for user space to use.  Data passed in the
  * 'closure' field for a request will be returned in the corresponding
  * event.  It's a 64-bit type so that it's a fixed size type big
  * enough to hold a pointer on all platforms. */
 
+struct fw_cdev_event_bus_reset {
+       __u32 type;
+       __u32 node_id;
+       __u32 local_node_id;
+       __u32 bm_node_id;
+       __u32 irm_node_id;
+       __u32 root_node_id;
+       __u32 generation;
+};
+
 struct fw_cdev_event_response {
        __u32 type;
        __u32 rcode;
index 5599265da4a6a442ec1deb3a00656a47127dec67..ccc05e511a4f6b4372ffc3e6370f234d96e25a50 100644 (file)
@@ -535,6 +535,7 @@ static void fw_device_update(struct work_struct *work)
        struct fw_device *device =
                container_of(work, struct fw_device, work.work);
 
+       fw_device_cdev_update(device);
        device_for_each_child(&device->device, NULL, update_unit);
 }
 
@@ -564,6 +565,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
                device->node = fw_node_get(node);
                device->node_id = node->node_id;
                device->generation = card->generation;
+               INIT_LIST_HEAD(&device->client_list);
 
                /* Set the node data to point back to this device so
                 * FW_NODE_UPDATED callbacks can update the node_id
index 402a785ceedb79a44cf2f1391631f2888ef7aaf9..4f731c2b121ca02be8eff969012a9c673a9c05e5 100644 (file)
@@ -40,6 +40,7 @@ struct fw_device {
        struct fw_card *card;
        struct device device;
        struct cdev cdev;
+       struct list_head client_list;
        __be32 *config_rom;
        size_t config_rom_length;
        int config_rom_retries;
@@ -56,6 +57,8 @@ struct fw_device *fw_device_get(struct fw_device *device);
 void fw_device_put(struct fw_device *device);
 int fw_device_enable_phys_dma(struct fw_device *device);
 
+void fw_device_cdev_update(struct fw_device *device);
+
 struct fw_unit {
        struct device device;
        u32 *directory;