树莓派(四):内核驱动框架

文章详细介绍了Linux内核中的file_operations结构,它是系统调用和驱动程序之间的桥梁,每个成员对应一个系统调用,如read、write等。同时,文章还展示了GPIO驱动的基本框架,包括驱动的初始化、注册、设备文件的创建以及测试流程。通过对file_operations的初始化和GPIO驱动的实现,阐述了设备驱动的基本工作原理。
摘要由CSDN通过智能技术生成

驱动框架图

 struct file_operations(include/linux/fs.h)

        1.系统调用和驱动程序关联起来的数据结构。(I/O设备的存取操作通过入口进行,入口点是设备驱动程序提供的,设备驱动程序接口是由结构file_operations结构体向系统说明的)。

        2.结构每个成员对应一个系统调用。

        3.读取其中的函数指针,把控制权转交给函数,完成驱动程序。

        驱动操作内核数据结构:file_operations、file、inode。

        struct file_operations字符设备驱动的操作和设备号联系在一起。

        

                struct inode

                {
                        dev_t i_rdev;        设备文件的设备号
                        struct cdev *i_cdev; 代表字符设备的数据结构

                }

        struct file打开的文件,在执行file_operation中的open操作时被创建。

        区别:
                file与用户inode指针:inode在内核,file指针在用户空间,由c库来定义。
                struct inode代表文件,struct file代表打开的文件。

               文件可以打开多次,对应很多struct file,struct inode唯一。

struct module *owner; 
不是操作, 指向拥有该结构的模块的指针,避免操作时被卸载,一般为初始化为THIS_MODULES (<linux/module.h>中定义的宏).

loff_t (*llseek) (struct file *, loff_t, int); 
函数指针修改文件当前的读写位置,返回新位置.

ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
函数指针用来读取数据。成功返回读取的字节数.

ssize_t (*aio_read)(struct kiocb *, char __user *, size_t, loff_t);
异步读可能在函数返回前不结束的读操作.

ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
函数指针发送数据给设备.

ssize_t (*aio_write)(struct kiocb *, const char __user *, size_t, 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);
函数指针执行设备特殊命令的方法

int (*mmap) (struct file *, struct vm_area_struct *);
请求将设备内存映射到进程的地址空间. 

int (*open) (struct inode *, struct file *);
指针函数用于打开设备.

int (*flush) (struct file *);
指针函数用于在进程关闭设备文件描述符副本时。

int (*release) (struct inode *, struct file *);
函数指针在file结构释放时,将被调用

int (*fsync) (struct file *, struct dentry *, int);
函数指针用于刷新待处理的数据.

int (*aio_fsync)(struct kiocb *, int);函数对应异步fsync.

int (*fasync) (int, struct file *, int);
函数指针用于通知设备FASYNC标志发生变化.

int (*lock) (struct file *, int, struct file_lock *);
文件加锁; 

ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
实现发散/汇聚读和写操作. 应用程序偶尔需要做一个包含多个内存区的单个读或写操作.

ssize_t (*sendfile)(struct file *, loff_t *, size_t, read_actor_t, void *);
系统调用的读,拷贝文件通过描述符. 

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);模块检查传递给 fnctl(F_SETFL…); 
调用的标志.

int (*dir_notify)(struct file *, unsigned long);
程序使用fcntl来请求目录改变通知调用. 

file_operations结构初始化:
struct file_operations scull_fops = {

.owner = THIS_MODULE,

.llseek = scull_llseek,

.read = scull_read,

.write = scull_write,

.ioctl = scull_ioctl,

.open = scull_open,

.release = scull_release,

};

 

GPIO驱动框架(字符设备)

        驱动框架代码

#include <linux/fs.h>        //file_operations声明
#include <linux/module.h>    //module_init  module_exit声明
#include <linux/init.h>      //__init  __exit 宏定义声明
#include <linux/device.h>    //class  devise声明
#include <linux/uaccess.h>   //copy_from_user 的头文件
#include <linux/types.h>     //设备号  dev_t 类型声明
#include <asm/io.h>          //ioremap iounmap的头文件             
 
static struct class *pin_class;  
static struct device *pin_class_dev;
 
static dev_t devno;                        //设备号
static int major =127;                     //主设备号
static int minor =0;                       //次设备号
static char *module_name="pin";            //模块名
 
static int pin_open(struct inode *inode,struct file *file)
{
    printk("pin open sucess\n");  
    return 0;
}
 
static ssize_t pin_write(struct file *file,const char __user *buf,size_t count, loff_t *ppos)
{
    printk("pin write success\n");
    return 0;
}
 
static struct file_operations pin_fops = {
    .owner = THIS_MODULE,
    .open  = pin_open,
    .write = pin_write,
};
 
int __init pin_drv_init(void)  
{
    int ret;
    devno = MKDEV(major,minor);                               //创建设备号
    ret   = register_chrdev(major, module_name,&pin_fops);    //注册驱动,驱动加入驱动链表
    pin_class = class_create(THIS_MODULE,"pinMoudle");       // /dev生成设备
    pin_class_dev =device_create(pin_class,NULL,devno,NULL,module_name);   //创建设备文件
    return 0;
}
 
void __exit pin_drv_exit(void)
{
    device_destroy(pin_class,devno);         //清除设备文件
    class_destroy(pin_class);                //清除设备
    unregister_chrdev(major, module_name);  //卸载驱动
}
 
module_init(pin_drv_init);      //模块入口
module_exit(pin_drv_exit);      //模块退出
MODULE_LICENSE("GPL v2");       //宏声明许可证

        驱动框架测试代码

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
        int fd;
        fd = open("/dev/pin",O_RDWR);
        if(fd < 0)
        {
                printf("open fail\n");
                perror("why");
                exit(-1);
        }
        write(fd,"hello word",10);
        return 0;
}

        测试流程 

ubuntu:

cd /root/linux-rpi-4.14.y/drivers/char

(驱动框架代码)

vim pin_test.c

(修改Makefile,添加驱动模块)

vim Makefile

obj-m                           += pin_test.o

cd /root/linux-rpi-4.14.y

ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make -j4  modules

(测试代码)

vim pinTest.c

arm-linux-gnueabihf-gcc pinTest.c -o pinPest

生成(/root/linux-rpi-4.14.y/drivers/char):pin_test.ko,pinPest上传文件到Pi


Pi:

insmod pin_test.ko

lsmod|grep pin

ls -lrt /dev/| tail -f

chmod 666 /dev/pin

./pinTest

dmesg|grep pin|grep success

rmmod pin_test

lsmod|grep pin|grep suc

测试图例

驱动安装成功

驱动文件生成,修改权限

 测试代码执行,查看内核成功信息

卸载驱动

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值