linux应用与驱动之间的通讯--驱动篇

linux应用与驱动之间的通讯--驱动篇

应用与驱动之间调用关系

首先我们要明白,应用程序是不能直接操作内核的,由于写应用程序的人水平参差不齐,又或是动机不良,直接允许应用程序操作内核是件危险的事。所以,驱动只要提供标准接口,供应用程序调用即可。
如应用调用read,write,open,ioctl, 驱动则提供对于的drv_read,drv_write,drv_ioctl。

阻塞与非阻塞

对于非阻塞,驱动程序在应用程序调用read时,提供驱动程序的drv_read,所以主要判断传入的参数,在drv_read函数中,判断file->flag是否为O_NONBLOCK即可

对于阻塞,只要传入的flag不为O_NONBLOCK即可,当无数据时,程序会进入休眠,直到被唤醒。
① APP调用read等函数试图读取数据,比如读取按键;
② APP进入内核态,也就是调用驱动中的对应函数,发现有数据则复制到用户空间并马上返回;
③ 如果APP在内核态,也就是在驱动程序中发现没有数据,则APP休眠;
④ 当有数据时,比如当按下按键时,驱动程序的中断服务程序被调用,它会记录数据、唤醒APP;
⑤ APP继续运行它的内核态代码,也就是驱动程序中的函数,复制数据到用户空间并马上返回。
函数 说明
1.wait_event_interruptible(wq, condition) 休眠,直到condition为真;休眠期间是可被打断的,可以被信号打断
2.wait_event(wq, condition) 休眠,直到condition为真;退出的唯一条件是condition为真,信号也不好使
3.wait_event_interruptible_timeout(wq, condition, timeout) 休眠,直到condition为真或超时;休眠期间是可被打断的,可以被信号打断
4.wait_event_timeout(wq, condition, timeout) 休眠,直到condition为真;退出的唯一条件是condition为真,信号也不好使
① wq:waitqueue,等待队列
休眠时除了把程序状态改为非RUNNING之外,还要把进程/进程放入wq中,以后中断服务程序要从wq中把它取出来唤醒。
② condition
这可以是一个变量,也可以是任何表达式。表示“一直等待,直到condition为真”。

//如果没有值,且是以非阻塞打开的,立即返回
static DECLARE_WAIT_QUEUE_HEAD(gpio_key_wait); //声明
static ssize_t gpio_key_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
	//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	int err;
	int key;

	if (is_key_buf_empty() && (file->f_flags & O_NONBLOCK))
		return -EAGAIN;
	
	wait_event_interruptible(gpio_key_wait, !is_key_buf_empty());//调用并不会马上休眠,先判断条件
	key = get_key();
	err = copy_to_user(buf, &key, 4);
	
	return 4;
}

//中断
static irqreturn_t gpio_key_isr(int irq, void *dev_id)
{
	struct gpio_key *gpio_key = dev_id;
	int val;
	val = gpiod_get_value(gpio_key->gpiod);
	g_key = (gpio_key->gpio << 8) | val;
	wake_up_interruptible(&gpio_key_wait);//唤醒
	return IRQ_HANDLED;
}

POLL

① APP不知道驱动程序中是否有数据,可以先调用poll函数查询一下,poll函数可以传入超时时间;
② APP进入内核态,调用到驱动程序的poll函数,如果有数据的话立刻返回;
③ 如果发现没有数据时就休眠一段时间;
④ 当有数据时,比如当按下按键时,驱动程序的中断服务程序被调用,它会记录数据、唤醒APP;
⑤ 当超时时间到了之后,内核也会唤醒APP;
⑥ APP根据poll函数的返回值就可以知道是否有数据,如果有数据就调用read得到数据
在file_operations结构体中,定义poll函数

static DECLARE_WAIT_QUEUE_HEAD(gpio_key_wait); //声明
 unsigned int  gpio_key_drv_poll (struct file *fp, struct poll_table_struct *wait)
{
  printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
  poll_wait(fp ,&gpio_key_wait, wait);
  return is_key_buf_empty() ?0 :POLLIN| POLLRDNORM;
}

static struct file_operations gpio_key_drv = {

      .owner  = THIS_MODULE,
	  .read   = gpio_key_drv_read,
	  .poll   = gpio_key_drv_poll,
 };

异步通知

在file_operations结构体中定义fasync函数

static int gpio_key_drv_fasync(int fd, struct file *file, int on)
{
	if (fasync_helper(fd, file, on, &button_fasync) >= 0)//fasync_helper函数会分配、构造一个fasync_struct结构体
		return 0;
	else
		return -EIO;
}
static struct file_operations gpio_key_drv = {
	.owner	 = THIS_MODULE,
	.read    = gpio_key_drv_read,
	.fasync  = gpio_key_drv_fasync,
};

static irqreturn_t gpio_key_isr(int irq, void *dev_id)
{
	struct gpio_key *gpio_key = dev_id;
	int val;
	int key;
	val = gpiod_get_value(gpio_key->gpiod);
	kill_fasync(&button_fasync, SIGIO, POLL_IN);//取出PID,发送信号
	return IRQ_HANDLED;
}

驱动程序程序“只提供功能,不提供策略”。就是说驱动程序可以提供休眠唤醒、查询等等各种方式,,驱动程序只提供这些能力,怎么用由APP决定。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值