1.模块化编程
按照Linux规定模块的形式添加代码
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("GPL v2");
static int hello_init(void) //入口函数
{
printk("Hello linux module init!\n");
return 0;
}
static void hello_exit(void)//出口函数
{
printk("Hello linux module exit!\n");
}
module_init(hello_init);//告诉linux模块入口函数,加载模块代码到操作系统的时候会调用
module_exit(hello_exit);//告诉linux模块出口函数,从操作系统中卸载模块代码的时候调用
Makefile的编写
思想:
Linux 内核源码的编译系统可以编译我们编写的模块代码
第一种(产品发布):
将自己编写的代码,拷贝到Linux内核源码树下,然后配置编译,编译进内核
第二种(驱动调试):
自己编写Makefile,然后使用Linux内核的编译系统,编译自己的模块代码
问:Linux内核的编译系统在哪里?
答:
<1>Linux内核源码下的Makefile
注意:
你的Linux内核源码必须已经根据自己所开发的平台进行了配置
[1]修改了Makefile,指定了开发工具链
[2]已经使用Linux内核默认配置文件进行了配置
<2>ubuntu系统自带的Linux内核编译系统(pc机,x86)
/lib/modules/3.13.0-32-generic/build/Makefile
问:如何在自己编写的Makefile中使用Linux内核的编译系统
答:make -C linux内核编译系统的路径 M=需要编译的模块代码路径 modules
make 调用当前目录下的Makefile-----------切换到------------>linux内核编译系统的路径Makefile
ifeq ($(KERNELRELEASE),)
KERNEL_BUILD=/lib/modules/$(shell uname -r)/build 记录Linux内核的编译系统路径
MODULE_PATH =$(shell pwd) 记录模块代码的路径
module:
$(MAKE) -C $(KERNEL_BUILD) M=$(MODULE_PATH) modules
make -C /lib/modules/$(shell uname -r)/build M=记录模块代码的路径 modules
clean:
$(MAKE) -C $(KERNEL_BUILD) M=$(MODULE_PATH) clean
else
obj-m = hello_module.o
endif
Makefile调用图
2.注册字符设备
七 写字符设备驱动,驱动需要包含哪些信息
1.设备号
|
|
2.struct cdev
|
|
|
3.一组函数接口 -----> struct file_operations
LED驱动----字符设备驱动注册
1.应用层的进程如何访问底层的驱动程序
字符设备或块设备,我们可以通过设备文件(属性信息中包含的设备号)来找到底层驱动程序
---------------------------------------------------------------------------------------
驱动的标识:设备号
12bit(主设备号) + 20bit(次设备号) = 32bit
主设备号:标识一类设备
次设备号:为了区分同类型设备的不同设备
----------------------------------------------------------------------------------------
问:Linux内核有那么多驱动程序,如何才能确定自己需要访问的驱动程序?
答:通过设备文件中包含的设备号信息
问:Linux内核中,如何描述描述文件?
答:<1>struct inode 描述文件属性信息(文件类型,权限,大小,修改时间,设备号[设备文件])
<2>struct file 描述一个打开的文件(打开的方式,文件偏移量,...)
[注意:只要打开一次文件,就会分配一次]
问:应用层访问底层字符设备驱动的过程?
答:open---->设备文件
struct inode:设备号
--------->struct cdev
它的一个成员记录操作硬件设备的函数接口
(struct file_operations)
寻找成功之后:(.probe的实现。cdev_init就可以把自己写的操作硬件接口放到虚拟文件系统对象当中去)
struct inode 结构体记录struct cdev这个结构体首地址
struct file 结构体记录struct file_operations这个结构体首地址
问:写字符驱动,需要做什么?
答:<1>struct cdev:Linux 针对字符设备的通用描述
struct led_device{
struct cdev cdev;//通用的字符设备描述
...
};
需要给自己设计的结构体分配空间
<2>提供硬件设备的操作函数接口
struct file_operations 结构体做填充
需要将这个结构体的首地址记录在struct cdev结构体中
<3>申请一个空闲的设备号
<4>使用设备号,将struct cdev这个结构体添加到系统中去
3.自动创建设备文件
自动创建设备文件
1.驱动程序必须导出设备号信息
2.捕获设备号信息的程序,帮我们创建设备文件
<1>devtmpfs 在内核启动的时候,它就会运行,在内核空间(可以通过make menuconfig去掉这个功能)
<2>udev 应用程序,功能强大
<3>mdev 应用程序,它是udev简化版本
4.传统字符设备缺点
驱动与设备未分离,而且写的比较死,可移植性差,原因:驱动中包含了特定平台的硬件信息,如果是其他平台,硬件信息会有差异,所以
驱动无法直接使用。