app: open , read , write
驱动: led_open,led_read,led_write
驱动框架:
一、写出:led_open,led_read
二、怎么告诉内核?
a、定义一个file_operations
b、把这个结构体告诉内核:
register_chrdev(major,name,file_operations)
c、谁来调用它 (register_chrdev)
驱动的入口函数 first_drv_init
d、修饰:module_init(first_drv_init) (怎么知道是哪个入口函数)
module_init:(入口函数)定义了一个结构体,结构体有个函数指针,指向入口函数xxx_init。加载一个驱动的时候,内核就会找到这个结构体里面的函数指针,指向入口函数。
加载一个驱动时,内核就会找到这个结构体里面的函数指针,指向入口函数。入口函数把file_operations告诉内核。
介绍一个内核里的数组chrdevs(字符设备的file_operations和major都包含在这个数组中):
static struct char_device_struct {
struct char_device_struct *next;
unsigned int major;
unsigned int baseminor;
int minorct;
char name[64];
struct file_operations *fops;
struct cdev *cdev; /* will die */
} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];
app:open("/dev/xxx")
打开文件的属性:c _ _ _, _ _ _, _ _ _, major, minor
设备类型,主设备号
内核数组chrdevs:
1 2 …… …… …… …… major …… …… ……
★★VFS系统根据打开的这个文件的属性(设备类型:字符设备,主设备号major),就会找到注册进去的file_operations结构。
★★register_chrdev的实现:在一个内核数组chrdevs里,以major为索引,找到一项,在这一项里把file_operations填充进去,挂进去。
总结:
怎么根据打开的设备(open),找到驱动程序具体的实现(led_open)?
在内核定义了一个chrdevs数组,在这个数组里面,根据主设备号,找到了那一项的file_operations,这个file_operations结构是驱动程序里面实现的。
驱动程序:
1、定义了led_open、led_write、led_read
2、定义了file_operations结体,.open=led_open,.write=led_write
3、入口函数里,用register_chrdev(major,name,file_operations)把这个结构体放到内核数组chrdevs,对应的主设备号里面。
入口函数(注册):把file_operations结构体挂到chrdevs数组对应的设备号那一项
出口函数(卸载):把file_operations结构体从对应的设备号那一项拖出来。
第一个驱动程序 first_drv.c:
#include #include #include #include #include #include #include #include #include #include static int first_drv_open(struct inode *inode, struct file *file) { printk("first_drv_openn"); return 0; } static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) { printk("first_drv_writen"); return 0; } static struct file_operations first_drv_fops = { .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */ .open = first_drv_open, .write = first_drv_write, }; int first_drv_init(void) { register_chrdev(111, "first_drv", &first_drv_fops); //注册驱动程序,告诉内核 return 0; } void first_drv_exit(void) { unregister_chrdev(111, "first_drv"); //卸载驱动 } module_init(first_drv_init); module_exit(first_drv_exit); Makefile文件: KERN_DIR = /work/system/linux-2.6.22.6 all: make -C $(KERN_DIR) M=`pwd` modules clean: make -C $(KERN_DIR) M=`pwd` modules clean rm -rf modules.order obj-m += first_drv.o KERN_DIR表示内核的目录,编一个驱动程序,依赖于内核。 -C:转到这个KERN_DIR这个目录去,用这个目录的Makefile来进行编译。 M=:当前目录是什么。modules:目标。
上一篇:S3C2440 字符设备驱动程序之概念介绍(一)
下一篇:S3C2440 字符设备驱动程序之LED驱动程序_测试改进(三)
推荐阅读最新更新时间:2024-11-08 12:15
设计资源 培训 开发板 精华推荐
- LT3970IMS-5 5V 同步降压转换器的典型应用
- 基于NCV81599和NVTFS5C460NL的4开关汽车降压-升压预调器
- 0001
- ADR392B 4V 输出微功率、低噪声精密电压基准的典型应用
- AM30EW-2405SZ 5V 三路输出 DC/DC 转换器的典型应用
- AD9613-170EBZ,用于评估 AD9613 模数转换器的评估板
- LTC1261LCMS8 最小部件数 -4.5V 发生器的典型应用电路
- LT3970IMS 5V、2MHz 降压转换器的典型应用
- LD1117 可调和固定低压降正电压调节器的典型应用电路(在其他固定输出电压下)
- 基于 MCF5233CVM150 MPU ColdFire MCF5xxx 处理器的 M5235EVB、M523xEVB 评估板