Linux驅動編程--字符設備文件註冊

(反正這種方法已經被寫爛了,所以請允許我拿來練練英語吧。歡迎指正,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);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章