字符驱动程序
1 设备号
字符设备通过字符设备文件来存取
ls -l 如果输出的第一列是c标识,说明该文件是字符设备文件
设备文件项中的两个数分别为 主设备号/次设备号
设备文件与设备驱动通过主设备号建立联系
次设备号用来分辩操作的哪个设备
dev_t 用来描述设备号 在linux/types.h中声明,示例代码如下:
typedef __u32 __kernel_dev_t;
typedef __kernel_fd_setfd_set;
typedef __kernel_dev_tdev_t;
实质为unsigned int 32位整数,高难12位为主设备号,低12位为次设备号
#主设备号
MAJOR(dev_t dev)
#次设备号
MINOR(dev_t dev)
#将主设备号和次设备号转化为dev_t
MKDEV(int major,int minor)
以上几个宏在linux/kdev_t.h中声明
示例代码如下:
#define MAJOR(dev)((dev)>>8)
#define MINOR(dev)((dev) & 0xff)
#define MKDEV(ma,mi)((ma)<<8 | (mi))
linux内核有两种分配设备号的方法
1 静态申请
根据Documentation/devices.txt 确定设备号是否使用
使用register_chardev_region函数来注册设备号,在linux/fs.h中声明
extern int register_chrdev_region(dev_t from, unsigned count, const
char *name);
form: 需要申请的设备号
count:设备号数目
name:设备名
2 动态分配(推荐使用)
使用alloc_chardev_region函数来注册设备号,在linux/fs.h中声明
extern int alloc_chrdev_region(dev_t *dev, unsigned baseminor,
unsigned count, const char *name);
dev:分配的设备号
baseminor: 起始次设备号
count:设备号数目
name:设备名
缺点:无法在安装驱动前创建设备文件
安装驱动后,从/proc/devices中查询设备号
注:对于动态分配设备号的设备驱动程序,对insmod的调用可以替换为一个角
本,角本的主要内容:
1 调用insmod
2 在调用insmod后读取proc/devices取的新分配的主设备号
3 创建设备文件
可以使用awk工具取得proc/devices信息
示例代码如下:
#!/bin/sh
driver="test"
echo "角本执行 ...wait"
#读取/proc/devices信息
major=$(awk "{if(\$2==\"$driver\") {print \$1}}" /proc/devices)
echo $major
#创建设备文件
mknod /dev/$driver0 c $major 0
注销设备号
void unregister_chrdev_region(dev_t from,unsigned count)
form:起始设备号
count:设备号数目
2 创建设备文件
mknod命令手工创建
mknod filename type major minor
filename:设备文件名
type:设备文件类型
major: 主设备号
minor: 次设备号
自动创建
3 设备注册
4 重要数据结构
#打开一个文件
struct file
重要成员:
/*文件模式*/
mode_t f_mode
/*文件读写位置*/
loff_t f_pos
/*与文件相关的操作*/
struct file_operations *f_op
/*文件标志*/
unsigned int f_flags
/*跨系统调用时保存状态信息 */
void *private_data
/*文件对应的目录项结构*/
struct dentry *f_dentry
#用来记录文件物理上的信息
#一个文件可以对应多个file结构,但只有一个inode结构
struct inode
重要成员:
/*设备号*/
dev_t i_rdev
/*字符设备内核的内部结构*/
sturct cdev *i_cdev
/*从一个inode中取得主从设备号最好使用以下两个宏*/
unsigned int iminor(struct inode *inode);
unsigned int imajor(struct inode *inode)
#一个函数指针的集合,定义能在设备上进行的操作,在linux/fs.h中声明
struct file_operations
示例代码如下;
/*
* NOTE:
* read, write, poll, fsync, readv, writev, unlocked_ioctl and
compat_ioctl
* can be called without the big kernel lock held in all filesystems.
*/
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t
*);
ssize_t (*write) (struct file *, const char __user *, size_t,
loff_t *);
ssize_t (*aio_read) (struct kiocb *, const struct iovec *,
unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *,
unsigned long, loff_t);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct
*);
int (*ioctl) (struct inode *, struct file *, unsigned int,
unsigned long);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned
long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned
long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, struct dentry *, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t,
loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned
long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file
*, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct
pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **);
};
static const struct file_operations mem_fops = {
.llseek = memory_lseek,
.read= read_mem,
.write = write_mem,
.mmap= mmap_mem,
.open= open_mem,
.get_unmapped_area = get_unmapped_area_mem,
};
应用程序访问驱动程序的过程
read_write.c示例代码如下:
读文件
ssize_t vfs_read(struct file *file, char __user *buf, size_t count,
loff_t *pos){
...
/*f_op是file_operations,就是调用其中的read方法来完成*/
ret = file->f_op->read(file, buf, count, pos);
...
}
5 设备注册
字符设备是用struct cdev 来描述
字符设备的注册分为以下三步;
1 分配cdev
struct cdev *cdev_alloc(void)
2 初始化cdev
void cdev_init(struct cdev *cdev,const struct
file_operstions *fops)
cdev:要初始化的cdev结构
fops:设备对应的操作函数集
3 添加cdev
int cdev_add(struct cdev *p,dev_t dev,unsigned count)
p:要添加的字符设备结构
dev:设备号
count:添加设备的个数
设备注销
int cdev_del(struct cdev *p)
p:要注销的字符设备结构
6 设备操作
/*完成一些初始化工作
检查设备特定的错误码
首次打开则进行初始化
更新f_op指针
分配填写filp->private_data数据结构
*/
int (*open)(struct inode *,sturct file *)
/*设备关闭时调用这个操作*/
void (*release)(struct inode *,struct file *)
/*从设备中读取数据*/
ssize_t (*read) (struct file *,char__user *,size_t,loff_t *)
/*向设备发送数据*/
ssize_t (*write) (struct file *,const char__user *,size_t,loff_t *)
ssize_t xxx_read (struct file *filp,char__user *buff,size_t
count,loff_t *offp)
ssize_t xxx_write (struct file *filp,const char__user *buff,size_t
count,loff_t *offp)
filp:文件指针
count:请求传输的数据量
buff:参数指向的数据缓存
offp:文件当前的访问位置
注:buff参数是用户空间的指针,不能被内核代码直接引用
用于访问用户空间的指针的方法有:
int copy_from_user(void *to,const void__user *from,int n);
int copy_to_user(void __user *to,const void *from,int n);
/*对应select系统调用*/
unsigned int (*poll) (struct file *,struct poll_table_struct *)
/*控制设备*/
int (*ioctl)(struct inode *,struct file *,unsigned int,unsigned
long)
/*将设备映射到进程虚拟空间中*/
int (*mmap) (struct file *,struct vm_area_struct *)
/*修改文件的当前读写位置*/
off_t (*llseek) (sturct file *, loff_t,int)
- 浏览: 263224 次
- 性别:
- 来自: 济南
文章分类
- 全部博客 (303)
- c (31)
- c++ (16)
- java (18)
- c# (1)
- python (3)
- java web (6)
- oracle (7)
- sqlserver (2)
- mysql (2)
- android (24)
- android系统 (15)
- android多媒体部分 (15)
- android游戏 (12)
- linux (26)
- javaScript (1)
- ajax (1)
- node JS (2)
- html (5)
- apache (3)
- jboss (1)
- weblogic (0)
- 通信协议 (10)
- 云计算 (1)
- 分布式 (5)
- ejb (1)
- webservice (5)
- 设计模式 (16)
- JNI (6)
- swing (13)
- 版本控制 (1)
- UML (1)
- xml (4)
- spring (5)
- hibernate (5)
- struts1 (3)
- struts2 (4)
- ibatis (0)
- tomcat (2)
- 心得体会 (1)
- css (1)
- 嵌入式 (41)
- arm体系结构 (10)
发表评论
-
u-boot Makefile 文件分析
2013-06-01 21:44 2429Makefile文件分析 # #(C)Copyri ... -
uboot start.S文件分析
2013-06-03 22:18 1325U-boot第一个开始文件arch\arm\cpu\arm1 ... -
u-boot mkconfig文件分析
2013-05-31 21:29 1140Mkconfig文件分析 #!/bin/ ... -
链接地址学习笔记
2013-05-05 12:40 1287链接地址 启动过程 示例代码如下: ... -
DDR学习笔记
2013-05-11 14:19 1041DDR 15条地址线32k 128M*2(20)=2(2 ... -
nand flash学习笔记一
2013-05-13 21:05 962Nandflash 原理图上有data0-data7 ... -
openJTAG学习笔记一
2013-05-22 21:45 2183安装软件 光盘Windows\install目录下的 01.O ... -
linux进程管理学习笔记
2013-03-28 20:57 1367linux 进程管理 1 linux进程控制 进程的四个要素: ... -
字符设备驱动程序学习笔记一
2013-04-01 21:55 889linux 驱动程序 字符设备驱动程序 网络接口驱动程序 块设 ... -
字符设备驱动程序学习笔记三
2013-04-04 14:03 789memdev.h文件示例代码如下: #ifndef _MEM ... -
字符设备驱动程序学习笔记四
2013-04-05 11:12 589竟争与互斥 程序调试 1 ... -
GPIO学习笔记
2013-04-14 19:50 813用汇编点亮一个led 1看原理图GPK4=0,led亮G ... -
系统时钟学习笔记
2013-05-04 21:59 83712m晶振----->pll------>cpu ... -
UART学习笔记
2013-05-04 22:00 1167串口(UART) DIV_VAL=(PCLK/(bpsx1 ... -
linux内存管理学习笔记
2013-03-12 20:50 10781 linux内存管理 地址类型 物理地址 出现在cpu地址 ... -
嵌入式linux系统学习笔记
2013-03-06 21:39 973嵌入式linux内核制作 1 清除原有配置文件与中间文件 x8 ... -
原理图学习笔记一
2013-02-17 22:24 425画个草图也挺过瘾 -
进程间通信学习笔记一(管道通信)
2013-02-01 20:08 1418进程间通信(ipc) 应用场景: 数据传输 资源共享 通知事件 ... -
进程间通信学习笔记二(信号通信)
2013-02-16 21:39 793信号通信 用户按某些键时,产生信号 硬件异常产生信号 进程用k ... -
进程间通信学习笔记三(共享内存通信)
2013-02-16 21:40 608共享内存通信 被多个进程共享的一部分物理内存,是进程间共享数据 ...
相关推荐
Linux 字符设备驱动程序学习笔记 Linux 字符设备驱动程序是 Linux 操作系统中的一种驱动程序,负责管理字符设备的输入和输出操作。字符设备是一种按字节来访问的设备,字符驱动则负责驱动字符设备,这样的驱动通常...
Linux 字符设备驱动学习笔记 本文档主要讲述 Linux 字符设备驱动学习笔记,涵盖了设备文件、主次设备号、字符设备驱动中的数据结构等知识点。 一、 设备文件 设备文件是一种特殊类型的文件,用来代表一个设备。...
"Linux内核与设备驱动程序学习笔记"可能包含了以下内容: 1. **内核模块**:内核模块是可加载到运行中的内核中的代码段,允许用户动态添加或移除设备驱动。这使得系统可以在需要时加载特定驱动,节省内存。 2. **...
这篇“字符设备驱动学习笔记(2.6.23)”文档针对的是Linux内核版本2.6.23,这可能是2007年的内核版本,当时Linux系统已经相当成熟,但相对于最新的内核版本,它可能不包含一些新特性或优化。 学习Linux字符设备驱动...
《Linux设备驱动程序(2)-字符设备驱动程序》将介绍如何实现基本的字符设备驱动,包括设备节点创建、打开、关闭、读写等操作。 3. **高级字符驱动程序操作**:在《Linux设备驱动程序(7)-高级字符驱动程序操作2》...
学习Linux设备驱动程序是深入了解Linux操作系统工作原理的重要步骤,同时也是嵌入式系统开发中不可或缺的知识。 首先,设备驱动程序在Linux内核中扮演着特殊的角色。它是硬件与内核之间的中介,使得硬件能够响应一...
Linux字符设备驱动是操作系统与硬件设备交互的关键组件,它提供了软件层面与硬件设备通信的接口。在Linux系统中,设备通常被表示为文件,这种特殊类型的文件被称为设备文件。设备文件使得用户空间的应用程序能够通过...
本学习笔记主要关注于如何开发这些驱动程序,涉及C和C++编程语言,系统编程,网络编程以及ARM架构的驱动开发。 首先,了解基本的数据结构对于开发设备驱动至关重要。数据结构是组织和存储数据的方式,它影响着算法...
### Windows驱动程序开发学习笔记知识点解析 #### 一、Windows驱动程序开发概述 - **学习背景**: 学习者最初接触Windows驱动程序开发时遇到不少困难,经历了一段时间的摸索后逐渐入门。这一过程中,作者参考了...
本文主要讲述了s3c2440 Linux设备驱动开发过程中的重要细节,包括字符设备驱动程序的设计、实现和测试。下面是相关知识点的总结: 1. 设备驱动程序的基本结构: 在Linux设备驱动程序中,需要定义一个结构体file_...
《Linux设备驱动程序学习》是一本深入探讨Linux操作系统下设备驱动程序开发的教程,共170页。这本书旨在帮助读者理解Linux内核与设备之间的交互机制,掌握编写高效、稳定设备驱动的基本技能。标签“Linux 设备驱动 ...
本学习笔记主要关注Linux环境下对设备驱动程序的构建和优化,这是一门涉及多方面知识的综合学科。 首先,我们要理解Linux设备驱动的基本概念。在Linux系统中,设备驱动是操作系统内核的一部分,它提供了与硬件设备...
《Linux 设备驱动开发详解》是宋宝华先生的一本经典著作,专注于讲解Linux系统下的设备驱动程序开发。这本书深入浅出地介绍了如何为各种硬件设备编写驱动程序,是嵌入式Linux开发者的重要参考资料。在学习这本书的...
这份"Linux设备驱动程序笔记"深入浅出地讲解了如何编写和理解这些程序,对于学习Linux内核机制和提升系统开发能力具有极大价值。 笔记可能涵盖了以下几个核心知识点: 1. **设备模型**:Linux设备模型提供了一种...
以上就是《Linux设备驱动程序》第三版学习笔记的主要内容,涵盖了Linux驱动开发的各个方面。通过深入学习和实践,你可以掌握构建高效、可靠的Linux驱动程序的技巧,为你的Linux开发事业奠定坚实的基础。
以下是 Linux Kernel 的学习笔记,涵盖了存储器寻址、设备驱动程序开发、字符设备驱动程序、PCI 设备、内核初始化优化宏、访问内核参数的接口、内核初始化选项、内核模块编程和网络子系统等方面的知识点。...