日期:2014-05-16 浏览次数:20903 次
P { MARGIN-TOP: 0px; MARGIN-BOTTOM: 0px }
设备号
创建设备文件
设备注册
重要数据结构
设备操作
?
设备号
用ls -l查看,设备文件项中有两个数(中间有逗号),是为主次设备编号
?
字符设备文件调用字符设备驱动访问硬件
?
主设备号用来标识驱动程序,次设备号被驱动程序用来辨别操作的是那个设备
?
主设备号反映设备类型,次设备号用来区分同类型的设备
?
内核中使用dev_t这个类型描述设备号,为unsigned int 32位,其中高12位为主设备号,低20位为次设备号
?
MAJOR(dev_t dev)提取主设备号
MINOR(dev_t dev)提取次设备号
?
内核采用静态申请、动态申请的方法给设备分配主设备号
?
静态申请
根据documenta/devices.txt,找出没有使用的主设备号,使用regist_chrdev_region函数注册设备号
可能导致冲突
?
int register_chrdev_region(
dev_t from,?????? 希望申请的设备号
unsigned count,? 设备数量
const char *name 设备名称,体现在/proc/devices
)
?
动态申请
alloc_chrdev_region分配设备号
优点:易于推广
缺点:是无法在安装驱动前创建设备文件(还没分配主设备号)
解决办法:
安装驱动后,从/proc/devices中查询设备号
?
int alloc_chrdev_region(
dev_t *dev, 无需传值,写入
unsigned baseminor, 起始次设备号
unsigned count, 设备数目
const char *name 设备名称
)
?
设备注销
不再使用设备时,应注销掉设备号
?
void unregistor_chrdev_region( dev_t from, unsigned count)
?
创建设备文件
?
1、使用mknod命令手工创建
?
mknod filename type major minor
参数:文件名、类型、主设备号、次设备号
如:mknod serial0 c 100 0
?
2、自动创建
在驱动程序中,通过函数调用
?
设备文件的作用
设备文件本身无任何内容,只是在应用程序与设备驱动之间建立桥梁,帮助应用程序
?
文件数据结构
?
Struct file 代表一个打开的文件。每个打开的文件在内核空间都有一个关联的struct file,记录文件读写位置。一个文件打开10次,则有10个Struct file。内核打开文件时创建,关闭后释放
主要成员:
loff_t f_pos 文件读写位置
struct file_operations *f_op
?
Struct inode 记录文件物理上的信息
Struct file_operations 一个函数指针的集合,定义能在设备上进行的操作 。结构中的成员指向驱动中的函数
?
strunct file_operations mem_fops = {
.owner = THIS_MODULE,
.llseek = mem_seek,
.read = mem_read,
.write = mem_write,
.ioctl = mem_ioctl,
.open = mem_open,
.release = mem_release,
};
?
字符设备的注册
在linux 2.6内核中,字符设备使用struct cdev这个结构来描述:
1、分配 cdev
struct cdev *cdev_alloc(void)
2、初始化 cdev
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
3、添加 cdev
init cdev_add(struct cdev *p, dev_t dev, unsigned count)
参数:设备、设备号、数目
?
实现file_operations里面注册的函数
int (*open)(struct inode *, struct file *)
打开这个设备,并不要求驱动程序一定要实现, open = NULL表示设备永远打开,不需要手动打开
?
void (*release)(struct inode *, struct file *)
关闭设备
?
read 读
write 写
poll 对应select系统调用
ioctl 控制设备
mmap 将设备映射到进程虚拟地址空间
llseek 修改文件的当前读写位置,并将新位置作为返回值
?
?
open函数
int (*open)(struct inode *, struct file *)
初始化设备、标明次设备号
?
读和写
ssize_t xxx_read(struct file * filp, char __user * buff, size_t count, loff_t * offp);
ssize_t xxx_write(struct file * filp, char __user * buff, size_t count, loff_t * offp);
filp=文件指针,(正在操纵的文件)
count=请求传输的数据量,对应系统调用里传入的count
buff = 参数指向数据缓存 ,对应系统调用里传入的fuff, 是用户空间指针,不能被内核代码直接引用(用户空间指针在内核空间可能是无效的,没有那个地址的映射)
offp = 指出文件的当前访问位置(字节索引) 内核会把Struct file里面的loff_t f_pos 植入这个参数
?
内核提供了专门的函数访问用户空间指针
int copy_from_user(void *to, const void_user *from, int n)? == write 数据从用户流向驱动
int copy_to_user(void __user *to, const void *from, int n) ==read 数据从驱动流向用户
?
设备注销
int cdev_del(struct cdev *p)
?
字符设备驱动程序 memdev.c
?
module_init() 内核模块