2007-01-25 07:52:01

by Markku Savela

[permalink] [raw]
Subject: How to get /dev entry created automaticly for dynamic major number?


If want to write a loadable module which "implements" a char device
("virtual", no real device present). How do I get the correct
"/dev/foo" to appear automaticly? What is the current recommended
solution (kernel 2.6.17 in Ubuntu and later).

static int major;

static int __init foo_init(void)
{
...
major = register_chrdev(0, "foo", &fops);
....
}

static void __exit foo_exit(void)
{
...
if (major > 0)
unregister_chrdev(major, "foo");
...
}

I thought that the above code would be enough to trigger the "udevd",
but apparently not (if it should, what is the match rule I have to
use? DRIVER=="foo" or KERNEL="foo[0-9]*"? None of these seem to
work). Do I have to do some additional poking with sysfs? I can see
my module there, but nothing else.

The problem seems to be that most information I find from books or net
is out of date for 2.6, or carries note "these things are currently
been changed". A pointer to a definitive documentation would also do!


2007-01-25 08:25:58

by Greg KH

[permalink] [raw]
Subject: Re: How to get /dev entry created automaticly for dynamic major number?

On Thu, Jan 25, 2007 at 09:35:07AM +0200, Markku Savela wrote:
>
> If want to write a loadable module which "implements" a char device
> ("virtual", no real device present). How do I get the correct
> "/dev/foo" to appear automaticly? What is the current recommended
> solution (kernel 2.6.17 in Ubuntu and later).
>
> static int major;
>
> static int __init foo_init(void)
> {
> ...
> major = register_chrdev(0, "foo", &fops);
> ....
> }
>
> static void __exit foo_exit(void)
> {
> ...
> if (major > 0)
> unregister_chrdev(major, "foo");
> ...
> }
>
> I thought that the above code would be enough to trigger the "udevd",
> but apparently not (if it should, what is the match rule I have to
> use? DRIVER=="foo" or KERNEL="foo[0-9]*"? None of these seem to
> work). Do I have to do some additional poking with sysfs? I can see
> my module there, but nothing else.
>
> The problem seems to be that most information I find from books or net
> is out of date for 2.6, or carries note "these things are currently
> been changed". A pointer to a definitive documentation would also do!

If you look in the book, Linux Device Drivers, third edition, free
online, there's a section on what is needed for udev to work properly.

The ideas are still the same, but the way to do it has changed since the
book was written. Just use a struct device and a class, and you will be
fine. Look at the misc device core or the mem code in
drivers/char/mem.c for examples of what you need to do.

Hope this helps,

greg k-h

2007-01-25 13:11:19

by Markku Savela

[permalink] [raw]
Subject: Re: How to get /dev entry created automaticly for dynamic major number?

Solution found!

> On Thu, Jan 25, 2007 at 09:35:07AM +0200, Markku Savela wrote:
> > If want to write a loadable module which "implements" a char device
> > ("virtual", no real device present). How do I get the correct
> > "/dev/foo" to appear automaticly?

> From: Greg KH <[email protected]>

> If you look in the book, Linux Device Drivers, third edition, free
> online, there's a section on what is needed for udev to work properly.
>
> The ideas are still the same, but the way to do it has changed since the
> book was written. Just use a struct device and a class, and you will be
> fine. Look at the misc device core or the mem code in
> drivers/char/mem.c for examples of what you need to do.

Thanks! The solution seems to work. The final *obstacle* was, that
class_* symbols were not available until I added the
LICENSE("GPL"). Here is the resulting template, maybe useful for
someone, and just for verification, that I got it right.

...
static int foo_major = 0;
static struct class *foo_class;
static struct class_device *foo_device;
...

static int __init foo_init(void)
{
foo_major = 0;
foo_class = NULL;
foo_device = NULL;

foo_major = register_chrdev(foo_major, "foo", &foo_fops);
if (foo_major <= 0)
return -EIO;
foo_class = class_create(THIS_MODULE, "foo");
if (IS_ERR(foo_class))
{
return PTR_ERR(foo_class);
}
foo_device = class_device_create(foo_class, NULL, MKDEV(foo_major, 0), NULL, "foo0");
if (IS_ERR(foo_device))
{
return PTR_ERR(foo_device);
}
return 0;
}

static void __exit foo_exit(void)
{
if (foo_device && !IS_ERR(foo_device))
class_device_del(foo_device);
if (foo_class && !IS_ERR(foo_class))
class_destroy(foo_class);
if (foo_major > 0)
unregister_chrdev(foo_major, "foo");
}

module_init(foo_init);
module_exit(foo_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Markku Savela");
MODULE_DESCRIPTION("Just fooling around");

2007-01-25 13:17:20

by Markku Savela

[permalink] [raw]
Subject: Re: How to get /dev entry created automaticly for dynamic major number?

Oops!

The error exits are not right in foo_init (need to release anything
succesfully created, if later operations fail). Probably need to make
the current foo_exit into foo_cleanup and call it in real foo_exit and
in any errors at foo_init.

But, again thanks for the help. I consider the "case closed" now.

2007-01-25 13:37:22

by Jiri Kosina

[permalink] [raw]
Subject: Re: How to get /dev entry created automaticly for dynamic major number?

On Thu, 25 Jan 2007, Markku Savela wrote:

> Thanks! The solution seems to work. The final *obstacle* was, that
> class_* symbols were not available until I added the
> LICENSE("GPL"). Here is the resulting template, maybe useful for
> someone, and just for verification, that I got it right.
> static struct class_device *foo_device;
[...]
> foo_device = class_device_create(foo_class, NULL, MKDEV(foo_major, 0), NULL, "foo0");
[...]

You should probably rather move away from struct class_device and
class_device_create() and use struct device and device_create() instead
(all the drivers using class_device are currently being converted this
way, so that class_device could go away), so that your driver is using the
new kernel driver core API.

The conversion should be really very simple.

--
Jiri Kosina

2007-01-25 15:52:36

by Greg KH

[permalink] [raw]
Subject: Re: How to get /dev entry created automaticly for dynamic major number?

On Thu, Jan 25, 2007 at 03:11:15PM +0200, Markku Savela wrote:
> Solution found!
>
> > On Thu, Jan 25, 2007 at 09:35:07AM +0200, Markku Savela wrote:
> > > If want to write a loadable module which "implements" a char device
> > > ("virtual", no real device present). How do I get the correct
> > > "/dev/foo" to appear automaticly?
>
> > From: Greg KH <[email protected]>
>
> > If you look in the book, Linux Device Drivers, third edition, free
> > online, there's a section on what is needed for udev to work properly.
> >
> > The ideas are still the same, but the way to do it has changed since the
> > book was written. Just use a struct device and a class, and you will be
> > fine. Look at the misc device core or the mem code in
> > drivers/char/mem.c for examples of what you need to do.
>
> Thanks! The solution seems to work. The final *obstacle* was, that
> class_* symbols were not available until I added the
> LICENSE("GPL"). Here is the resulting template, maybe useful for
> someone, and just for verification, that I got it right.

Your code _is_ licensed under the GPL, right?

> ...
> static int foo_major = 0;
> static struct class *foo_class;
> static struct class_device *foo_device;
> ...
>
> static int __init foo_init(void)
> {
> foo_major = 0;
> foo_class = NULL;
> foo_device = NULL;
>
> foo_major = register_chrdev(foo_major, "foo", &foo_fops);
> if (foo_major <= 0)
> return -EIO;
> foo_class = class_create(THIS_MODULE, "foo");
> if (IS_ERR(foo_class))
> {
> return PTR_ERR(foo_class);
> }
> foo_device = class_device_create(foo_class, NULL, MKDEV(foo_major, 0), NULL, "foo0");
> if (IS_ERR(foo_device))
> {
> return PTR_ERR(foo_device);
> }
> return 0;
> }
>
> static void __exit foo_exit(void)
> {
> if (foo_device && !IS_ERR(foo_device))
> class_device_del(foo_device);
> if (foo_class && !IS_ERR(foo_class))
> class_destroy(foo_class);
> if (foo_major > 0)
> unregister_chrdev(foo_major, "foo");
> }

Yes, this should work just fine. But as others said, try just using
'device_create' instead, so I don't have to go changing your code in the
next few months when 'struct class_device' finally goes away (it is
being replaced.)

thanks,

greg k-h