diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2009-05-22 18:03:29 -0400 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2009-06-01 06:48:49 -0400 |
commit | 0210b66dd88a2a1e451901b00378a2068b6ccb35 (patch) | |
tree | e1a308f0800a2a0950f1af4e259008af1a62babf /drivers | |
parent | e5333db9285e088a98f4bad5147bfb0b4665fafb (diff) |
firewire: core: add sysfs attribute for easier udev rules
This adds the attribute /sys/bus/firewire/devices/fw[0-9]+/units. It
can be used in udev rules like the following ones:
# IIDC devices: industrial cameras and some webcams
SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x00010?*", GROUP="video"
# AV/C devices: camcorders, set-top boxes, TV sets, audio devices, ...
SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x010001*", GROUP="video"
Background:
firewire-core manages two device types:
- fw_device is a FireWire node. A character device file is associated
with it.
- fw_unit is a unit directory on a node. Each fw_device may have 0..n
children of type fw_unit. The units tell us what kinds of protocols
a node implements.
We want to set ownership or ACLs or permissions of the character device
file of an fw_device, or/and create symlinks to it, based on available
protocols. Until now udev rules had to look at the fw_unit devices and
then modify their parent's character device file accordingly. This is
problematic for two reasons: 1) It happens sometime after the creation
of the fw_device, 2) an access policy may require that information from
all children is evaluated before a decision about the parent is made.
Problem 1) can ultimately not be avoided since this is the nature of
FireWire nodes: They may add or remove unit directories at any point in
time.
However, we can still help userland a lot by providing the protocol type
information of all units in a summary sysfs attribute directly at the
fw_device. This way,
- the information is immediately available at the affected device
when userspace goes about to handle an ADD or CHANGE event of the
fw_device,
- with most policies, it won't be necessary anymore to dig through
child attributes.
The new attribute is called "units". It contains space-separated tuples
of specifier_id and version of each present unit. The delimiter within
tuples is a colon. Specifier_id and version are printed as 0x%06x.
Here is an example of a node which implements an IPv4 unit and an IPv6
unit: $ cat /sys/bus/firewire/devices/fw2/units
0x00005e:0x000001 0x00005e:0x000002
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/firewire/fw-device.c | 50 | ||||
-rw-r--r-- | drivers/firewire/fw-device.h | 2 |
2 files changed, 51 insertions, 1 deletions
diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c index 98ce0841f4c9..551588342898 100644 --- a/drivers/firewire/fw-device.c +++ b/drivers/firewire/fw-device.c | |||
@@ -355,9 +355,56 @@ static ssize_t guid_show(struct device *dev, | |||
355 | return ret; | 355 | return ret; |
356 | } | 356 | } |
357 | 357 | ||
358 | static int units_sprintf(char *buf, u32 *directory) | ||
359 | { | ||
360 | struct fw_csr_iterator ci; | ||
361 | int key, value; | ||
362 | int specifier_id = 0; | ||
363 | int version = 0; | ||
364 | |||
365 | fw_csr_iterator_init(&ci, directory); | ||
366 | while (fw_csr_iterator_next(&ci, &key, &value)) { | ||
367 | switch (key) { | ||
368 | case CSR_SPECIFIER_ID: | ||
369 | specifier_id = value; | ||
370 | break; | ||
371 | case CSR_VERSION: | ||
372 | version = value; | ||
373 | break; | ||
374 | } | ||
375 | } | ||
376 | |||
377 | return sprintf(buf, "0x%06x:0x%06x ", specifier_id, version); | ||
378 | } | ||
379 | |||
380 | static ssize_t units_show(struct device *dev, | ||
381 | struct device_attribute *attr, char *buf) | ||
382 | { | ||
383 | struct fw_device *device = fw_device(dev); | ||
384 | struct fw_csr_iterator ci; | ||
385 | int key, value, i = 0; | ||
386 | |||
387 | down_read(&fw_device_rwsem); | ||
388 | fw_csr_iterator_init(&ci, &device->config_rom[5]); | ||
389 | while (fw_csr_iterator_next(&ci, &key, &value)) { | ||
390 | if (key != (CSR_UNIT | CSR_DIRECTORY)) | ||
391 | continue; | ||
392 | i += units_sprintf(&buf[i], ci.p + value - 1); | ||
393 | if (i >= PAGE_SIZE - (8 + 1 + 8 + 1)) | ||
394 | break; | ||
395 | } | ||
396 | up_read(&fw_device_rwsem); | ||
397 | |||
398 | if (i) | ||
399 | buf[i - 1] = '\n'; | ||
400 | |||
401 | return i; | ||
402 | } | ||
403 | |||
358 | static struct device_attribute fw_device_attributes[] = { | 404 | static struct device_attribute fw_device_attributes[] = { |
359 | __ATTR_RO(config_rom), | 405 | __ATTR_RO(config_rom), |
360 | __ATTR_RO(guid), | 406 | __ATTR_RO(guid), |
407 | __ATTR_RO(units), | ||
361 | __ATTR_NULL, | 408 | __ATTR_NULL, |
362 | }; | 409 | }; |
363 | 410 | ||
@@ -1000,6 +1047,9 @@ static void fw_device_refresh(struct work_struct *work) | |||
1000 | 1047 | ||
1001 | create_units(device); | 1048 | create_units(device); |
1002 | 1049 | ||
1050 | /* Userspace may want to re-read attributes. */ | ||
1051 | kobject_uevent(&device->device.kobj, KOBJ_CHANGE); | ||
1052 | |||
1003 | if (atomic_cmpxchg(&device->state, | 1053 | if (atomic_cmpxchg(&device->state, |
1004 | FW_DEVICE_INITIALIZING, | 1054 | FW_DEVICE_INITIALIZING, |
1005 | FW_DEVICE_RUNNING) == FW_DEVICE_GONE) | 1055 | FW_DEVICE_RUNNING) == FW_DEVICE_GONE) |
diff --git a/drivers/firewire/fw-device.h b/drivers/firewire/fw-device.h index 623cfee289bd..892dd5916276 100644 --- a/drivers/firewire/fw-device.h +++ b/drivers/firewire/fw-device.h | |||
@@ -42,7 +42,7 @@ enum fw_device_state { | |||
42 | struct fw_attribute_group { | 42 | struct fw_attribute_group { |
43 | struct attribute_group *groups[2]; | 43 | struct attribute_group *groups[2]; |
44 | struct attribute_group group; | 44 | struct attribute_group group; |
45 | struct attribute *attrs[11]; | 45 | struct attribute *attrs[12]; |
46 | }; | 46 | }; |
47 | 47 | ||
48 | struct fw_node; | 48 | struct fw_node; |