驱动:

#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>//内存管理头文件,含有页面大小定义和一些页面释放函数原型
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <asm/io.h>//I/O头文件,以宏的嵌入汇编程序形式定义对I/O端口操作的函数。
#include <asm/system.h>//系统头文件,定义了设置或修改描述符/中断门等的嵌入式汇编宏。
#include <asm/uaccess.h>//包含了copy_to_user、copy_from_user等内核访问用户进程内存地址的函数定义
#include <linux/slab.h>//包含了kcalloc、kzalloc内存分配函数的定义。
#include <linux/poll.h>//--------------platform_device------------
#include <linux/platform_device.h>//-------------class_create,device_create------
#include <linux/device.h>/*用udev机制自动添加设备节点*/
struct class *globalfifo_class;#define GLOBALFIFO_SIZE    0x1000    /*全局内存最大4K字节*/
#define MEM_CLEAR 0x1  /*清0全局内存*/
#define GLOBALFIFO_MAJOR 0    /*预设的globalfifo的主设备号*/#define DEVICE_NAME "globalfifo"static int globalfifo_major = GLOBALFIFO_MAJOR;/*globalfifo设备结构体*/
struct globalfifo_dev
{                                                        struct cdev cdev; /*cdev结构体*/                       unsigned char mem[GLOBALFIFO_SIZE]; /*全局内存*/ unsigned int current_len;/*fifo 有效数据长度*/struct semaphore sem;/*并发控制用的信号量*/wait_queue_head_t r_wait;/*阻塞读用的等待队列头*/wait_queue_head_t w_wait;/*阻塞写用的等待队列头*/struct fasync_struct *async_queue;/*异步结构体指针*/
};struct globalfifo_dev *globalfifo_devp; /*设备结构体指针*/
/*文件打开函数*/
int globalfifo_open(struct inode *inode, struct file *filp)
{/*将设备结构体指针赋值给文件私有数据指针*/struct globalfifo_dev *dev;dev=container_of(inode->i_cdev,struct globalfifo_dev,cdev);//通过结构体成员的指针找到对应结构体的指针filp->private_data = dev;return 0;
}/* ioctl设备控制函数 */
static int globalfifo_ioctl(struct inode *inodep, struct file *filp, unsignedint cmd, unsigned long arg)
{struct globalfifo_dev *dev = filp->private_data;/*获得设备结构体指针*/switch (cmd){case MEM_CLEAR:if(down_interruptible(&dev->sem))/*获取信号量*/return -ERESTARTSYS;memset(dev->mem, 0, GLOBALFIFO_SIZE);  //mem数组名,即空间首地址
up(&dev->sem);printk(KERN_INFO "globalfifo is set to zero\n");break;default:return  - EINVAL;}return 0;
}/*读函数*/
static ssize_t globalfifo_read(struct file *filp, char __user *buf, size_t size,loff_t *ppos)
{int ret = 0;struct globalfifo_dev *dev = filp->private_data; /*获得设备结构体指针*/DECLARE_WAITQUEUE(wait,current);/*define wait queue*/if(down_interruptible(&dev->sem))/*获得信号量*/{return -ERESTARTSYS;}add_wait_queue(&dev->r_wait,&wait);/*进入读等待队列头*//*等待fifo非空并检测用户空间是否要求非阻塞访问*/while(dev->current_len==0){if(filp->f_flags &O_NONBLOCK){ret = -EAGAIN;goto out;}__set_current_state(TASK_INTERRUPTIBLE);/*改变进程状态为睡眠*//*********************************************************/up(&dev->sem);/*释放信号量,防止死锁*//*********************************************************/schedule();/*调度其他进程执行,开始睡眠*/if(signal_pending(current))/*如果是因为信号唤醒*/{ret = -ERESTARTSYS;/*重新执行系统调用*/goto out2;} else if(down_interruptible(&dev->sem)){return -ERESTARTSYS;}}/*内核空间->用户空间*/if(size>dev->current_len)size=dev->current_len;if (copy_to_user(buf,dev->mem,size)){ret =  - EFAULT;   /* Bad address */goto out;}else{memcpy(dev->mem,dev->mem+size,size);/*fifo数据前移*/dev->current_len -=size;/*有效数据长度减少*/printk(KERN_INFO"read %d bytes(s),current_len:%d \n",size,dev->current_len);wake_up_interruptible(&dev->w_wait);/*唤醒写等待队列*/ret= size;}out:up(&dev->sem);/*释放信号量*/out2:remove_wait_queue(&dev->r_wait,&wait);__set_current_state(TASK_RUNNING);return ret;
}/*写函数*/
static ssize_t globalfifo_write(struct file *filp, const char __user *buf,size_t size, loff_t *ppos)
{int ret = 0;struct globalfifo_dev *dev = filp->private_data; /*获得设备结构体指针*/DECLARE_WAITQUEUE(wait,current);/*define wait queue*/if(down_interruptible(&dev->sem))/*获得信号量*/{return -ERESTARTSYS;}add_wait_queue(&dev->w_wait,&wait);/*进入写等待队列*//*等待fifo非满并检测用户空间是否要求非阻塞访问*/while(dev->current_len==GLOBALFIFO_SIZE){if(filp->f_flags &O_NONBLOCK){ret = -EAGAIN;goto out;}__set_current_state(TASK_INTERRUPTIBLE);/*改变进程状态为睡眠*/up(&dev->sem);/*释放信号量,防止死锁*/schedule();/*调度其他进程执行,开始睡眠*/if(signal_pending(current)){ret = -ERESTARTSYS;goto out2;} else if(down_interruptible(&dev->sem)){return -ERESTARTSYS;}}/*内核空间<-用户空间*/if(size>GLOBALFIFO_SIZE-dev->current_len)size=GLOBALFIFO_SIZE-dev->current_len;if (copy_from_user(dev->mem+dev->current_len,buf,size)){ret =  - EFAULT;   /* Bad address */goto out;}else{dev->current_len +=size;/*有效数据长度减少*/printk(KERN_INFO"write %d bytes(s),current_len:%d \n",size,dev->current_len);wake_up_interruptible(&dev->r_wait);/*唤醒读等待队列*//*产生异步读信号*/if(dev->async_queue)kill_fasync(&dev->async_queue,SIGIO,POLL_IN);ret= size;}out:up(&dev->sem);/*释放信号量*/out2:remove_wait_queue(&dev->w_wait,&wait);__set_current_state(TASK_RUNNING);return ret;
}static unsigned int globalfifo_poll(struct file *filp,poll_table *wait)
{unsigned int mask=0;struct globalfifo_dev *dev=filp->private_data;if(down_interruptible(&dev->sem)){return -ERESTARTSYS;}poll_wait(filp,&dev->w_wait,wait);/*将对应的等待队列头添加到poll_table*/poll_wait(filp,&dev->w_wait,wait);/*fifo非空*/if(dev->current_len!=0)mask |=POLLIN|POLLRDNORM;/*标示数据可获得*//*fifo非满*/if(dev->current_len!=GLOBALFIFO_SIZE)mask |=POLLOUT|POLLWRNORM;/*标示数据可获得*/up(&dev->sem);return mask;}static int globalfifo_fasync(int fd,struct file *filp,int mode)
{struct globalfifo_dev *dev =filp->private_data;return fasync_helper(fd,filp,mode,&dev->async_queue);
}/*文件释放函数*/
int globalfifo_release(struct inode *inode, struct file *filp)
{/*将文件从异步通知列表里删除*/globalfifo_fasync(-1,filp,0);return 0;
}/*文件操作结构体*/
static const struct file_operations globalfifo_fops =
{.owner = THIS_MODULE,.read = globalfifo_read,.write = globalfifo_write,.ioctl = globalfifo_ioctl,.open = globalfifo_open,.release = globalfifo_release,.poll = globalfifo_poll,.fasync=globalfifo_fasync,
};/*初始化并注册cdev*/
static void globalfifo_setup_cdev(struct globalfifo_dev *dev, int index)
{int err, devno = MKDEV(globalfifo_major, index);cdev_init(&dev->cdev, &globalfifo_fops);dev->cdev.owner = THIS_MODULE;dev->cdev.ops = &globalfifo_fops;err = cdev_add(&dev->cdev, devno, 1);if (err)printk(KERN_NOTICE "Error %d ", err);
}static int __devinit globalfifo_probe(struct platform_device *pdev)
{printk("in the globalfifo_probe!!\n");int result;dev_t devno = MKDEV(globalfifo_major, 0);/* 申请设备号*/if (globalfifo_major)result = register_chrdev_region(devno, 1, DEVICE_NAME);else  /* 动态申请设备号 */{result = alloc_chrdev_region(&devno, 0, 1,DEVICE_NAME);globalfifo_major = MAJOR(devno);}  if (result < 0)return result;/* 动态申请设备结构体的内存*/globalfifo_devp = kmalloc(sizeof(struct globalfifo_dev), GFP_KERNEL);//kmalloc()内核空间;malloc()用户空间。返回起始地址if (!globalfifo_devp)     /*申请失败*/{result =    - ENOMEM;goto fail_malloc;}memset(globalfifo_devp, 0, sizeof(struct globalfifo_dev));//把此内存空间清零
    globalfifo_setup_cdev(globalfifo_devp, 0);//注册设备/*udev机制可以自动添加设备节点,只需要添加xxx_class这个类,以及device_create()*/globalfifo_class = class_create(THIS_MODULE, "globalfifo_class");/*在sys目录下创建xx_class这个类,/sys/class/~*/device_create(globalfifo_class, NULL, globalfifo_devp->cdev.dev,  DEVICE_NAME, DEVICE_NAME);/*自动创建设备/dev/$DEVICE_NAME*/init_MUTEX(&globalfifo_devp->sem);/*初始化信号量*/init_waitqueue_head(&globalfifo_devp->r_wait);/*初始化读写等待队列*/init_waitqueue_head(&globalfifo_devp->w_wait);printk("globalfifo driver installed!\n");printk("globalfifo_major is:%d\n",globalfifo_major);printk("the device name is %s\n",DEVICE_NAME);return 0;fail_malloc: unregister_chrdev_region(devno, 1);return result;}static int __devexit globalfifo_remove(struct platform_device *pdev)
{printk("in the globalfifo_remove!!\n");device_destroy(globalfifo_class, globalfifo_devp->cdev.dev);class_destroy(globalfifo_class);cdev_del(&globalfifo_devp->cdev);    /*注销cdev*/kfree(globalfifo_devp);     /*释放设备结构体内存*/unregister_chrdev_region(MKDEV(globalfifo_major, 0), 1); /*释放设备号*/printk("globalfifo driver uninstalled!\n");return 0;}static struct platform_driver globalfifo_device_driver={.probe=globalfifo_probe,.remove=globalfifo_remove,.driver={.name=DEVICE_NAME,.owner=THIS_MODULE,},
};/*设备驱动模块加载函数*/
static int __init globalfifo_init(void)
{return platform_driver_register(&globalfifo_device_driver);
}/*模块卸载函数*/
static void __exit globalfifo_exit(void)
{platform_driver_unregister(&globalfifo_device_driver);
}MODULE_AUTHOR("mhb@SEU");
MODULE_LICENSE("Dual BSD/GPL");module_param(globalfifo_major, int, S_IRUGO);module_init(globalfifo_init);
module_exit(globalfifo_exit);

测试程序:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <signal.h>void input_handler(int signum)
{printf("signum is ;%d\n",signum);
}int main()
{int fd,oflags;fd=open("/dev/globalfifo",O_RDWR,S_IRUSR|S_IWUSR);if(fd != -1) {/*启动信号驱动机制*/signal(SIGIO,input_handler);/*让input_handler 处理SIGIO信号*/fcntl(fd,F_SETOWN,getpid());oflags=fcntl(fd,F_GETFL);fcntl(fd,F_SETFL,oflags|FASYNC);while(1){sleep(100);}} else{printf("device open failed!\n");}return 0;    }

转载于:https://www.cnblogs.com/hello2mhb/p/3326610.html

支持异步通知的globalfifo平台设备驱动程序及其测试代码相关推荐

  1. 使用内核定时器的second字符设备驱动及测试代码

    驱动: #include <linux/kernel.h> #include <linux/module.h> #include <linux/fs.h> #inc ...

  2. 微信小程序开发-微信支付功能【WxMaService 获取openid,WxPayService建微信订单,接收微信支付异步通知回调方法,附有完整前后端代码】

    前提:对小程序开发有一定的基础:小程序已发布使用,已开通微信支付,关联商户号. 微信小程序平台:小程序平台 微信开发者文档:开发者文档 微信小程序支付API 地址:微信支付文档地址 微信支付平台:微信 ...

  3. 异步通知《来自Linux驱动程序开发实例》

    您所在的位置:读书频道 > 操作系统 > Linux > 1.2.8 异步通知 1.2.8 异步通知 2012-05-22 13:38 冯国进 机械工业出版社 我要评论(0) 字号: ...

  4. 字符设备驱动程序之异步通知

    如果要实现:平时应用程序处于休眠状态,当按下按键时,驱动告诉应用程序由状态改变,需要读取按键状态了.那么就需要建立驱动和应用程序之间的通信. 应用函数中的某个函数怎么使用,需要包含哪些头文件,可以在服 ...

  5. Linux 设备驱动中的 I/O模型(二)—— 异步通知和异步I/O

    阻塞和非阻塞访问.poll() 函数提供了较多地解决设备访问的机制,但是如果有了异步通知整套机制就更加完善了. 异步通知的意思是:一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态 ...

  6. Linux设备驱动中的异步通知

    异步通知的概念: 一旦设备就绪,主动通知应用程序.这样应用程序根本不需要查询设备状态. 阻塞,非阻塞和异步: - 阻塞 IO 是等待设备可访问后再访问 - 非阻塞 IO 是查询设备是否可以访问 - 异 ...

  7. linux编写驱动后write已杀死_《Linux4.0设备驱动开发详解》笔记--第九章:Linux设备驱动中的异步通知与同步I/O...

    在设备驱动中使用异步通知可以使得对设备的访问可进行时,由驱动主动通知应用程序进行访问.因此,使用无阻塞I/O的应用程序无需轮询设备是否可访问,而阻塞访问也可以被类似"中断"的异步通 ...

  8. [架构之路-38]:目标系统 - 系统软件 - Linux OS硬件设备驱动必须熟悉的六大工作机制之(并发与互斥、阻塞与非阻塞、异步通知)

    目录 前言: 第4章 内核程序并发与互斥机制 4.1 内核程序优先级机制 4.2 内核线程状态:并发与竞争 4.3 内核锁的类型 4.4 乱序问题 第5章 阻塞与非阻塞机制 5.1 什么是阻塞问题 5 ...

  9. jz2440_基于平台设备的LED驱动程序

    平台设备驱动程序是基于总线系统实现的,由三个部分组成: 总线,这里的总线使用的是内核自带的 platform_bus_type 总线,无需我们进行实现: 设备,这个驱动主要是对 LED 灯的操作,因此 ...

最新文章

  1. TinyBERT搜索: 比BERT快10倍,小20倍
  2. Python中的元类是什么?
  3. Visual studio 利用Nuget 控制台安装已经下载好的插件
  4. (33)调试驱动程序
  5. 《口袋奇兵》开发商引入阿里云PolarDB数据库 IT成本降幅达50%
  6. ScrollView中嵌入Listview,当item高度不一样的时候,item展示不全问题
  7. Wannafly挑战赛23F-计数【原根,矩阵树定理,拉格朗日插值】
  8. Chapter1-4_Speech_Recognition(HMM)
  9. 用Python实现反转字符串
  10. 【分享】用东野圭吾的方式说爱你
  11. Spring中的ApplicationContextAware使用
  12. Ruby on Rails 实践
  13. GB2312简体中文编码表
  14. 种子填充算法c语言代码实现,OpenGL绘图实例三之种子填充算法
  15. Linux系统内核升级
  16. 如何把多个pdf文件合并成一个?
  17. html 动态文本框的值,HTML Javascript动态添加和删除文本框
  18. excel设置行高和列宽_Excel使用小技巧-Excel里设置列宽和行高
  19. python在地图上标注点_只要两步,用Python将地址标记在地图上!
  20. 塔防游戏制作教程(三)

热门文章

  1. 如何在Python中将元素添加到列表
  2. scala 写入文件_Scala文件IO –写入文件,读取文件
  3. java8foreach_Java forEach – Java 8 forEach
  4. 斯威夫特山地车_斯威夫特枚举
  5. 如何在Ubuntu 18.04上安装Elasticsearch Logstash Kibana(Elastic Stack)
  6. 二叉树 平衡二叉树 红黑树_迅捷树,二叉树
  7. 全栈工程师的3个关键技能是什么?
  8. 人工智能重点领域有哪些呢?
  9. php高效获取数据分页
  10. PHP+MySQL 网站 SQL 注入攻击测试用例