fasync driver demo

Linux系统中的fasync用于设备驱动程序与用户空间之间的异步通信。它允许设备驱动程序通知用户空间的进程,当设备状态发生变化时,通过发送SIGIO信号来告知进程。

具体来说,设备驱动程序可以调用fasync_helper()函数来注册一个或多个进程,当设备状态发生变化时,内核会自动发送SIGIO信号给这些进程。而用户空间进程可以通过调用fcntl()函数,并设置F_SETOWN标志来接收SIGIO信号。一旦接收到SIGIO信号,进程就可以执行相应的处理操作,如读取设备数据或进行其他操作。

通过使用fasync,设备驱动程序可以避免阻塞用户进程,可以实现非阻塞I/O操作,提高系统的响应性能。

下面实现的是打开设备文件并启用异步通知功能,然后进入一个无限循环中,等待接收SIGIO信号的触发。当设备发生变化时,设备驱动程序会发送SIGIO信号给这个用户空间程序,触发fasync_handler函数的执行,从而可以进行相应的处理操作。

#include
#include
#include
#include
#include
#include
#include
#include 
#include 
#include 

int fd;
void fasync_handler(int num)
{
   printf("fasync_handler entering\n");
}

void main()
{
  int i=2;
  char data[256];
  int oflags=0;
  int retval;

  signal(SIGIO, fasync_handler);
  fd=open("/dev/fcn",O_RDWR);
  if(fd==-1)
  {
     perror("error open\n");
     exit(-1);
  }
  printf("open /dev/fcn successfully\n");
  //使能了异步的通知到当前进程
  fcntl(fd, F_SETOWN, getpid());
  oflags=fcntl(fd, F_GETFL);
  fcntl(fd, F_SETFL, oflags | FASYNC);

  while(1);
  close(fd);
}

demo.c ​​​​​​​

  1. 下面代码定义了一个名为simple_dev的结构体,用于表示设备的相关信息。在模块加载时,通过register_chrdev_region()函数请求一个主设备号。

  2. 创建并初始化一个simple_dev结构体,然后通过cdev_init()函数对其进行初始化。

  3. 调用cdev_add()函数将字符设备添加到系统中。定义了简单的设备操作函数,包括打开设备(simple_open)、关闭设备(simple_release)和异步通知(simple_fasync)。

  4. 初始化一个定时器simple_timer,当时间到达时,会调用simple_timer_handler函数。

  5. 在simple_open函数中,将定时器添加到内核定时器列表中,并启动定时器。

  6. 在simple_fasync函数中,通过fasync_helper函数将当前进程添加到异步通知队列fasync_queue中。

  7. 在simple_release函数中,调用simple_fasync函数取消异步通知。

  8. 模块卸载时,通过cdev_del()函数删除字符设备,释放相关资源。


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 


#include "demo.h"

MODULE_AUTHOR("fgj");
MODULE_LICENSE("Dual BSD/GPL");


struct simple_dev *simple_devices;
static unsigned char simple_inc=0;
static struct timer_list simple_timer;
static struct fasync_struct *fasync_queue=NULL;

static void simple_timer_handler( unsigned long data)
{
    printk("simple_timer_handler...\n");
    if (fasync_queue)
    {
	  //POLL_IN可读,POLL_OUT为可写
      kill_fasync(&fasync_queue, SIGIO, POLL_IN);
      printk("kill_fasync...\n");
    }
    return ;
}

int simple_open(struct inode *inode, struct file *filp)
{
	struct simple_dev *dev;
	dev = container_of(inode->i_cdev, struct simple_dev, cdev);
	filp->private_data = dev;

    simple_timer.function = &simple_timer_handler;
	simple_timer.expires = jiffies + 2*HZ;
	add_timer (&simple_timer);
    printk("add_timer...\n");
	return 0;
}


static int simple_fasync(int fd, struct file * filp, int mode) 
{
    int retval;
    printk("simple_fasync...\n");
    retval=fasync_helper(fd,filp,mode,&fasync_queue);
    if(retval<0)
      return retval;
    return 0;
}

int simple_release(struct inode *inode, struct file *filp)
{
	simple_fasync(-1, filp, 0);
	return 0;
}

struct file_operations simple_fops = {
	.owner =    THIS_MODULE,
	.open =     simple_open,
	.release=   simple_release,
	.fasync=    simple_fasync,
	
};

/*******************************************************
                MODULE ROUTINE
*******************************************************/
void simple_cleanup_module(void)
{
	dev_t devno = MKDEV(simple_MAJOR, simple_MINOR);

	if (simple_devices) 
	{
		cdev_del(&simple_devices->cdev);
		kfree(simple_devices);
	}

	unregister_chrdev_region(devno,1);
}

int simple_init_module(void)
{
	int result;
	dev_t dev = 0;

	dev = MKDEV(simple_MAJOR, simple_MINOR);
	result = register_chrdev_region(dev, 1, "DEMO");
	if (result < 0) 
	{
		printk(KERN_WARNING "DEMO: can't get major %d\n", simple_MAJOR);
		return result;
	}

	simple_devices = kmalloc(sizeof(struct simple_dev), GFP_KERNEL);
	if (!simple_devices)
	{
		result = -ENOMEM;
		goto fail;
	}
	memset(simple_devices, 0, sizeof(struct simple_dev));

	cdev_init(&simple_devices->cdev, &simple_fops);
	simple_devices->cdev.owner = THIS_MODULE;
	simple_devices->cdev.ops = &simple_fops;
	result = cdev_add (&simple_devices->cdev, dev, 1);
	if(result)
	{
		printk(KERN_NOTICE "Error %d adding DEMO\n", result);
		goto fail;
	}
	init_timer(&simple_timer);
	return 0;

fail:
	simple_cleanup_module();
	return result;
}

module_init(simple_init_module);
module_exit(simple_cleanup_module);

demo.h

#ifndef _simple_H_
#define _simple_H_

#include  /* needed for the _IOW etc stuff used later */

/********************************************************
 * Macros to help debugging
 ********************************************************/
#undef PDEBUG             /* undef it, just in case */
#ifdef simple_DEBUG
#ifdef __KERNEL__
#    define PDEBUG(fmt, args...) printk( KERN_DEBUG "DEMO: " fmt, ## args)
#else//usr space
#    define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
#endif
#else
#  define PDEBUG(fmt, args...) /* not debugging: nothing */
#endif

#undef PDEBUGG
#define PDEBUGG(fmt, args...) /* nothing: it's a placeholder */

//设备号
#define simple_MAJOR 226
#define simple_MINOR 0
#define COMMAND_LEDON 1
#define COMMAND_LEDOFF 2

//设备结构
struct simple_dev 
{
	struct cdev cdev;	  /* Char device structure		*/
};

//函数申明
ssize_t simple_read(struct file *filp, char __user *buf, size_t count,
                   loff_t *f_pos);
ssize_t simple_write(struct file *filp, const char __user *buf, size_t count,
                    loff_t *f_pos);
loff_t  simple_llseek(struct file *filp, loff_t off, int whence);
int     simple_ioctl(struct inode *inode, struct file *filp,
                    unsigned int cmd, unsigned long arg);


#endif /* _simple_H_ */

上述代码的实现了一个简单的字符设备驱动程序,并使用定时器实现了异步通知功能,通过调用fasync_helper函数将进程添加到异步通知队列中,当定时器时间到达时,会发送SIGIO信号给进程,以实现类似中断的功能。 

你可能感兴趣的:(linux内核,linux,驱动开发,嵌入式)