From: Marcel Holtmann <marcel@holtmann.org>
To: Kay Sievers <kay.sievers@vrfy.org>
Cc: Greg KH <greg@kroah.com>, linux-kernel@vger.kernel.org
Subject: Re: Implement class_device_update_dev() function
Date: Sat, 08 Jul 2006 15:28:21 +0200 [thread overview]
Message-ID: <1152365301.29506.9.camel@localhost> (raw)
In-Reply-To: <1152363634.3408.3.camel@pim.off.vrfy.org>
[-- Attachment #1: Type: text/plain, Size: 1508 bytes --]
Hi Kay,
> > > > > But userspace should also find out about this change, and this patch
> > > > > prevents that from happening. What about just tearing down the class
> > > > > device and creating a new one? That way userspace knows about the new
> > > > > linkage properly, and any device naming and permission issues can be
> > > > > handled anew?
> > > >
> > > > This won't work for Bluetooth. We create the TTY and its class device
> > > > with tty_register_device() and then the device node is present. Then at
> > > > some point later we open that device and the Bluetooth connection gets
> > > > established. Only when the connection has been established we know the
> > > > device that represents it. So tearing down the class device and creating
> > > > a new one will screw up the application that is using this device node.
> > > >
> > > > Would reissuing the uevent of the class device help here?
> > >
> > > How about KOBJ_ONLINE/OFFLINE?
> >
> > I am not that familiar with the internals of kobject. Can you give me an
> > example on how to do that?
>
> Just send another event (but not add or remove), for the already created
> object. CPU hotplug uses ONLINE/OFFLINE, and we also use it to get
> notified when the device mapper table is set up (not upstream). Udev is
> able to update symlinks, or run actions on "online" events if asked
> for.
the attached patch sends ONLINE when a device has been attached to a
class device and OFFLINE when it has been removed.
Regards
Marcel
[-- Attachment #2: patch-class-device-update-dev --]
[-- Type: text/plain, Size: 5964 bytes --]
[PATCH] Allow dynamically changing the device of a class device
This patch implements the class_device_update_dev() function which
allows to change the device of a class device after its creation.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
commit 97372f657bbb68ee1c4119bb21642fc700317ce3
tree bd46b493dd75b09515897eb0d12b2fd30a234e3c
parent 120bda20c6f64b32e8bfbdd7b34feafaa5f5332e
author Marcel Holtmann <marcel@holtmann.org> Sat, 08 Jul 2006 15:24:15 +0200
committer Marcel Holtmann <marcel@holtmann.org> Sat, 08 Jul 2006 15:24:15 +0200
drivers/base/class.c | 98 ++++++++++++++++++++++++++++++++++--------------
include/linux/device.h | 1
2 files changed, 71 insertions(+), 28 deletions(-)
diff --git a/drivers/base/class.c b/drivers/base/class.c
index de89083..1789a6b 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -485,6 +485,48 @@ static void class_device_remove_groups(s
}
}
+static int class_device_add_dev(struct class_device *class_dev)
+{
+ char *class_name = NULL;
+ int error = 0;
+
+ if (class_dev->dev) {
+ class_name = make_class_name(class_dev->class->name,
+ &class_dev->kobj);
+ error = sysfs_create_link(&class_dev->kobj,
+ &class_dev->dev->kobj, "device");
+ if (error)
+ goto out;
+
+ error = sysfs_create_link(&class_dev->dev->kobj,
+ &class_dev->kobj, class_name);
+ if (error) {
+ sysfs_remove_link(&class_dev->kobj, "device");
+ goto out;
+ }
+
+ kobject_uevent(&class_dev->kobj, KOBJ_ONLINE);
+ }
+
+ out:
+ kfree(class_name);
+ return error;
+}
+
+static void class_device_remove_dev(struct class_device *class_dev)
+{
+ char *class_name;
+
+ if (class_dev->dev) {
+ class_name = make_class_name(class_dev->class->name,
+ &class_dev->kobj);
+ sysfs_remove_link(&class_dev->kobj, "device");
+ sysfs_remove_link(&class_dev->dev->kobj, class_name);
+ kobject_uevent(&class_dev->kobj, KOBJ_OFFLINE);
+ kfree(class_name);
+ }
+}
+
static ssize_t show_dev(struct class_device *class_dev, char *buf)
{
return print_dev_t(buf, class_dev->devt);
@@ -526,7 +568,6 @@ int class_device_add(struct class_device
struct class *parent_class = NULL;
struct class_device *parent_class_dev = NULL;
struct class_interface *class_intf;
- char *class_name = NULL;
int error = -EINVAL;
class_dev = class_device_get(class_dev);
@@ -593,22 +634,13 @@ int class_device_add(struct class_device
if (error)
goto out5;
- if (class_dev->dev) {
- class_name = make_class_name(class_dev->class->name,
- &class_dev->kobj);
- error = sysfs_create_link(&class_dev->kobj,
- &class_dev->dev->kobj, "device");
- if (error)
- goto out6;
- error = sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj,
- class_name);
- if (error)
- goto out7;
- }
+ error = class_device_add_dev(class_dev);
+ if (error)
+ goto out6;
error = class_device_add_groups(class_dev);
if (error)
- goto out8;
+ goto out7;
kobject_uevent(&class_dev->kobj, KOBJ_ADD);
@@ -623,12 +655,8 @@ int class_device_add(struct class_device
goto out1;
- out8:
- if (class_dev->dev)
- sysfs_remove_link(&class_dev->kobj, class_name);
out7:
- if (class_dev->dev)
- sysfs_remove_link(&class_dev->kobj, "device");
+ class_device_remove_dev(class_dev);
out6:
class_device_remove_attrs(class_dev);
out5:
@@ -644,7 +672,6 @@ int class_device_add(struct class_device
class_put(parent_class);
out1:
class_device_put(class_dev);
- kfree(class_name);
return error;
}
@@ -720,7 +747,6 @@ void class_device_del(struct class_devic
struct class *parent_class = class_dev->class;
struct class_device *parent_device = class_dev->parent;
struct class_interface *class_intf;
- char *class_name = NULL;
if (parent_class) {
down(&parent_class->sem);
@@ -731,12 +757,7 @@ void class_device_del(struct class_devic
up(&parent_class->sem);
}
- if (class_dev->dev) {
- class_name = make_class_name(class_dev->class->name,
- &class_dev->kobj);
- sysfs_remove_link(&class_dev->kobj, "device");
- sysfs_remove_link(&class_dev->dev->kobj, class_name);
- }
+ class_device_remove_dev(class_dev);
sysfs_remove_link(&class_dev->kobj, "subsystem");
class_device_remove_file(class_dev, &class_dev->uevent_attr);
if (class_dev->devt_attr)
@@ -749,7 +770,6 @@ void class_device_del(struct class_devic
class_device_put(parent_device);
class_put(parent_class);
- kfree(class_name);
}
void class_device_unregister(struct class_device *class_dev)
@@ -821,6 +841,27 @@ int class_device_rename(struct class_dev
return error;
}
+int class_device_update_dev(struct class_device *class_dev, struct device *dev)
+{
+ int error = 0;
+
+ class_dev = class_device_get(class_dev);
+ if (!class_dev)
+ return -EINVAL;
+
+ if (class_dev->dev != dev) {
+ class_device_remove_dev(class_dev);
+
+ class_dev->dev = dev;
+
+ error = class_device_add_dev(class_dev);
+ }
+
+ class_device_put(class_dev);
+
+ return error;
+}
+
struct class_device * class_device_get(struct class_device *class_dev)
{
if (class_dev)
@@ -911,6 +952,7 @@ EXPORT_SYMBOL_GPL(class_device_get);
EXPORT_SYMBOL_GPL(class_device_put);
EXPORT_SYMBOL_GPL(class_device_create);
EXPORT_SYMBOL_GPL(class_device_destroy);
+EXPORT_SYMBOL_GPL(class_device_update_dev);
EXPORT_SYMBOL_GPL(class_device_create_file);
EXPORT_SYMBOL_GPL(class_device_remove_file);
EXPORT_SYMBOL_GPL(class_device_create_bin_file);
diff --git a/include/linux/device.h b/include/linux/device.h
index 1e5f30d..d76072b 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -249,6 +249,7 @@ extern int class_device_add(struct class
extern void class_device_del(struct class_device *);
extern int class_device_rename(struct class_device *, char *);
+extern int class_device_update_dev(struct class_device *, struct device *);
extern struct class_device * class_device_get(struct class_device *);
extern void class_device_put(struct class_device *);
next prev parent reply other threads:[~2006-07-08 13:28 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-07-06 22:59 Implement class_device_update_dev() function Marcel Holtmann
2006-07-06 23:57 ` Greg KH
2006-07-07 7:42 ` Marcel Holtmann
2006-07-08 0:26 ` Kay Sievers
2006-07-08 9:27 ` Marcel Holtmann
2006-07-08 13:00 ` Kay Sievers
2006-07-08 13:28 ` Marcel Holtmann [this message]
2006-07-08 17:27 ` Marcel Holtmann
2006-07-11 23:18 ` Greg KH
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1152365301.29506.9.camel@localhost \
--to=marcel@holtmann.org \
--cc=greg@kroah.com \
--cc=kay.sievers@vrfy.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.