]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/firewire/fw-device.c
firewire: don't use extern on public symbols
[linux-2.6-omap-h63xx.git] / drivers / firewire / fw-device.c
index 4ade867db88800fd71ebc2d2f893bf1f513a69b0..99d1c418d2b0daf0820775dd2c3bdd040cede06a 100644 (file)
@@ -26,6 +26,9 @@
 #include <linux/device.h>
 #include <linux/delay.h>
 #include <linux/idr.h>
+#include <linux/rwsem.h>
+#include <asm/semaphore.h>
+#include <linux/ctype.h>
 #include "fw-transaction.h"
 #include "fw-topology.h"
 #include "fw-device.h"
@@ -136,9 +139,6 @@ fw_unit_uevent(struct device *dev, char **envp, int num_envp,
        int length = 0;
        int i = 0;
 
-       if (!is_fw_unit(dev))
-               goto out;
-
        get_modalias(unit, modalias, sizeof modalias);
 
        if (add_uevent_var(envp, num_envp, &i,
@@ -146,7 +146,6 @@ fw_unit_uevent(struct device *dev, char **envp, int num_envp,
                           "MODALIAS=%s", modalias))
                return -ENOMEM;
 
- out:
        envp[i] = NULL;
 
        return 0;
@@ -155,18 +154,17 @@ fw_unit_uevent(struct device *dev, char **envp, int num_envp,
 struct bus_type fw_bus_type = {
        .name = "firewire",
        .match = fw_unit_match,
-       .uevent = fw_unit_uevent,
 };
 EXPORT_SYMBOL(fw_bus_type);
 
-extern struct fw_device *fw_device_get(struct fw_device *device)
+struct fw_device *fw_device_get(struct fw_device *device)
 {
        get_device(&device->device);
 
        return device;
 }
 
-extern void fw_device_put(struct fw_device *device)
+void fw_device_put(struct fw_device *device)
 {
        put_device(&device->device);
 }
@@ -196,9 +194,129 @@ int fw_device_enable_phys_dma(struct fw_device *device)
 }
 EXPORT_SYMBOL(fw_device_enable_phys_dma);
 
+struct config_rom_attribute {
+       struct device_attribute attr;
+       u32 key;
+};
+
+static ssize_t
+show_immediate(struct device *dev, struct device_attribute *dattr, char *buf)
+{
+       struct config_rom_attribute *attr =
+               container_of(dattr, struct config_rom_attribute, attr);
+       struct fw_csr_iterator ci;
+       u32 *dir;
+       int key, value;
+
+       if (is_fw_unit(dev))
+               dir = fw_unit(dev)->directory;
+       else
+               dir = fw_device(dev)->config_rom + 5;
+
+       fw_csr_iterator_init(&ci, dir);
+       while (fw_csr_iterator_next(&ci, &key, &value))
+               if (attr->key == key)
+                       return snprintf(buf, buf ? PAGE_SIZE : 0,
+                                       "0x%06x\n", value);
+
+       return -ENOENT;
+}
+
+#define IMMEDIATE_ATTR(name, key)                              \
+       { __ATTR(name, S_IRUGO, show_immediate, NULL), key }
+
 static ssize_t
-show_modalias_attribute(struct device *dev,
-                       struct device_attribute *attr, char *buf)
+show_text_leaf(struct device *dev, struct device_attribute *dattr, char *buf)
+{
+       struct config_rom_attribute *attr =
+               container_of(dattr, struct config_rom_attribute, attr);
+       struct fw_csr_iterator ci;
+       u32 *dir, *block = NULL, *p, *end;
+       int length, key, value, last_key = 0;
+       char *b;
+
+       if (is_fw_unit(dev))
+               dir = fw_unit(dev)->directory;
+       else
+               dir = fw_device(dev)->config_rom + 5;
+
+       fw_csr_iterator_init(&ci, dir);
+       while (fw_csr_iterator_next(&ci, &key, &value)) {
+               if (attr->key == last_key &&
+                   key == (CSR_DESCRIPTOR | CSR_LEAF))
+                       block = ci.p - 1 + value;
+               last_key = key;
+       }
+
+       if (block == NULL)
+               return -ENOENT;
+
+       length = min(block[0] >> 16, 256U);
+       if (length < 3)
+               return -ENOENT;
+
+       if (block[1] != 0 || block[2] != 0)
+               /* Unknown encoding. */
+               return -ENOENT;
+
+       if (buf == NULL)
+               return length * 4;
+
+       b = buf;
+       end = &block[length + 1];
+       for (p = &block[3]; p < end; p++, b += 4)
+               * (u32 *) b = (__force u32) __cpu_to_be32(*p);
+
+       /* Strip trailing whitespace and add newline. */
+       while (b--, (isspace(*b) || *b == '\0') && b > buf);
+       strcpy(b + 1, "\n");
+
+       return b + 2 - buf;
+}
+
+#define TEXT_LEAF_ATTR(name, key)                              \
+       { __ATTR(name, S_IRUGO, show_text_leaf, NULL), key }
+
+static struct config_rom_attribute config_rom_attributes[] = {
+       IMMEDIATE_ATTR(vendor, CSR_VENDOR),
+       IMMEDIATE_ATTR(hardware_version, CSR_HARDWARE_VERSION),
+       IMMEDIATE_ATTR(specifier_id, CSR_SPECIFIER_ID),
+       IMMEDIATE_ATTR(version, CSR_VERSION),
+       IMMEDIATE_ATTR(model, CSR_MODEL),
+       TEXT_LEAF_ATTR(vendor_name, CSR_VENDOR),
+       TEXT_LEAF_ATTR(model_name, CSR_MODEL),
+       TEXT_LEAF_ATTR(hardware_version_name, CSR_HARDWARE_VERSION),
+};
+
+static void
+init_fw_attribute_group(struct device *dev,
+                       struct device_attribute *attrs,
+                       struct fw_attribute_group *group)
+{
+       struct device_attribute *attr;
+       int i, j;
+
+       for (j = 0; attrs[j].attr.name != NULL; j++)
+               group->attrs[j] = &attrs[j].attr;
+
+       for (i = 0; i < ARRAY_SIZE(config_rom_attributes); i++) {
+               attr = &config_rom_attributes[i].attr;
+               if (attr->show(dev, attr, NULL) < 0)
+                       continue;
+               group->attrs[j++] = &attr->attr;
+       }
+
+       BUG_ON(j >= ARRAY_SIZE(group->attrs));
+       group->attrs[j++] = NULL;
+       group->groups[0] = &group->group;
+       group->groups[1] = NULL;
+       group->group.attrs = group->attrs;
+       dev->groups = group->groups;
+}
+
+static ssize_t
+modalias_show(struct device *dev,
+             struct device_attribute *attr, char *buf)
 {
        struct fw_unit *unit = fw_unit(dev);
        int length;
@@ -209,14 +327,25 @@ show_modalias_attribute(struct device *dev,
        return length + 1;
 }
 
-static struct device_attribute modalias_attribute = {
-       .attr = { .name = "modalias", .mode = S_IRUGO, },
-       .show = show_modalias_attribute,
+static ssize_t
+rom_index_show(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 fw_unit_attributes[] = {
+       __ATTR_RO(modalias),
+       __ATTR_RO(rom_index),
+       __ATTR_NULL,
 };
 
 static ssize_t
-show_config_rom_attribute(struct device *dev,
-                         struct device_attribute *attr, char *buf)
+config_rom_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct fw_device *device = fw_device(dev);
 
@@ -225,25 +354,22 @@ show_config_rom_attribute(struct device *dev,
        return device->config_rom_length * 4;
 }
 
-static struct device_attribute config_rom_attribute = {
-       .attr = {.name = "config_rom", .mode = S_IRUGO,},
-       .show = show_config_rom_attribute,
-};
-
 static ssize_t
-show_rom_index_attribute(struct device *dev,
-                        struct device_attribute *attr, char *buf)
+guid_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct fw_device *device = fw_device(dev->parent);
-       struct fw_unit *unit = fw_unit(dev);
+       struct fw_device *device = fw_device(dev);
+       u64 guid;
 
-       return snprintf(buf, PAGE_SIZE, "%d\n",
-                       unit->directory - device->config_rom);
+       guid = ((u64)device->config_rom[3] << 32) | device->config_rom[4];
+
+       return snprintf(buf, PAGE_SIZE, "0x%016llx\n",
+                       (unsigned long long)guid);
 }
 
-static struct device_attribute rom_index_attribute = {
-       .attr = { .name = "rom_index", .mode = S_IRUGO, },
-       .show = show_rom_index_attribute,
+static struct device_attribute fw_device_attributes[] = {
+       __ATTR_RO(config_rom),
+       __ATTR_RO(guid),
+       __ATTR_NULL,
 };
 
 struct read_quadlet_callback_data {
@@ -368,9 +494,14 @@ static void fw_unit_release(struct device *dev)
        kfree(unit);
 }
 
+static struct device_type fw_unit_type = {
+       .uevent         = fw_unit_uevent,
+       .release        = fw_unit_release,
+};
+
 static int is_fw_unit(struct device *dev)
 {
-       return dev->release == fw_unit_release;
+       return dev->type == &fw_unit_type;
 }
 
 static void create_units(struct fw_device *device)
@@ -395,40 +526,32 @@ static void create_units(struct fw_device *device)
 
                unit->directory = ci.p + value - 1;
                unit->device.bus = &fw_bus_type;
-               unit->device.release = fw_unit_release;
+               unit->device.type = &fw_unit_type;
                unit->device.parent = &device->device;
                snprintf(unit->device.bus_id, sizeof unit->device.bus_id,
                         "%s.%d", device->device.bus_id, i++);
 
-               if (device_register(&unit->device) < 0) {
-                       kfree(unit);
-                       continue;
-               }
+               init_fw_attribute_group(&unit->device,
+                                       fw_unit_attributes,
+                                       &unit->attribute_group);
+               if (device_register(&unit->device) < 0)
+                       goto skip_unit;
 
-               if (device_create_file(&unit->device, &modalias_attribute) < 0) {
-                       device_unregister(&unit->device);
-                       kfree(unit);
-               }
+               continue;
 
-               if (device_create_file(&unit->device, &rom_index_attribute) < 0) {
-                       device_unregister(&unit->device);
-                       kfree(unit);
-               }
+       skip_unit:
+               kfree(unit);
        }
 }
 
 static int shutdown_unit(struct device *device, void *data)
 {
-       struct fw_unit *unit = fw_unit(device);
-
-       if (is_fw_unit(device)) {
-               device_remove_file(&unit->device, &modalias_attribute);
-               device_unregister(&unit->device);
-       }
+       device_unregister(device);
 
        return 0;
 }
 
+static DECLARE_RWSEM(idr_rwsem);
 static DEFINE_IDR(fw_device_idr);
 int fw_cdev_major;
 
@@ -436,9 +559,9 @@ struct fw_device *fw_device_from_devt(dev_t devt)
 {
        struct fw_device *device;
 
-       down_read(&fw_bus_type.subsys.rwsem);
+       down_read(&idr_rwsem);
        device = idr_find(&fw_device_idr, MINOR(devt));
-       up_read(&fw_bus_type.subsys.rwsem);
+       up_read(&idr_rwsem);
 
        return device;
 }
@@ -449,15 +572,19 @@ static void fw_device_shutdown(struct work_struct *work)
                container_of(work, struct fw_device, work.work);
        int minor = MINOR(device->device.devt);
 
-       down_write(&fw_bus_type.subsys.rwsem);
+       down_write(&idr_rwsem);
        idr_remove(&fw_device_idr, minor);
-       up_write(&fw_bus_type.subsys.rwsem);
+       up_write(&idr_rwsem);
 
-       device_remove_file(&device->device, &config_rom_attribute);
+       fw_device_cdev_remove(device);
        device_for_each_child(&device->device, NULL, shutdown_unit);
        device_unregister(&device->device);
 }
 
+static struct device_type fw_device_type = {
+       .release        = fw_device_release,
+};
+
 /* These defines control the retry behavior for reading the config
  * rom.  It shouldn't be necessary to tweak these; if the device
  * doesn't respond to a config rom read within 10 seconds, it's not
@@ -467,8 +594,8 @@ static void fw_device_shutdown(struct work_struct *work)
  * aggressive than that, since it scales pretty well; if 10 devices
  * are plugged in, they're all getting read within one second. */
 
-#define MAX_RETRIES    5
-#define RETRY_DELAY    (2 * HZ)
+#define MAX_RETRIES    10
+#define RETRY_DELAY    (3 * HZ)
 #define INITIAL_DELAY  (HZ / 2)
 
 static void fw_device_init(struct work_struct *work)
@@ -496,30 +623,28 @@ static void fw_device_init(struct work_struct *work)
        }
 
        err = -ENOMEM;
-       down_write(&fw_bus_type.subsys.rwsem);
+       down_write(&idr_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);
+       up_write(&idr_rwsem);
        if (err < 0)
                goto error;
 
        device->device.bus = &fw_bus_type;
-       device->device.release = fw_device_release;
+       device->device.type = &fw_device_type;
        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", minor);
 
+       init_fw_attribute_group(&device->device,
+                               fw_device_attributes,
+                               &device->attribute_group);
        if (device_add(&device->device)) {
                fw_error("Failed to add device.\n");
                goto error_with_cdev;
        }
 
-       if (device_create_file(&device->device, &config_rom_attribute) < 0) {
-               fw_error("Failed to create config rom file.\n");
-               goto error_with_device;
-       }
-
        create_units(device);
 
        /* Transition the device to running state.  If it got pulled
@@ -546,12 +671,10 @@ static void fw_device_init(struct work_struct *work)
 
        return;
 
- error_with_device:
-       device_del(&device->device);
  error_with_cdev:
-       down_write(&fw_bus_type.subsys.rwsem);
+       down_write(&idr_rwsem);
        idr_remove(&fw_device_idr, minor);
-       up_write(&fw_bus_type.subsys.rwsem);
+       up_write(&idr_rwsem);
  error:
        put_device(&device->device);
 }
@@ -561,8 +684,11 @@ 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;
 }