设备驱动:为应用层提供了访问设备的接口
字符设备:mouse/keyboard/串口/帧缓存... 以字节为单位访问,一般只支持顺序访问,无缓冲
块设备:disk/flash... 以固定大小为单位访问 支持随机访问 ,有缓冲
网络设备:无设备文件 通过socket访问
虚拟文件系统(VFS):为应用层提供了统一的文件访问接口
设备驱动编写步骤:
一、申请设备号
设备号作用:识别设备
设备号 为32位无符号整形数
低20位为次设备号,高12位为主设备号
主设备号(major)
|
次设备号(minor)
|
区别不同类型的设备
|
区分同一类型的不同设备
|
获取设备号用MKDEV 函数:
-
int hello_major = 250;
-
int hello_minor = 0;
-
dev_t dev = 0;
-
-
dev = MKDEV (hello_major, hello_minor);
查看当前版本内核中设备号的使用情况:内核/Document 下 devices.txt 文本中
申请设备号:
1、静态申请
-
申请设备号:
-
result = register_chrdev_region (dev, number_of_devices, "hello");
-
if (result<0) {
-
printk (KERN_WARNING "hello: can't get major number %d\n", hello_major);
-
return result;
-
}
-
释放设备号:
-
unregister_chrdev_region (dev, number_of_devices);
/proc/devices 存放系统中当前已经申请的设备号
2.动态申请
int alloc_chrdev_region(dev_t *dev,unsigned baseminor,unsigned count,const char *name)
静态申请和动态申请比较:
静态申请可以提前创建设备文件,动态申请不会设备号冲突
二、定义操作集合:
设备操作:打开,关闭,读,写
struct file_operations 字符设备操作集合结构体
成员 .owner = THIS_MODULE ;只有这一种复制
三、注册字符设备
通过cdev 把设备号和操作集合相关联,并且添加到内核cdev链表中,
如:struct cdev cdev;
cdev.owner = THIS_MODULE;
cdev_init(&cdev,&hello_ops);
cdev_add(&cdev,dev,1);
创建设备节点:mknod /dev/hello c 250 0
删除设备节点:rmmod /dev/hello
常见错误:
mknod /dev/hello c 250 0
mknod /dev/hello c 251 0
创建第二个设备节点时错误,因为linux下不能有同名文件。
下面这个用法则可以:
mknod /dev/hello c 250 0
mknod /dev/hi c 250 0
这样创建节点 ,无论打开哪个,只要设备号一样 打开的是同一个设备
驱动源码:
-
#include <linux/module.h>
-
#include <linux/kernel.h>
-
#include <linux/init.h>
-
#include <linux/cdev.h>
-
#include <linux/fs.h>
-
-
MODULE_LICENSE ("GPL"); //必须遵循GPL协议
-
-
int hello_major = 250; //主设备号
-
int hello_minor = 0; //次设备号
-
int number_of_devices = 1; //设备数
-
-
struct cdev cdev;
-
-
struct file_operations hello_ops =
-
{
-
.owner = THIS_MODULE
-
};
-
-
static void char_reg_setup_cdev(void) //注册设备
-
{
-
dev_t dev = MKDEV (hello_major,hello_minor);
-
int error;
-
-
cdev_init(&cdev,&hello_ops);
-
error = cdev_add(&cdev,dev,1);
-
if(error)
-
printk("Error %d cdev_add",error);
-
-
}
-
-
static int __init hello_2_init (void) //初始化函数
-
{
-
int result;
-
dev_t dev = 0;
-
-
dev = MKDEV (hello_major, hello_minor);
-
result = register_chrdev_region (dev, number_of_devices, "hello"); //申请设备号
-
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 "Registered character driver\n");
-
-
return 0;
-
}
-
-
static void __exit hello_2_exit (void)
-
{
-
dev_t dev = MKDEV (hello_major, hello_minor);
-
-
cdev_del(&cdev); //接触关联
-
-
unregister_chrdev_region (dev, number_of_devices); //释放设备号
-
-
printk (KERN_INFO "Char driver cleaned up\n");
-
}
-
-
module_init (hello_2_init);
-
module_exit (hello_2_exit);
阅读(1140) | 评论(0) | 转发(0) |