]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/firewire/fw-device.c
firewire: fix compiler warnings on 64bit
[mirror_ubuntu-artful-kernel.git] / drivers / firewire / fw-device.c
index 4fb5587252a9d5a1649d619c7c65e6057db56f32..a834221b7588568fbe094a498779e003abcd5472 100644 (file)
@@ -25,6 +25,9 @@
 #include <linux/kthread.h>
 #include <linux/device.h>
 #include <linux/delay.h>
+#include <linux/idr.h>
+#include <linux/rwsem.h>
+#include <asm/semaphore.h>
 #include "fw-transaction.h"
 #include "fw-topology.h"
 #include "fw-device.h"
@@ -145,14 +148,14 @@ fw_unit_uevent(struct device *dev, char **envp, int num_envp,
                           "MODALIAS=%s", modalias))
                return -ENOMEM;
 
     out:
+ out:
        envp[i] = NULL;
 
        return 0;
 }
 
 struct bus_type fw_bus_type = {
-       .name = "fw",
+       .name = "firewire",
        .match = fw_unit_match,
        .uevent = fw_unit_uevent,
 };
@@ -229,6 +232,22 @@ static struct device_attribute config_rom_attribute = {
        .show = show_config_rom_attribute,
 };
 
+static ssize_t
+show_rom_index_attribute(struct device *dev,
+                        struct device_attribute *attr, char *buf)
+{
+       struct fw_device *device = fw_device(dev->parent);
+       struct fw_unit *unit = fw_unit(dev);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+                       (int)(unit->directory - device->config_rom));
+}
+
+static struct device_attribute rom_index_attribute = {
+       .attr = { .name = "rom_index", .mode = S_IRUGO, },
+       .show = show_rom_index_attribute,
+};
+
 struct read_quadlet_callback_data {
        struct completion done;
        int rcode;
@@ -392,6 +411,11 @@ static void create_units(struct fw_device *device)
                        device_unregister(&unit->device);
                        kfree(unit);
                }
+
+               if (device_create_file(&unit->device, &rom_index_attribute) < 0) {
+                       device_unregister(&unit->device);
+                       kfree(unit);
+               }
        }
 }
 
@@ -407,14 +431,32 @@ static int shutdown_unit(struct device *device, void *data)
        return 0;
 }
 
+static DEFINE_IDR(fw_device_idr);
+int fw_cdev_major;
+
+struct fw_device *fw_device_from_devt(dev_t devt)
+{
+       struct fw_device *device;
+
+       down_read(&fw_bus_type.subsys.rwsem);
+       device = idr_find(&fw_device_idr, MINOR(devt));
+       up_read(&fw_bus_type.subsys.rwsem);
+
+       return device;
+}
+
 static void fw_device_shutdown(struct work_struct *work)
 {
        struct fw_device *device =
                container_of(work, struct fw_device, work.work);
+       int minor = MINOR(device->device.devt);
+
+       down_write(&fw_bus_type.subsys.rwsem);
+       idr_remove(&fw_device_idr, minor);
+       up_write(&fw_bus_type.subsys.rwsem);
 
+       fw_device_cdev_remove(device);
        device_remove_file(&device->device, &config_rom_attribute);
-       cdev_del(&device->cdev);
-       unregister_chrdev_region(device->device.devt, 1);
        device_for_each_child(&device->device, NULL, shutdown_unit);
        device_unregister(&device->device);
 }
@@ -434,9 +476,9 @@ static void fw_device_shutdown(struct work_struct *work)
 
 static void fw_device_init(struct work_struct *work)
 {
-       static int serial;
        struct fw_device *device =
                container_of(work, struct fw_device, work.work);
+       int minor, err;
 
        /* All failure paths here set node->data to NULL, so that we
         * don't try to do device_for_each_child() on a kfree()'d
@@ -449,33 +491,31 @@ static void fw_device_init(struct work_struct *work)
                } else {
                        fw_notify("giving up on config rom for node id %x\n",
                                  device->node_id);
+                       if (device->node == device->card->root_node)
+                               schedule_delayed_work(&device->card->work, 0);
                        fw_device_release(&device->device);
                }
                return;
        }
 
+       err = -ENOMEM;
+       down_write(&fw_bus_type.subsys.rwsem);
+       if (idr_pre_get(&fw_device_idr, GFP_KERNEL))
+               err = idr_get_new(&fw_device_idr, device, &minor);
+       up_write(&fw_bus_type.subsys.rwsem);
+       if (err < 0)
+               goto error;
+
        device->device.bus = &fw_bus_type;
        device->device.release = fw_device_release;
        device->device.parent = device->card->device;
+       device->device.devt = MKDEV(fw_cdev_major, minor);
        snprintf(device->device.bus_id, sizeof device->device.bus_id,
-                "fw%d", serial++);
-
-       if (alloc_chrdev_region(&device->device.devt, 0, 1, "fw")) {
-               fw_error("Failed to register char device region.\n");
-               goto error;
-       }
-
-       cdev_init(&device->cdev, &fw_device_ops);
-       device->cdev.owner = THIS_MODULE;
-       kobject_set_name(&device->cdev.kobj, device->device.bus_id);
-       if (cdev_add(&device->cdev, device->device.devt, 1)) {
-               fw_error("Failed to register char device.\n");
-               goto error;
-       }
+                "fw%d", minor);
 
        if (device_add(&device->device)) {
                fw_error("Failed to add device.\n");
-               goto error;
+               goto error_with_cdev;
        }
 
        if (device_create_file(&device->device, &config_rom_attribute) < 0) {
@@ -492,7 +532,7 @@ static void fw_device_init(struct work_struct *work)
         * necessary.  We have to use the atomic cmpxchg here to avoid
         * racing with the FW_NODE_DESTROYED case in
         * fw_node_event(). */
-       if (cmpxchg(&device->state,
+       if (atomic_cmpxchg(&device->state,
                    FW_DEVICE_INITIALIZING,
                    FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN)
                fw_device_shutdown(&device->work.work);
@@ -509,11 +549,13 @@ static void fw_device_init(struct work_struct *work)
 
        return;
 
     error_with_device:
+ error_with_device:
        device_del(&device->device);
-      error:
-       cdev_del(&device->cdev);
-       unregister_chrdev_region(device->device.devt, 1);
+ error_with_cdev:
+       down_write(&fw_bus_type.subsys.rwsem);
+       idr_remove(&fw_device_idr, minor);
+       up_write(&fw_bus_type.subsys.rwsem);
+ error:
        put_device(&device->device);
 }
 
@@ -522,21 +564,28 @@ static int update_unit(struct device *dev, void *data)
        struct fw_unit *unit = fw_unit(dev);
        struct fw_driver *driver = (struct fw_driver *)dev->driver;
 
-       if (is_fw_unit(dev) && driver != NULL && driver->update != NULL)
+       if (is_fw_unit(dev) && driver != NULL && driver->update != NULL) {
+               down(&dev->sem);
                driver->update(unit);
+               up(&dev->sem);
+       }
 
        return 0;
 }
 
+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);
+}
+
 void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
 {
        struct fw_device *device;
 
-       /* Ignore events for the local node (i.e. the node that
-        * corresponds to the ieee1394 controller in this linux box). */
-       if (node == card->local_node)
-               return;
-
        switch (event) {
        case FW_NODE_CREATED:
        case FW_NODE_LINK_ON:
@@ -554,11 +603,12 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
                 * device_for_each_child() in FW_NODE_UPDATED is
                 * doesn't freak out. */
                device_initialize(&device->device);
-               device->state = FW_DEVICE_INITIALIZING;
+               atomic_set(&device->state, FW_DEVICE_INITIALIZING);
                device->card = fw_card_get(card);
                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
@@ -580,7 +630,10 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
                device = node->data;
                device->node_id = node->node_id;
                device->generation = card->generation;
-               device_for_each_child(&device->device, NULL, update_unit);
+               if (atomic_read(&device->state) == FW_DEVICE_RUNNING) {
+                       PREPARE_DELAYED_WORK(&device->work, fw_device_update);
+                       schedule_delayed_work(&device->work, 0);
+               }
                break;
 
        case FW_NODE_DESTROYED:
@@ -599,9 +652,9 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
                 * the device in shutdown state to have that code fail
                 * to create the device. */
                device = node->data;
-               if (xchg(&device->state,
-                        FW_DEVICE_SHUTDOWN) == FW_DEVICE_RUNNING) {
-                       INIT_DELAYED_WORK(&device->work, fw_device_shutdown);
+               if (atomic_xchg(&device->state,
+                               FW_DEVICE_SHUTDOWN) == FW_DEVICE_RUNNING) {
+                       PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
                        schedule_delayed_work(&device->work, 0);
                }
                break;