设备驱动模型通过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;
}