linux 字符驱动框架(用户态的read,write,poll是怎么操作驱动的)

本文通过一个简单的字符设备驱动示例,解释了在Linux系统中,用户态如何通过read、write和poll函数与驱动进行交互。文章详细介绍了驱动的初始化、打开、关闭函数,以及file_operations结构体中read、write、poll函数的实现。同时,提到了用户态的select机制和简单读写操作的示例代码。测试表明,在驱动层面使用数组模拟时,poll机制始终能返回可读可写状态。
摘要由CSDN通过智能技术生成

前言

这篇文章是通过对一个简单字符设备驱动的操作来解释,用户态的读写操作是怎么映射到具体设备的。
因为针对不同版本的linux内核,驱动的接口函数一直有变化,这贴出我测试的系统信息:

root@ubuntu:~/share/dev/cdev-2# cat /etc/os-release |grep -i ver
VERSION="16.04.5 LTS (Xenial Xerus)"
VERSION_ID="16.04"
VERSION_CODENAME=xenial
root@ubuntu:~/share/dev/cdev-2#
root@ubuntu:~/share/dev/cdev-2# uname -r
4.15.0-33-generic

字符驱动

这里给出了一个不怎么标准的驱动,定义了一个结构体 struct dev,其中buffer成员模拟驱动的寄存器。由wr,rd作为读写指针,len作为缓存buffer的长度。具体步骤如下:
1. 定义 init 函数,exit函数,这是在 insmod,rmmod时候调用的。
2. 定义驱动打开函数open,这是在用户态打开设备时候调用的。
3. 定义release函数,这是在用户态关闭设备时候用到的。
4. 定义read,write,poll函数,并挂接到 file_operations结构体中,所有用户态的read,write,poll都会最终调到这些函数。

chardev.c

/*
参考:深入浅出linux设备驱动开发
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/wait.h>
#include <linux/semaphore.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/device.h>
#include <linux/poll.h>

#define MAXNUM 100
#define MAJOR_NUM 400 //主设备号 ,没有被使用

struct dev{
    struct cdev devm; //字符设备
    struct semaphore sem;
    int flag;
    poll_table* table;
    wait_queue_head_t outq;//等待队列,实现阻塞操作
    char buffer[MAXNUM+1]; //字符缓冲区
    char *rd,*wr,*end; //读,写,尾指针
}globalvar;
static struct class *my_class;
int major=MAJOR_NUM;

static ssize_t globalvar_read(struct file *,char *,size_t ,loff_t *);
static ssize_t globalvar_write(struct file *,const char *,size_t ,loff_t *);
static int globalvar_open(struct inode *inode,struct file *filp);
static int globalvar_release(struct inode *inode,struct file *filp);
static unsigned int globalvar_poll(struct file* filp, poll_table* wait);
/*
结构体file_operations在头文件 linux/fs.h中定义,用来存储驱动内核模块提供的对设备进行各种操作的函数的指针。
该结构体的每个域都对应着驱动内核模块用来处理某个被请求的事务的函数的地址。
设备"gobalvar"的基本入口点结构变量gobalvar_fops 
*/
struct file_operations globalvar_fops =
{
    /*
    标记化的初始化格式这种格式允许用名字对这类结构的字段进行初始化,这就避免了因数据结构发生变化而带来的麻烦。
    这种标记化的初始化处理并不是标准 C 的规范,而是对 GUN 编译器的一种(有用的)特殊扩展
    */
    //用来从设备中获取数据. 在这个位置的一个空指针导致 read 系统调用以 -EINVAL("Invalid argument") 失败. 一个非负返回值代表了成功读取的字节数( 返回值是一个 "signed size" 类型, 常常是目标平台本地的整数
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值