Skip to contentSkip to conversation

V4L/DVB: ir: Add a link to associate /sys/class/ir/irrcv with the input device

PATCH In review Mauro Carvalho Chehab 2 participants 8 messages Mar 11, 2010 – Mar 14, 2010

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 V4L/DVB: ir: Add a link to associate /sys/class/ir/irrcv with the input device

In order to allow userspace programs to autoload an IR table, a link is needed to point to the corresponding input device.

$ tree /sys/class/irrcv/irrcv0
/sys/class/irrcv/irrcv0
|-- current_protocol
|-- input -> ../../../pci0000:00/0000:00:0b.1/usb1/1-3/input/input22
|-- power
|   `-- wakeup
|-- subsystem -> ../../../../class/irrcv
`-- uevent

It is now easy to associate an irrcv device with the corresponding device node, at the input interface.

drivers/media/IR/ir-sysfs.c +17 -1
index bf5fbcd..7de32e7 100644
@@ -138,6 +138,7 @@ int ir_register_class(struct input_dev *input_dev)
 {
 	int rc;
 	struct kobject *kobj;
+	const char *path;
 
 	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
 	int devno = find_first_zero_bit(&ir_core_dev_number,
@@ -152,13 +153,26 @@ int ir_register_class(struct input_dev *input_dev)
 					  "irrcv%d", devno);
 	kobj = &ir_dev->class_dev->kobj;
 
-	printk(KERN_WARNING "Creating IR device %s\n", kobject_name(kobj));
 	rc = sysfs_create_group(kobj, &ir_dev->attr);
 	if (unlikely(rc < 0)) {
 		device_destroy(ir_input_class, input_dev->dev.devt);
 		return -ENOMEM;
 	}
 
+	rc = sysfs_create_link(kobj, &input_dev->dev.kobj, "input");
+	if (unlikely(rc < 0)) {
+		sysfs_remove_group(kobj, &ir_dev->attr);
+		device_destroy(ir_input_class, input_dev->dev.devt);
+		return -ENOMEM;
+	}
+
+	path = kobject_get_path(&input_dev->dev.kobj, GFP_KERNEL);
+	printk(KERN_INFO "%s: %s associated with sysfs %s\n",
+		kobject_name(kobj),
+		input_dev->name ? input_dev->name : "Unspecified device",
+		path ? path : "N/A");
+	kfree(path);
+
 	ir_dev->devno = devno;
 	set_bit(devno, &ir_core_dev_number);
 
@@ -181,6 +195,8 @@ void ir_unregister_class(struct input_dev *input_dev)
 
 	kobj = &ir_dev->class_dev->kobj;
 
+	sysfs_remove_link(kobj, "input");
+
 	sysfs_remove_group(kobj, &ir_dev->attr);
 	device_destroy(ir_input_class, input_dev->dev.devt);
 
Signature · 1 line
1.6.6.1
#1 lore raw

Hi Mauro,

Quoted 12 lines · Mauro Carvalho Chehab

In order to allow userspace programs to autoload an IR table, a link is needed to point to the corresponding input device.

$ tree /sys/class/irrcv/irrcv0
/sys/class/irrcv/irrcv0
|-- current_protocol
|-- input -> ../../../pci0000:00/0000:00:0b.1/usb1/1-3/input/input22
|-- power
|   `-- wakeup
|-- subsystem -> ../../../../class/irrcv
`-- uevent
Quoted 3 lines

It is now easy to associate an irrcv device with the corresponding device node, at the input interface.

I guess the question is why don't you make input device a child of your irrcvX device? Then I believe driver core will link them properly. It will also ensure proper power management hierarchy.

That probably will require you changing from class_dev into device but that's the direction kernel is going to anyway.

Thanks.

Signature · 1 line
Dmitry
#2 lore raw

Dmitry,

Quoted 19 lines · Dmitry Torokhov

Hi Mauro,

Quoted 12 lines · Mauro Carvalho Chehab

In order to allow userspace programs to autoload an IR table, a link is needed to point to the corresponding input device.

$ tree /sys/class/irrcv/irrcv0
/sys/class/irrcv/irrcv0
|-- current_protocol
|-- input -> ../../../pci0000:00/0000:00:0b.1/usb1/1-3/input/input22
|-- power
|   `-- wakeup
|-- subsystem -> ../../../../class/irrcv
`-- uevent
Quoted 3 lines

It is now easy to associate an irrcv device with the corresponding device node, at the input interface.

Quoted 6 lines

I guess the question is why don't you make input device a child of your irrcvX device? Then I believe driver core will link them properly. It will also ensure proper power management hierarchy.

That probably will require you changing from class_dev into device but that's the direction kernel is going to anyway.

I remember you asked me to create a separate class for IR. The current code does it, using class_create(). Once the class is created, I'm using device_create() to create the nodes.

The current code is:

int ir_register_class(struct input_dev *input_dev)

{
	...
	ir_dev->class_dev = device_create(ir_input_class, NULL,
					  input_dev->dev.devt, ir_dev,
					  "irrcv%d", devno);
	...
	rc = sysfs_create_group(kobj, &ir_dev->attr);
	...
	rc = sysfs_create_link(kobj, &input_dev->dev.kobj, "input");
	...
	return 0;
};

int ir_input_register(struct input_dev *input_dev,
const struct ir_scancode_table *rc_tab, const struct ir_dev_props *props)

{
	...
	rc = input_register_device(input_dev);
	...
	rc = ir_register_class(input_dev);
	...
}

static int __init ir_core_init(void)

{
	ir_input_class = class_create(THIS_MODULE, "irrcv");
	...
}

I couldn't find any other way to create the link without explicitly calling sysfs_create_link().

Do you have a better idea?

Signature · 2 lines
Cheers,
Mauro
#3 lore raw
In reply to Dmitry Torokhov
Quoted 19 lines · Dmitry Torokhov

Hi Mauro,

Quoted 12 lines · Mauro Carvalho Chehab

In order to allow userspace programs to autoload an IR table, a link is needed to point to the corresponding input device.

$ tree /sys/class/irrcv/irrcv0
/sys/class/irrcv/irrcv0
|-- current_protocol
|-- input -> ../../../pci0000:00/0000:00:0b.1/usb1/1-3/input/input22
|-- power
|   `-- wakeup
|-- subsystem -> ../../../../class/irrcv
`-- uevent
Quoted 3 lines

It is now easy to associate an irrcv device with the corresponding device node, at the input interface.

Quoted 6 lines

I guess the question is why don't you make input device a child of your irrcvX device? Then I believe driver core will link them properly. It will also ensure proper power management hierarchy.

That probably will require you changing from class_dev into device but that's the direction kernel is going to anyway.

Done, see enclosed. It is now using class_register/device_register. The newly created device for irrcv is used as the parent for input_dev->dev.

The resulting code looked cleaner after the change ;)

Cheers,
Mauro

---

V4L/DVB: ir: use a real device instead of a virtual class

Change the ir-sysfs approach to create irrcv0 as a device, instead of using class_dev. Also, change the way input is registered, in order to make its parent to be the irrcv device.

Due to this change, now the event device is created under /sys/class/ir/irrcv class:

/sys/class/irrcv/irrcv0/

|-- current_protocol
|-- device -> ../../../1-3
|-- input9
|   |-- capabilities
|   |   |-- abs

...

drivers/media/IR/ir-keytable.c +1 -9
index 0903f53..c9c0a54 100644
@@ -448,22 +448,15 @@ int ir_input_register(struct input_dev *input_dev,
 	input_dev->setkeycode = ir_setkeycode;
 	input_set_drvdata(input_dev, ir_dev);
 
-	rc = input_register_device(input_dev);
-	if (rc < 0)
-		goto err;
-
 	rc = ir_register_class(input_dev);
-	if (rc < 0) {
-		input_unregister_device(input_dev);
+	if (rc < 0)
 		goto err;
-	}
 
 	return 0;
 
 err:
 	kfree(rc_tab->scan);
 	kfree(ir_dev);
-	input_set_drvdata(input_dev, NULL);
 	return rc;
 }
 EXPORT_SYMBOL_GPL(ir_input_register);
@@ -492,7 +485,6 @@ void ir_input_unregister(struct input_dev *dev)
 	ir_unregister_class(dev);
 
 	kfree(ir_dev);
-	input_unregister_device(dev);
 }
 EXPORT_SYMBOL_GPL(ir_input_unregister);
 
drivers/media/IR/ir-sysfs.c +54 -24

126 lines not on this page · raw message

include/media/ir-core.h +1 -3
index 61c223b..ce9f347 100644
@@ -47,11 +47,9 @@ struct ir_dev_props {
 
 
 struct ir_input_dev {
-	struct input_dev		*dev;		/* Input device*/
+	struct device			dev;		/* device */
 	struct ir_scancode_table	rc_tab;		/* scan/key table */
 	unsigned long			devno;		/* device number */
-	struct attribute_group		attr;		/* IR attributes */
-	struct device			*class_dev;	/* virtual class dev */
 	const struct ir_dev_props	*props;		/* Device properties */
 };
 #define to_ir_input_dev(_attr) container_of(_attr, struct ir_input_dev, attr)
#4 lore raw
Quoted 24 lines · Mauro Carvalho Chehab
Quoted 23 lines · Dmitry Torokhov

Hi Mauro,

Quoted 12 lines · Mauro Carvalho Chehab

In order to allow userspace programs to autoload an IR table, a link is needed to point to the corresponding input device.

$ tree /sys/class/irrcv/irrcv0
/sys/class/irrcv/irrcv0
|-- current_protocol
|-- input -> ../../../pci0000:00/0000:00:0b.1/usb1/1-3/input/input22
|-- power
|   `-- wakeup
|-- subsystem -> ../../../../class/irrcv
`-- uevent
Quoted 3 lines

It is now easy to associate an irrcv device with the corresponding device node, at the input interface.

I guess the question is why don't you make input device a child of your irrcvX device? Then I believe driver core will link them properly. It will also ensure proper power management hierarchy.

Quoted 8 lines
Quoted 2 lines

That probably will require you changing from class_dev into device but that's the direction kernel is going to anyway.

Done, see enclosed. It is now using class_register/device_register. The newly created device for irrcv is used as the parent for input_dev->dev.

The resulting code looked cleaner after the change ;)

It is indeed better, however I wonder if current hierarchy expresses the hardware in best way. You currently have irrcv devices grow in parallel with input devices whereas I would expect input devices be children of irrcv devices:

	parent (PCI board, USB) -> irrcvX -> input1
                                          -> input2
					 ...

This way your PM sequence as follows - input core does its thing and releases all pressed keys, etc, then you can shut off the receiver and then board driver can shut doen the main piece. Otherwise irrcv0 suspend may be racing with input suspend and so forth.

Thanks.

Signature · 1 line
Dmitry
#5 lore raw
Quoted 38 lines · Dmitry Torokhov
Quoted 23 lines · Mauro Carvalho Chehab
Quoted 22 lines · Dmitry Torokhov

Hi Mauro,

Quoted 12 lines · Mauro Carvalho Chehab

In order to allow userspace programs to autoload an IR table, a link is needed to point to the corresponding input device.

$ tree /sys/class/irrcv/irrcv0
/sys/class/irrcv/irrcv0
|-- current_protocol
|-- input -> ../../../pci0000:00/0000:00:0b.1/usb1/1-3/input/input22
|-- power
|   `-- wakeup
|-- subsystem -> ../../../../class/irrcv
`-- uevent
Quoted 3 lines

It is now easy to associate an irrcv device with the corresponding device node, at the input interface.

I guess the question is why don't you make input device a child of your irrcvX device? Then I believe driver core will link them properly. It will also ensure proper power management hierarchy.

Quoted 7 lines
Quoted 2 lines

That probably will require you changing from class_dev into device but that's the direction kernel is going to anyway.

Done, see enclosed. It is now using class_register/device_register. The newly created device for irrcv is used as the parent for input_dev->dev.

The resulting code looked cleaner after the change ;)

It is indeed better, however I wonder if current hierarchy expresses the hardware in best way. You currently have irrcv devices grow in parallel with input devices whereas I would expect input devices be children of irrcv devices:

Quoted 4 lines
	parent (PCI board, USB) -> irrcvX -> input1
                                          -> input2
					 ...

It is representing it right:

usb1/1-3 -> irrcv -> irrcv0 -> input7 -> event7

The only extra attribute there is the class name "irrcv", but this seems coherent with the other classes on this device (dvb, sound, power, video4linux).

The created tree is:

$ tree /sys/class/irrcv/
/sys/class/irrcv/
`-- irrcv0 -> ../../devices/pci0000:00/0000:00:0b.1/usb1/1-3/irrcv/irrcv0
$ tree /sys/devices/pci0000:00/0000:00:0b.1/usb1/1-3/
/sys/devices/pci0000:00/0000:00:0b.1/usb1/1-3/
|-- 1-3:1.0
|   |-- bAlternateSetting
|   |-- bInterfaceClass
|   |-- bInterfaceNumber
|   |-- bInterfaceProtocol
|   |-- bInterfaceSubClass
|   |-- bNumEndpoints
|   |-- driver -> ../../../../../../bus/usb/drivers/em28xx
|   |-- ep_81
|   |   |-- bEndpointAddress
|   |   |-- bInterval
|   |   |-- bLength
|   |   |-- bmAttributes
|   |   |-- direction
|   |   |-- interval
|   |   |-- power
|   |   |   `-- wakeup
|   |   |-- type
|   |   |-- uevent
|   |   `-- wMaxPacketSize
|   |-- ep_82
|   |   |-- bEndpointAddress
|   |   |-- bInterval
|   |   |-- bLength
|   |   |-- bmAttributes
|   |   |-- direction
|   |   |-- interval
|   |   |-- power
|   |   |   `-- wakeup
|   |   |-- type
|   |   |-- uevent
|   |   `-- wMaxPacketSize
|   |-- ep_83
|   |   |-- bEndpointAddress
|   |   |-- bInterval
|   |   |-- bLength
|   |   |-- bmAttributes
|   |   |-- direction
|   |   |-- interval
|   |   |-- power
|   |   |   `-- wakeup
|   |   |-- type
|   |   |-- uevent
|   |   `-- wMaxPacketSize
|   |-- ep_84
|   |   |-- bEndpointAddress
|   |   |-- bInterval
|   |   |-- bLength
|   |   |-- bmAttributes
|   |   |-- direction
|   |   |-- interval
|   |   |-- power
|   |   |   `-- wakeup
|   |   |-- type
|   |   |-- uevent
|   |   `-- wMaxPacketSize
|   |-- modalias
|   |-- power
|   |   `-- wakeup
|   |-- subsystem -> ../../../../../../bus/usb
|   |-- supports_autosuspend
|   |-- uevent
|   `-- video4linux
|       |-- vbi2
|       |   |-- dev
|       |   |-- device -> ../../../1-3:1.0
|       |   |-- index
|       |   |-- name
|       |   |-- power
|       |   |   `-- wakeup
|       |   |-- subsystem -> ../../../../../../../../class/video4linux
|       |   `-- uevent
|       `-- video2
|           |-- dev
|           |-- device -> ../../../1-3:1.0
|           |-- index
|           |-- name
|           |-- power
|           |   `-- wakeup
|           |-- subsystem -> ../../../../../../../../class/video4linux
|           `-- uevent
|-- authorized
|-- bcdDevice
|-- bConfigurationValue
|-- bDeviceClass
|-- bDeviceProtocol
|-- bDeviceSubClass
|-- bmAttributes
|-- bMaxPacketSize0
|-- bMaxPower
|-- bNumConfigurations
|-- bNumInterfaces
|-- busnum
|-- configuration
|-- descriptors
|-- dev
|-- devnum
|-- devpath
|-- driver -> ../../../../../bus/usb/drivers/usb
|-- dvb
|   |-- dvb0.demux0
|   |   |-- dev
|   |   |-- device -> ../../../1-3
|   |   |-- power
|   |   |   `-- wakeup
|   |   |-- subsystem -> ../../../../../../../class/dvb
|   |   `-- uevent
|   |-- dvb0.dvr0
|   |   |-- dev
|   |   |-- device -> ../../../1-3
|   |   |-- power
|   |   |   `-- wakeup
|   |   |-- subsystem -> ../../../../../../../class/dvb
|   |   `-- uevent
|   |-- dvb0.frontend0
|   |   |-- dev
|   |   |-- device -> ../../../1-3
|   |   |-- power
|   |   |   `-- wakeup
|   |   |-- subsystem -> ../../../../../../../class/dvb
|   |   `-- uevent
|   `-- dvb0.net0
|       |-- dev
|       |-- device -> ../../../1-3
|       |-- power
|       |   `-- wakeup
|       |-- subsystem -> ../../../../../../../class/dvb
|       `-- uevent
|-- ep_00
|   |-- bEndpointAddress
|   |-- bInterval
|   |-- bLength
|   |-- bmAttributes
|   |-- direction
|   |-- interval
|   |-- power
|   |   `-- wakeup
|   |-- type
|   |-- uevent
|   `-- wMaxPacketSize
|-- i2c-3
|   |-- 3-005c
|   |   |-- driver -> ../../../../../../../bus/i2c/drivers/tvp5150
|   |   |-- modalias
|   |   |-- name
|   |   |-- power
|   |   |   `-- wakeup
|   |   |-- subsystem -> ../../../../../../../bus/i2c
|   |   `-- uevent
|   |-- 3-0061
|   |   |-- driver -> ../../../../../../../bus/i2c/drivers/tuner
|   |   |-- modalias
|   |   |-- name
|   |   |-- power
|   |   |   `-- wakeup
|   |   |-- subsystem -> ../../../../../../../bus/i2c
|   |   `-- uevent
|   |-- delete_device
|   |-- device -> ../../1-3
|   |-- name
|   |-- new_device
|   |-- power
|   |   `-- wakeup
|   |-- subsystem -> ../../../../../../bus/i2c
|   `-- uevent
|-- idProduct
|-- idVendor
|-- irrcv
|   `-- irrcv0
|       |-- current_protocol
|       |-- device -> ../../../1-3
|       |-- input7
|       |   |-- capabilities
|       |   |   |-- abs
|       |   |   |-- ev
|       |   |   |-- ff
|       |   |   |-- key
|       |   |   |-- led
|       |   |   |-- msc
|       |   |   |-- rel
|       |   |   |-- snd
|       |   |   `-- sw
|       |   |-- device -> ../../irrcv0
|       |   |-- event7
|       |   |   |-- dev
|       |   |   |-- device -> ../../input7
|       |   |   |-- power
|       |   |   |   `-- wakeup
|       |   |   |-- subsystem -> ../../../../../../../../../class/input
|       |   |   `-- uevent
|       |   |-- id
|       |   |   |-- bustype
|       |   |   |-- product
|       |   |   |-- vendor
|       |   |   `-- version
|       |   |-- modalias
|       |   |-- name
|       |   |-- phys
|       |   |-- power
|       |   |   `-- wakeup
|       |   |-- subsystem -> ../../../../../../../../class/input
|       |   |-- uevent
|       |   `-- uniq
|       |-- power
|       |   `-- wakeup
|       |-- subsystem -> ../../../../../../../class/irrcv
|       `-- uevent
|-- maxchild
|-- power
|   |-- active_duration
|   |-- autosuspend
|   |-- connected_duration
|   |-- level
|   |-- persist
|   `-- wakeup
|-- product
|-- quirks
|-- remove
|-- serial
|-- sound
|   `-- card1
|       |-- controlC1
|       |   |-- dev
|       |   |-- device -> ../../card1
|       |   |-- power
|       |   |   `-- wakeup
|       |   |-- subsystem -> ../../../../../../../../class/sound
|       |   `-- uevent
|       |-- device -> ../../../1-3
|       |-- id
|       |-- number
|       |-- pcmC1D0c
|       |   |-- dev
|       |   |-- device -> ../../card1
|       |   |-- pcm_class
|       |   |-- power
|       |   |   `-- wakeup
|       |   |-- subsystem -> ../../../../../../../../class/sound
|       |   `-- uevent
|       |-- power
|       |   `-- wakeup
|       |-- subsystem -> ../../../../../../../class/sound
|       `-- uevent
|-- speed
|-- subsystem -> ../../../../../bus/usb
|-- uevent
|-- urbnum
`-- version
$ tree /sys/class/irrcv/irrcv0/
/sys/class/irrcv/irrcv0/
|-- current_protocol
|-- device -> ../../../1-3
|-- input7
|   |-- capabilities
|   |   |-- abs
|   |   |-- ev
|   |   |-- ff
|   |   |-- key
|   |   |-- led
|   |   |-- msc
|   |   |-- rel
|   |   |-- snd
|   |   `-- sw
|   |-- device -> ../../irrcv0
|   |-- event7
|   |   |-- dev
|   |   |-- device -> ../../input7
|   |   |-- power
|   |   |   `-- wakeup
|   |   |-- subsystem -> ../../../../../../../../../class/input
|   |   `-- uevent
|   |-- id
|   |   |-- bustype
|   |   |-- product
|   |   |-- vendor
|   |   `-- version
|   |-- modalias
|   |-- name
|   |-- phys
|   |-- power
|   |   `-- wakeup
|   |-- subsystem -> ../../../../../../../../class/input
|   |-- uevent
|   `-- uniq
|-- power
|   `-- wakeup
|-- subsystem -> ../../../../../../../class/irrcv
`-- uevent

13 directories, 25 files

Quoted 7 lines

This way your PM sequence as follows - input core does its thing and releases all pressed keys, etc, then you can shut off the receiver and then board driver can shut doen the main piece. Otherwise irrcv0 suspend may be racing with input suspend and so forth.

Thanks.

Signature · 2 lines
Cheers,
Mauro
#6 lore raw
Quoted 44 lines · Mauro Carvalho Chehab
Quoted 38 lines · Dmitry Torokhov
Quoted 23 lines · Mauro Carvalho Chehab
Quoted 22 lines · Dmitry Torokhov

Hi Mauro,

Quoted 12 lines · Mauro Carvalho Chehab

In order to allow userspace programs to autoload an IR table, a link is needed to point to the corresponding input device.

$ tree /sys/class/irrcv/irrcv0
/sys/class/irrcv/irrcv0
|-- current_protocol
|-- input -> ../../../pci0000:00/0000:00:0b.1/usb1/1-3/input/input22
|-- power
|   `-- wakeup
|-- subsystem -> ../../../../class/irrcv
`-- uevent
Quoted 3 lines

It is now easy to associate an irrcv device with the corresponding device node, at the input interface.

I guess the question is why don't you make input device a child of your irrcvX device? Then I believe driver core will link them properly. It will also ensure proper power management hierarchy.

Quoted 7 lines
Quoted 2 lines

That probably will require you changing from class_dev into device but that's the direction kernel is going to anyway.

Done, see enclosed. It is now using class_register/device_register. The newly created device for irrcv is used as the parent for input_dev->dev.

The resulting code looked cleaner after the change ;)

It is indeed better, however I wonder if current hierarchy expresses the hardware in best way. You currently have irrcv devices grow in parallel with input devices whereas I would expect input devices be children of irrcv devices:

Quoted 4 lines
	parent (PCI board, USB) -> irrcvX -> input1
                                          -> input2
					 ...
Quoted 7 lines

It is representing it right:

usb1/1-3 -> irrcv -> irrcv0 -> input7 -> event7

The only extra attribute there is the class name "irrcv", but this seems coherent with the other classes on this device (dvb, sound, power, video4linux).

Ah, yes, I saw where you take input device's parent and use it as irrcv's parent but missed the piece where you substitute original input device's parent with irrcv. I bit sneaky to my taste but I guess can be cleaned up later.

Signature · 1 line
Dmitry
#7 lore raw
Quoted 6 lines · Dmitry Torokhov
Quoted 4 lines · Mauro Carvalho Chehab

It is representing it right:

usb1/1-3 -> irrcv -> irrcv0 -> input7 -> event7

Quoted 8 lines
Quoted 3 lines

The only extra attribute there is the class name "irrcv", but this seems coherent with the other classes on this device (dvb, sound, power, video4linux).

Ah, yes, I saw where you take input device's parent and use it as irrcv's parent but missed the piece where you substitute original input device's parent with irrcv. I bit sneaky to my taste but I guess can be cleaned up later.

Yes. I opted to do this little trick to avoid changing the interfaces on the other modules, and to minimize the needs when porting from input. We can later clean it if/when needed.

Signature · 2 lines
Cheers,
Mauro