Linux下的驱动开发二

一、IO模型

  1. I/O 模型在操作系统中用于处理应用程序与设备驱动之间的数据传输。
  2. I/O 通信模型的核心是解决程序与设备之间如何高效、合理地进行数据通信。不同的模型通过阻塞、非阻塞、同步、异步的方式来控制数据流和处理 I/O 请求。

注:在驱动开发中可以定义一个全局结构体

  1. 用于全局管理驱动程序的状态和资源。
  2. 在驱动开发中,有时需要一个全局的数据结构来保存设备的状态、驱动配置、缓存、锁等信息,这样不同的驱动程序函数可以通过该结构体访问和修改共享的资源。
  3. 作用
    • 统一管理驱动状态: 全局结构体通常保存驱动程序的各种状态信息。例如,设备的注册信息、分配的内存、硬件寄存器映射等都可以保存在这个结构体中。
    • 共享资源: 驱动程序通常会有多个函数被内核调用,比如初始化函数、读写函数、中断处理函数等。使用全局结构体,可以让这些函数方便地共享和访问同样的数据或资源。
    • 简化代码结构: 将驱动程序涉及的所有全局变量封装在一个结构体中,使代码更加清晰、结构化,同时也减少了全局变量命名冲突的可能性。

一、阻塞 I/O 模型

  1. 阻塞 I/O 是最常见的 I/O 模型。当应用程序发起 I/O 请求时,如果数据没有准备好,应用程序将进入阻塞状态,等待数据准备完毕后,驱动程序会唤醒阻塞的应用程序。此时,应用程序才能继续执行。
  2. 工作流程
应用程序向驱动发送读取数据的请求。
如果驱动程序中数据尚未准备好,应用程序进入 睡眠状态,等待数据到来。
当数据准备好后,驱动程序会唤醒应用程序,程序从睡眠状态恢复,继续读取数据。
完成 I/O 操作后,应用程序继续执行其他任务。
  1. 具体步骤
    a. 定义并初始化等待队列
wait_queue_head_t wqhead;//在全局结构体中
在结构体 global_struct 中定义了 wqhead,表示等待队列头,用于管理睡眠进程的队列。

在mod_init() 初始化函数中,通过 init_waitqueue_head() 初始化等待队列头。
init_waitqueue_head(&gstruct.wqhead);

b. 进程睡眠机制

在 chdev_read 函数中,当应用程序尝试从驱动读取数据时,程序会检查数据是否可用。如果数据不可用,进程就会进入睡眠状态,挂到等待队列上。
wait_event_interruptible(pt_gstruct->wqhead, pt_gstruct->data_flag);

c. 唤醒机制

当数据到达时,会通过 chdev_write 函数进行处理
pt_gstruct->data_flag = 1;//数据写入后,data_flag 被设置为 1,表示数据已准备好。
wake_up_interruptible(&pt_gstruct->wqhead);
wake_up_interruptible() 函数用于唤醒等待队列 wqhead 上的所有进程,唤醒后,之前处于睡眠状态的进程会继续执行 chdev_read 函数中的代码,读取数据。

二、非阻塞I/O实现

  1. 非阻塞 I/O 的实现逻辑与阻塞 I/O 类似,但不进入睡眠状态。如果数据尚未准备好,非阻塞 I/O 立即返回错误 -EAGAIN,告诉应用程序稍后重试。
if (file->f_flags & O_NONBLOCK) {
       // 检查文件标志是否为非阻塞模式
    if (pt_gstruct->data_flag == 0)  // 没有数据可用
        return -EAGAIN;              // 返回 EAGAIN 错误,表示无数据,稍后重试
}

三、异步通知

  1. 异步通知(Asynchronous Notification)是 Linux 内核提供的一种机制,它允许设备驱动在数据准备好或状态发生变化时,主动向应用程序发送信号(通常是 SIGIO 信号),通知应用程序及时处理。
  2. 这种机制在应用程序不需要不断轮询设备状态的情况下非常有用。
  3. 设备驱动中的结构定义
struct global_struct {
   
    struct class *cls;
    int major, minor;
    struct cdev cdev_obj;
    wait_queue_head_t wqhead;    // 等待队列头
    char sharebuf[128];          // 共享缓冲区
    int data_flag;               // 标记数据是否可用,0 表示无数据,1 表示有数据
    struct fasync_struct *fapp;  // 异步通知结构,用于管理异步通知
};

  1. 驱动程序的 fasync 实现
int chdev_fasync(int fd, struct file *file, int on)
{
   
    struct global_struct *pt_gstruct = file->private_data;

    // fasync_helper 负责将文件描述符和进程与异步通知关联或解除关联
    return fasync_helper(fd, file, on, &pt_gstruct->fapp);
}

  1. 实现数据写入时的异步通知
//当驱动程序中有新数据时,通过 kill_fasync 向注册了异步通知的进程发送信号。
ssize_t chdev_write(struct file *file, const char __user *usr, size_t sz, loff_t *loff)
{
   
    struct global_struct *pt_gstruct = file->private_data;
    long ret;

    // 将用户数据复制到共享缓冲区
    ret = copy_from_user(pt_gstruct->sharebuf, usr, sz);
    if (ret > 0) {
   
        printk("%s-%d copy_from_user err\n", __func__, __LINE__);
        return -3;
    }

    // 数据写入完成后,标记数据已经准备好
    pt_gstruct->data_flag = 1;

    // 唤醒所有等待在等待队列上的进程
    wake_up_interruptible(&pt_gstruct->wqhead);

    // 发送异步通知信号,通知应用程序有数据可读
    kill_fasync(&pt_gstruct->fapp, SIGIO<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值