(反正这种方法已经被写烂了,所以请允许我拿来练练英语吧。欢迎指正,welcome your advices)
traditional method:
int register_chrdev(unsigned int major, const char *name,const struct file_operations *fops);
void unregister_chrdev(unsigned int major, const char *name);
new method:
In the later of Linux2.6, there is a new way to register a char-device.At the begining,
1). @kobject is a base-class for manage other thing, for example device-file and the like;
2). @cdev is a structure for manage char-device, and it is a sub-class of the @kobject.
3). ,内核里面有一个挂盘用来管理所有的物品,@kobject像上面的挂钩,@cdev像上面挂的东西。
so, create a @cdev and add it to the link of @kobject.
1). create:
cdev_alloc(void); -- alloc a @cdev.
cdev_init(struct cdev * cdev,const struct file_operations * fops); -- just to init a @cdev
the source code is explain what those function do:
struct cdev {
struct kobject kobj;
struct module *owner;
const struct file_operations *ops;
struct list_head list;
dev_t dev;
unsigned int count;
};
struct cdev *cdev_alloc(void)
{
struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);
if (p) {
INIT_LIST_HEAD(&p->list);
kobject_init(&p->kobj, &ktype_cdev_dynamic);
}
return p;
}
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
{
memset(cdev, 0, sizeof *cdev);
INIT_LIST_HEAD(&cdev->list);
kobject_init(&cdev->kobj, &ktype_cdev_default);
cdev->ops = fops;
}
2).add :there are two way to get a device number.
假如主设备号和从设备号是已知的,可以用 "MKDEV()"组装一个出来总设备号出来,使用下面的函数
register_chrdev_region(dev_t from,unsigned count,const char * name);
假如不知道,就用下面的方法自动获取一个
alloc_chrdev_region(dev_t * dev,unsigned baseminor,unsigned count,const char * name);
有了设备号就可以挂cdev了
cdev_add(struct cdev * p,dev_t dev,unsigned count);
3).destroy:
unregister_chrdev_region(dev_t from,unsigned count);
cdev_del(struct cdev * p)
关于使用的一点总结:
cdev_alloc -> alloc_chrdev_region -> cdev_add
(cdev_init -> register_chrdev_region -> cdev_add)
cdev_del->unregister_chrdev_region
About automatic create :
In the past, we use @devfs.now , it is instreaded by @udev. @udev give us a method, to automaticlly create device-file.
#include <linux/device.h>
class_create( THIS_MODULE, "myled");
device_create( pCla, NULL, MKDEV(ma,mi), NULL, "myled");
device_destroy( pCla, MKDEV(ma,mi));
class_destroy( pCla);
example_1:
(this example is come from:http://www.embedu.org/Column/Column476.htm.)
#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 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);
example_2:
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/device.h>
#define UDEVMAJOR 250
#define UDEVMINOR 0
#define UDEV_COUNT 1
#define CLASS_NAME "class_test"
#define UDEV_DEVNAME "udev_test"
static dev_t DevNum = 0;
static struct cdev cdev;
static struct file_operations fops = {
.owner = THIS_MODULE,
};
struct class *my_class;
static int __init udev_init(void)
{
printk("udev_init........\n");
/** init @cdev*/
cdev_init( &cdev, &fops);
cdev.owner = THIS_MODULE;
//pdev = cdev_alloc();
//pcdev->owner = THIS_MODULE;
//pcdev->ops = &fops;
/** add */
DevNum = MKDEV( UDEVMAJOR, UDEVMINOR);
if( 0>register_chrdev_region( UDEVMAJOR, UDEV_COUNT, UDEV_DEVNAME))
{
printk("error: fail in register_chrdev_region() \n");
goto LFAIL;
}
//alloc_chrdev_region( &DevNum,unsigned baseminor,unsigned count,const char * name)
if( 0>cdev_add( &cdev, DevNum, 1))
{
printk("error: fail in cdev_add() \n");
goto LFAIL;
}
my_class = class_create( THIS_MODULE, CLASS_NAME);
device_create( my_class,NULL, DevNum, NULL, UDEV_DEVNAME);
return 0;
LFAIL:
return -1;
}
static void __exit udev_exit(void)
{
printk("udev_exit........\n");
cdev_del( &cdev);
device_destroy( my_class, DevNum);
class_destroy( my_class);
unregister_chrdev_region( DevNum, UDEV_COUNT);
}
MODULE_LICENSE("GPL");
module_init(udev_init);
module_exit(udev_exit);