字符设备驱动程序之LED驱动程序_编写编译(二)

字符设备驱动程序之LED驱动程序_编写编译


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 <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>


static int first_drv_open(struct inode *inode, struct file *file)
{
	printk("first_drv_open\n");
	return 0;
}

static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
	printk("first_drv_write\n");
	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:目标。



猜你喜欢

转载自blog.csdn.net/xiaodingqq/article/details/80228839