歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> 關於Linux >> 【Linux驅動】自動創建設備節點

【Linux驅動】自動創建設備節點

日期:2017/3/3 17:00:07   编辑:關於Linux

開始學習驅動的時候,是將驅動程序編譯成模塊然後用mknod命令手動建立設備節點以提供給應用程序調用。這對於剛開始調試驅動程序的時候常用的一種方法。但是,當有種需要必須在系統啟動的時候就將驅動程序就緒,來供應用層程序調用。這時就不能再手動的建立設備節點了,而必須自動的創建設備節點(不需要人為的操作)。

★注冊類

注冊類的目的是為了使mdev可以在/dev/目錄下建立設備節點。

首先要定義一個類,利用struct class結構體。這個結構體定義在頭文件include/linux/device.h中

struct class {
	const char		* name;
	struct module		* owner;

	struct subsystem	subsys;
	struct list_head	children;
	struct list_head	devices;
	struct list_head	interfaces;
	struct semaphore	sem;	/* locks both the children and interfaces lists */

	struct kobject		*virtual_dir;

	struct class_attribute		* class_attrs;
	struct class_device_attribute	* class_dev_attrs;
	struct device_attribute		* dev_attrs;

	int	(*uevent)(struct class_device *dev, char **envp,
			   int num_envp, char *buffer, int buffer_size);
	int	(*dev_uevent)(struct device *dev, char **envp, int num_envp,
				char *buffer, int buffer_size);

	void	(*release)(struct class_device *dev);
	void	(*class_release)(struct class *class);
	void	(*dev_release)(struct device *dev);

	int	(*suspend)(struct device *, pm_message_t state);
	int	(*resume)(struct device *);
} 

然後使用

\

完成對類的注冊。其中第一個參數一般為:THIS_MODULE。第二個參數為:設備節點的名稱

舉個例子:

\\

★創建設備節點

創建設備節點的函數:

<pre name="code" class="cpp">struct device *device_create(struct class *class, struct device *parent,dev_t devt, const char *fmt, ...)
{
	va_list args;
	struct device *dev = NULL;
	int retval = -ENODEV;

	if (class == NULL || IS_ERR(class))
		goto error;

	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
	if (!dev) {
		retval = -ENOMEM;
		goto error;
	}

	dev->devt = devt;
	dev->class = class;
	dev->parent = parent;
	dev->release = device_create_release;

	va_start(args, fmt);
	vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args);
	va_end(args);
	retval = device_register(dev);
	if (retval)
		goto error;

	return dev;

error:
	kfree(dev);
	return ERR_PTR(retval);
}
該函數的四個參數從左到右以此為:創建設備節點所屬的類、該設備的父節點(若果沒有就指定為NULL)、設備號、設備名稱、次設備號。

★銷毀類和設備節點

注意不要忘記了還要銷毀類和銷毀設備節點。

銷毀類:參數為用struct class結構體定義的變量

void class_destroy(struct class *cls)
{
	if ((cls == NULL) || (IS_ERR(cls)))
		return;

	class_unregister(cls);
}
銷毀設備節點:
void device_destroy(struct class *class, dev_t devt)
{
	struct device *dev = NULL;
	struct device *dev_tmp;

	down(&class->sem);
	list_for_each_entry(dev_tmp, &class->devices, node) {
		if (dev_tmp->devt == devt) {
			dev = dev_tmp;
			break;
		}
	}
	up(&class->sem);

	if (dev)
		device_unregister(dev);
}

★例子(自己寫的延時驅動)

#include <linux/miscdevice.h>    
#include <linux/delay.h>    
#include <asm/irq.h>
#include <linux/kernel.h>    
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/unistd.h>
#include <linux/string.h>
#include <linux/fcntl.h>
#include <asm/uaccess.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/version.h>
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/device.h> 

#define NAME	"ralink_drive_delay"
#define RALINK_GPIO_DEVNAME "my_delay" 

#define delay_us 0     //most least is 10 US
#define delay_ms 1     //Ms

int delay_MAJOR = 109;
MODULE_LICENSE("Dual BSD/GPL");

static long Ralink_delay_ioctl(struct inode * inode, struct file * file, unsigned int cmd,unsigned long arg)
{
    
    switch(cmd)
    {
            case delay_us: 
                udelay(10 * arg);
                return 0;
            case delay_ms:
                udelay(1000);
                return 0;
            default:
                return -1;
    }
}

static struct file_operations My_delay_fops = 
{
    .owner = THIS_MODULE,
    .ioctl = Ralink_delay_ioctl,
};

static struct class *delay_class;

static int __init my_delay_init(void)
{
    int ret = 0;
    ret = register_chrdev(delay_MAJOR, RALINK_GPIO_DEVNAME,&My_delay_fops);
    if(ret < 0)
    {
        printk("unable to register character device\n");
        return ret;
    }
    if (delay_MAJOR == 0) 
    {
	    delay_MAJOR = ret;
	    printk(KERN_DEBUG NAME ": got dynamic major %d\n", ret);
    }
     
    //注冊一個類,使mdev可以在"/dev/目錄下建立設備節點"
    delay_class = class_create(THIS_MODULE, RALINK_GPIO_DEVNAME);
    if(IS_ERR(delay_class))
    {
        printk("failed in My_led class.\n");
        return -1;                       
    } 
    device_create(delay_class, NULL, MKDEV(delay_MAJOR, 0),RALINK_GPIO_DEVNAME 0);//
    //第一個參數是所要創建的設備所從屬的類
    //第二個參數是這個設備的父節點,沒有指定就是NULL 
    //第三個參數是設備號
    //第四個參數是設備名稱
    //第五個參數是從設備號 
    printk("my_delay driver initialized\n");
    return 0;
}

void __exit my_delay_exit(void)
{
    unregister_chrdev(delay_MAJOR,RALINK_GPIO_DEVNAME);
    device_destroy(delay_class,MKDEV(delay_MAJOR,0));//注銷設備節點 
    class_destroy(delay_class);//銷毀類 
    printk("my_delay driver exited\n");
    
}

module_init(my_delay_init);
module_exit(my_delay_exit);
					
                
              
            
        
        
			
			
Copyright © Linux教程網 All Rights Reserved