字符驅動程序模板

設備驅動模型通過sysfs文件系統向用戶層提供設備驅動視圖,如下。

1.設備是具體的一個個設備,在/sys/devices/是創建了實際的文件節點。而其他目錄,如設備類和總線以下的子目錄中出現的設備都是用符號鏈接指向/sys/devices/目錄下的文件。

2.設備類是對/sys/devices/下的各種設備進行歸類,以體現一類設備的公共屬性,如鼠標和觸摸屏都是屬於input設備類。

3.總線目錄是總線、設備、驅動模型的核心目錄。因爲設備和驅動都是依附在某種總線上的,如USB、PCI和平臺總線等。設備和驅動正是依靠總線的管理功能才能找到對方,如設備註冊到總線時去尋找驅動,而驅動註冊的時候去尋找其能夠支持的設備。

一、申請設備號:

    1.動態申請設備號(alloc_chrdev_region)

    2.靜態申請設備號(register_chrdev_region)

二、設備註冊:

    1.爲cdev分配空間(cdev_alloc)。爲字符設備分配空間。

    2.初始化cdev(cdev_init)。字符設備初始化,綁定相關操作到設備

    3.將cdev添加進Kernel(cdev_add)。把設備號和設備關聯起來。

三、生成設備節點

    1.創建設備類(class_create)

    2.通過設備類,創建設備節點(device_create)

字符驅動程序:
 

  • #include <linux/kernel.h>
    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/delay.h> /*delay*/
    #include <linux/cdev.h>
    #include <linux/device.h>
    #include <linux/slab.h>	/*kmalloc*/
    #include <linux/vmalloc.h> /*vmalloc*/
    #include <linux/types.h>   /*ssize_t*/
    #include <linux/fs.h>	  /*file_operaiotns*/
    #include <linux/gpio_keys.h>
    #include <linux/gpio.h>
    #include <linux/irq.h>
    #include <linux/interrupt.h>
    #include <linux/sched.h>
    #include <asm/irq.h>
    #include <asm/io.h>
    #include <asm/uaccess.h>
    #include <asm-generic/ioctl.h>
    #include <asm-generic/errno-base.h>
    
    /************硬件相關*************/
    #include <mach/iomux-mx6dl.h>
    
    #define DEV_NAME "gpios"
    
    /**主設備號和次設備號**/
    int device_major = 0;
    int device_minor = 0;
    static struct class *gpio_class;	/*在/sys目錄創造一個類*/
    static struct cdev *gpio_class_dev; /*在這個類下,創造一個設備節點*/
    
    /*open函數的實現*/
    static int gpio_open(struct inode *inode, struct file *file)
    {
    
    	printk(KERN_ALERT "OPEN\n");
    	return 0;
    }
    
    static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    {
    	printk(KERN_ALERT "ioctl\n");
    	return 0;
    }
    
    /*release函數的實現*/
    static int gpio_close(struct inode *inode, struct file *file)
    {
    
    	printk(KERN_ALERT "close\n");
    	return 0;
    }
    
    ssize_t gpio_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
    {
    
    	printk(KERN_ALERT "read\n");
    	return 0;
    }
    
    /*具體的文件操作集合*/
    static const struct file_operations gpio_fops =
    	{
    		/*這是擁有者*/
    		.owner = THIS_MODULE,
    		.open = gpio_open,
    		.unlocked_ioctl = gpio_ioctl,
    		.release = gpio_close,
    		.read = gpio_read,
    };
    
    /*驅動的初始化函數*/
    static int gpio_init(void)
    {
    	int ret;
    	dev_t gpio_dev_no; //設備號
    
    	if (device_major)
    	{
    		gpio_dev_no = MKDEV(device_major, device_minor);
    		register_chrdev_region(gpio_dev_no, 1, DEV_NAME);
    	}
    	else
    	{
    		ret = alloc_chrdev_region(&gpio_dev_no, 0, 1, DEV_NAME);
    		if (ret)
    		{
    			printk(KERN_ALERT "alloc_chrdev_region failed\n");
    		}
    		device_major = MAJOR(gpio_dev_no);
    		device_minor = MINOR(gpio_dev_no);
    		printk(KERN_ALERT "major=%d minor=%d\n", MAJOR(gpio_dev_no), MINOR(gpio_dev_no));
    	}
    
    	gpio_class_dev = cdev_alloc();								  //分配空間
    	cdev_init(gpio_class_dev, &gpio_fops);	/*字符設備初始化,綁定相關操作到設備*/
    	gpio_class_dev->owner = THIS_MODULE;						  /*設備的擁有者*/
    	cdev_add(gpio_class_dev, gpio_dev_no, 1);/*添加設備到內核*/
    	gpio_class = class_create(THIS_MODULE, DEV_NAME); /*創建設備類,用於自動創建設備文件*/
    	device_create(gpio_class, NULL, gpio_dev_no, NULL, DEV_NAME); /*依據以前創建的設備類,創建設備*/
    	return 0;
    }
    
    /*退出函數*/
    static void gpio_exit(void)
    {
    	/*設備卸載*/
    	cdev_del(gpio_class_dev);										//註銷設備
    	unregister_chrdev_region(MKDEV(device_major, device_minor), 1); //釋放設備號
    	device_destroy(gpio_class, MKDEV(device_major, device_minor));
    	class_destroy(gpio_class);
    }
    
    /*LICENSE信息*/
    MODULE_LICENSE("GPL");
    /*卸載和加載*/
    module_init(gpio_init);
    module_exit(gpio_exit);
    

測試程序:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <poll.h>
#include <signal.h>
#include <asm-generic/ioctl.h>

int main(int args, char *argv[])
{
    int fd, val,ret;
	unsigned char buffer[10]={0};
	
	fd = open("/dev/gpios",O_RDWR);	
	if(fd < 0)	
	{		
		printf("can't open %s\n","/dev/gpios");
	}
	sleep(2);		
	ret= read(fd,buffer,0);
	sleep(2);
	ioctl(fd,0,NULL);
	sleep(2);
    close(fd);
    return 0;
}

 

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