linux-2.6.35-based Class_create (), device_create parsing
Miao Teacher, huaqing Vision Embedded College lecturer.
After a version of Linux kernel 2.6, DEVFS no longer exists, and Udev becomes an alternative to DEVFS. As a reminder, Udev is the application layer, do not try to find it in the kernel configuration options; Adding support for Udev is simple, in the case of a character device driver written by the author, call Class_create to create a class for the device in the code that drives the initialization. Then call device_create for each device to create the corresponding device. The approximate usage is as follows:
struct class *myclass;
Class_create (This_module, "my_device_driver");
Device_create (MyClass, NULL, MKDEV (Major_num, minor_num), NULL, "My_device");
When such a module is loaded, Udev daemon automatically creates the My_device device file in/dev.
When we first started writing Linux device drivers, we used to create the device nodes manually using the Mknod command, and in fact the Linux kernel provided us with a set of functions that could be used to automatically create the corresponding device node in the/dev directory when the module was loaded and remove the node when the module was unloaded , of course, the precondition is that user space is ported to Udev.
A struct class struct is defined in the kernel, as the name implies, a struct class struct type variable corresponds to a class, and the kernel also provides class_create (...). function, which can be used to create a class, this class is stored under SYSFS, once the class is created, then the Device_create (...) is called. function to create the appropriate device node in the/dev directory. This way, when the module is loaded, udev in the user space will automatically respond to the Device_create (...) function, go to/SYSFS and look for the corresponding class to create the device node.
Note that in the earlier kernel version of 2.6, device_create (...) The function name is Class_device_create (...), so compiling the previous module in the new kernel sometimes makes an error, because the function name is different and there are some changes in the parameter settings.
struct class and Device_create (...) and device_create (...) are defined in the/include/linux/device.h, the use of the time must include the header file, or the compiler will error.
In the 2.6.35 kernel version, the struct class is defined in the header file include/linux/device.h
/*
* Device Classes
*/
struct Class {
const char *name;
struct module *owner;
struct Class_attribute *class_attrs;
struct Device_attribute *dev_attrs;
struct Kobject *dev_kobj;
Int (*dev_uevent) (struct device *dev, struct kobj_uevent_env *env);
char * (*devnode) (struct device *dev, mode_t *mode);
void (*class_release) (struct class *class);
void (*dev_release) (struct device *dev);
Int (*suspend) (struct device *dev, pm_message_t State);
Int (*resume) (struct device *dev);
const struct Kobj_ns_type_operations *ns_type;
const void * (*namespace) (struct device *dev);
const struct DEV_PM_OPS *pm;
struct Class_private *p;
};
Class_create (...) Implemented in/DRIVERS/BASE/CLASS.C:
/**
* Class_create-create a struct class structure
* @owner: Pointer to the module which is to "own" this struct class
* @name: Pointer to a string for the name of this class.
;*
* This was used to create a struct class pointer so can then be used
* In calls to Device_create ().
*
* Note, the pointer created here's to being destroyed when finished by
* Making a call to Class_destroy ().
*/
struct class *__class_create (struct module *owner, const char *name,
struct Lock_class_key *key)
{
struct class *cls;
int retval;
CLS = Kzalloc (sizeof (*CLS), Gfp_kernel);
if (!CLS) {
retval =-enomem;
Goto error;
}
Cls->name = name;
Cls->owner = owner;
Cls->class_release = Class_create_release;
retval = __class_register (CLS, key);
if (retval)
Goto error;
return CLS;
Error
Kfree (CLS);
Return Err_ptr (retval);
}
The first parameter specifies which module the owner of the class is, and the second parameter specifies the class name.
In CLASS.C, Class_destroy (...) is also defined. function to delete a class when the module is unloaded.
Device_create (...) The function is implemented in/DRIVERS/BASE/CORE.C:
/**
* Device_create-creates a device and registers it with SYSFS
* @class: Pointer to the struct class, this device should is registered to
* @parent: Pointer to the parent struct device of this new device, if any
* @devt: The dev_t for the char device to be added
* @fmt: String for the device ' s name
*
* This function can is used by char device classes. A struct Device
* 'll is created in Sysfs, registered to the specified class.
*
* A "dev" file is created, showing the dev_t for the device, if
* The dev_t is not 0,0.
* If A pointer to a parent struct device was passed in, the newly created
* struct device is a child of the that device in SYSFS.
* The pointer to the struct device is returned from the call.
* Any further SYSFS files, might be required can is created using this
* pointer.
*
* Note:the struct class passed to this function must has previously
* Been created with a call to Class_create ().
*/
struct Device *device_create (struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *FMT, ...)
{
Va_list Vargs;
struct device *dev;
Va_start (Vargs, FMT);
dev = Device_create_vargs (class, Parent, Devt, Drvdata, FMT, Vargs);
Va_end (Vargs);
return dev;
}
The first parameter specifies the class to which the device is to be created, the second parameter is the parent device of the device, if none is specified as NULL, the third parameter is the device number, the fourth parameter is the device name, and the fifth parameter is the device number.
Here's a simple character device driver to show you how to use these functions:
/*
* Copyright (C) 2005 Farsight
*
* This program was free software; You can redistribute it and/or modify
* It under the terms of the GNU general public License as published by
* The free software Foundation; Either version 2 of the License, or
* (at your option) any later version.
* This program was distributed in the hope that it'll be useful,
* but without any WARRANTY; Without even the implied warranty of
* merchantability or FITNESS for A particular PURPOSE. See the
* GNU general public License for more details.
* You should has received a copy of the GNU general public License
* Along with the program; If not, write to the free software
* Foundation, Inc., Wuyi Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/device.h>
Module_license ("GPL");
int hello_major = 250;
int hello_minor = 0;
int number_of_devices = 1;
struct Cdev Cdev;
dev_t dev = 0;
struct File_operations hello_fops = {
. Owner = This_module,
};
struct class *my_class;
static void Char_reg_setup_cdev (void)
{
int error, Devno = MKDEV (Hello_major, Hello_minor);
Cdev_init (&cdev, &hello_fops);
Cdev.owner = This_module;
Cdev.ops = &hello_fops;
Error = Cdev_add (&cdev, Devno, 1);
if (Error)
PRINTK (kern_notice "error%d adding Char_reg_setup_cdev", error);
/* Creating your own class */
My_class =class_create (This_module, "Farsight_class");
if (Is_err (My_class)) {
PRINTK ("err:failed in creating class.\n");
return;
}
/* Register your own device in Sysfs, and this would cause UDEVD to create corresponding device node */
Device_create (My_class,null, Devno, NULL, "Hello");
}
static int __init hello_2_init (void)
{
int result;
dev = MKDEV (hello_major, Hello_minor);
result = Register_chrdev_region (Dev, number_of_devices, "test");
if (result<0) {
PRINTK (kern_warning "Hello:can ' t get major number%d\n", hello_major);
return result;
}
Char_reg_setup_cdev ();
PRINTK (kern_info "char device registered\n");
return 0;
}
static void __exit hello_2_exit (void)
{
dev_t Devno = MKDEV (Hello_major, Hello_minor);
Cdev_del (&cdev);
Unregister_chrdev_region (Devno, number_of_devices);
Device_destroy (My_class, Devno);
Class_destroy (My_class);
}
Module_init (Hello_2_init);
Module_exit (Hello_2_exit);
When the module is loaded, this device file is/dev/hello
linux-2.6.35-based Class_create (), device_create parsing