驱动开发-模块
来源:互联网 发布:怎么成为算法工程师 编辑:程序博客网 时间:2024/05/01 20:08
驱动开发-
atexit – 程序终止时释放空间
void function(void){ printf("1\n");}void function1(void){ printf("2\n");}int main(int argc,char \*argv[]){ printf("duang\n"); atexit(function); printf("fang\n"); atexit(function1); return 0;}
输出结果
duang
fang
2
1exit比return 0多一个刷新缓冲区功能
exit–>释放空间
_exit–>不释放空间
应用程序和模块区别
- 入口函数
- 运行空间
- 调用函数
- 资源释放
应用程序 模块函数 自动释放或者手动释放 手动释放
什么程序可以编译生成模块
- 在linux下,有三大设备驱动
- 字符设备 –> led, beep,key,adc,mpu6050,usb,lcd
- 一般按字节的形式访问,顺序访问 char
- 一般按字节的形式访问,顺序访问 char
- 块设备 –> emmc,nand flash,nor flash,sd
- 固定大小随机访问,linux系统下block 512byte
- 固定大小随机访问,linux系统下block 512byte
- 网络设备驱动 –> 网卡
- 有自己的协议
- 有自己的协议
- 字符设备 –> led, beep,key,adc,mpu6050,usb,lcd
如何编写模块
如果想在内核中编译模块,必须在make menuconfig 中配置驱动程序才可以编译生成模块:make modules .o –> .ko
1. 模块分成内部模块和外部模块2. 编译模块的条件 - 必须是已经 编译过的内核 --> make - 必须是已经 配置过的内核 --> make menuconfig3. 在内核的源码目录外编译4. 采用模块化编程
模块的入口函数 –> 申请资源
module_init() --> 模块的入口函数// 函数的返回值typedef init (\*initcall_t)(void);
模块的出口函数 –> 释放资源
module_exit() --> 模块的出口函数// 函数的返回值typedef void (\*exitcall_t)(void);
C程序编程
//编写入口函数和出口函数 int hello_init(void) { //资源的申请 } void hello_exit(void) { //资源的释放 } module_init(); module_exit(); ```-------------------------### 查看内核和安装模块- 查看内核 <br/> 1. 添加文件索引 `make tags` <br/> 2. 搜索函数名 `vi -t module_init` <br/>- 模块的命令 1. 安装模块 <br/> `insmod 文件名` 2. 卸载模块 <br/> `rmmod 模块名` 2. 查看模块 <br/> `lsmod ` 3. 查看内核后台的打印信息 <br/> `dmesg` 4. 清空内核后台的打印信息 <br/> `dmesg -c`------------------------------------### 字符设备驱动> 应用程序是通过设备号找到驱动程序,在linux系统设备号是唯一的。- 内核定义设备号通过设备号可以找到对应的驱动程序,驱动程序可以绑定设备号- 设备号 是32bit的无符号整数 - 其中高12bit表示的是主设备号,低20位表示的是次设备号 - 主设备号:表示哪一类设备 - 次设备号:表示这一类设备的第几个设备- 申请设备号 -- 静态申请和动态申请 - 静态申请 int marjor = 250; int minor = 0; int decno = major << 20 | minor 内核申请设备号的函数 dev_t devno = MAKDEV(marjor,minor); MAKDEV - 注册字符设备号 ```c register_chrdev_region(); int register_chrdev_region(dev_t from, unsigned count,const char \*name); 参数 dev_t from 设备号 unsigned count 申请设备号的个数 const char * name 设备或者驱动的名字 返回值 成功返回0,失败返回错误码 int ret; ret register_chrdev_region("devno",1,"hello"); if(0 != ret) { return -EBUSY; } ``` - 释放设备号 ```c unregister_chrdev_region(); void unregister_chrdev_region(dev_t from,unsigned count); 参数 dev_t from 设备号 unsigned count 设备号的个数 unregister_chrdev_region(devno,1); ``` - 查看系统中注册的设备号 <br/> `cat /proc/devices`----------------------------------------### 初始化cdev结构体- 查看系统中已经注册的设备号 <br/>`cat /proc/devices`--------------------------------------1. 初始化cdev结构体 - **cdev_init()函数**```c555 * @fops: the file_operations for this device556 *557 * Initializes @cdev, remembering @fops, making it ready to add to the558 * system with cdev_add();559 *560 void cdev_init(struct cdev \*cdev, const struct file_operations \*fops);参数: struct cdev *cdev:cdev结构体 struct file_operations * ops:操作函数的接口<div class="se-preview-section-delimiter"></div>
- **struct cdev \*cdev**
struct cdev{ struct kobject kobj; // 内嵌的kobject对象 struct module \*owner; // 所属模块 const struct file_operations \*ops; // 文件操作结构体 struct list_head list; //linux内核所维护的链表指针 dev_t dev; //设备号 unsigned int count;};<div class="se-preview-section-delimiter"></div>
- **struct file_operations**
struct file_operations {
struct module *owner;//拥有该结构的模块的指针,一般为THIS_MODULES
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);//仅用于读取目录,对于设备文件,该字段为NULL
unsigned int (*poll) (struct file *, struct poll_table_struct *); //轮询函数,判断目前是否可以进行非阻塞的读写或写入
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); //执行设备I/O控制命令
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); //不使用BLK文件系统,将使用此种函数指针代替ioctl
long (*compat_ioctl) (struct file *, unsigned int, unsigned long); //在64位系统上,32位的ioctl调用将使用此函数指针代替
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); //通知设备FASYNC标志发生变化
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 **);
};
Linux使用file_operations结构访问驱动程序的函数,这个结构的每一个成员的名字都对应着一个调用。用户进程利用在对设备文件进行诸如read/write操作的时候,系统调用通过设备文件的主设备号找到相应的设备驱动程序,然后读取这个数据结构相应的函数指针,接着把控制权交给该函数,这是Linux的设备驱动程序工作的基本原理。
- **cdev_add()函数**
c
464 **
465 * cdev_add(); - add a char device to the system
466 * @p: the cdev structure for the device
467 * @dev: the first device number for which this device is responsible
468 * @count: the number of consecutive minor numbers corresponding to this
469 * device
470 *
471 * cdev_add(); adds the device represented by @p to the system, making it
472 * live immediately. A negative error code is returned on failure.
473 *
474 int cdev_add(struct cdev \*p, dev_t dev, unsigned count)
参数: struct cdev * p:字符设备
dev_t devno;设备号
unsigned count :次设备号的个数
- **删除cdev结构体**
496 **497 * cdev_del(); - remove a cdev from the system498 * @p: the cdev structure to be removed499 * 500 * cdev_del(); removes @p from the system, possibly freeing the structure501 * itself.502 *503 void cdev_del(struct cdev \*p)504 {505 cdev_unmap(p->dev, p->count);506 kobject_put(&p->kobj);507 }
- 驱动开发-模块
- 驱动开发之模块
- linux驱动开发-模块参数
- RTC模块驱动开发总结
- linux驱动开发第二帖--模块参数
- usb驱动识别模块开发(一)
- linux 模块驱动开发第一弹 helloworld
- 利用Eclipse开发Linux驱动模块
- linux驱动开发--内核模块参数
- 【嵌入式Linux驱动开发】二、模块
- linux驱动开发——模块基础知识
- linux内核驱动开发--编译外部模块
- linux 驱动开发-模块的构建
- linux驱动开发-模块多文件编译
- 复位按键模块设备驱动开发
- Linux 驱动开发内核模块的添加
- 第四十二天:Tiny4412模块驱动开发
- 3G 模块驱动应用开发总结
- STL中vector查找算法find()和find_if()深入比较
- 下载字体库的地址
- 文章标题
- 系统移植-文件系统移植
- Ubuntu下使用Eclipse和PyDev搭建完美Python开发环境
- 驱动开发-模块
- 2016/4/28所学大致总结
- if语句与switch的使用
- centos 6 下编译打包 ceph 10.2.0
- 【Android】Android的Activity生命周期
- Solaris 10环境下安装oracle Client
- 布局 网页 切换栏目 有个new 的字样的 布局, 害的我被说
- 编译和反编译
- git初次接触记录简单一些用法