設備驅動模型通過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;
}