代码示例_mmap的实现
//头文件 #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/device.h> #include <linux/slab.h> #include <linux/gpio.h> #include <linux/cdev.h> #include <linux/interrupt.h> #include <linux/input.h> #include <linux/sched.h> #include <linux/poll.h> #include <linux/mm.h>#include <asm/io.h> #include <asm/page.h> #include <asm/string.h> #include <asm/uaccess.h> #include <asm-generic/ioctl.h>#define BUTTON_iOC_GET_DATA 0x4321 struct mem_data{char buf[128]; };//定义一个按键的数据包 struct button_event{int code; //按键的名称---键值:KEY_DOWNint value; //按键的状态---按下:1,松开:0 };//设计一个描述按键的结构体类型 struct buttons{char *name; //名称unsigned int irqno; //中断号int gpio; //按键对应的gpio口int code; //键值unsigned long flags; //触发方式 };//定义一个数组来保存多个按键的数据 struct buttons buttons_set[] = {[0] = {.name = "key1_up",.irqno = IRQ_EINT(0),.gpio = S5PV210_GPH0(0),.code = KEY_UP,.flags = IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,},[1] = {.name = "key2_down",.irqno = IRQ_EINT(1),.gpio = S5PV210_GPH0(1),.code = KEY_DOWN,.flags = IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,},[2] = {.name = "key3_left",.irqno = IRQ_EINT(2),.gpio = S5PV210_GPH0(2),.code = KEY_LEFT,.flags = IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,},[3] = {.name = "key4_right",.irqno = IRQ_EINT(3),.gpio = S5PV210_GPH0(3),.code = KEY_RIGHT,.flags = IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,}, };//面向对象编程----设计设备的类型 struct s5pv210_button{//unsigned int major; dev_t devno;struct class * cls;struct device * dev;struct cdev *cdev;unsigned int irqno;struct button_event event;wait_queue_head_t wq_head;int have_data; //表示当前是否有数据可读,可读--1,不可读--0void * virt_mem; }; struct s5pv210_button *button_dev;//实现中断处理函数--------当触发中断时会被执行 irqreturn_t button_irq_svc(int irqno, void *dev) {int value;struct buttons *p;printk("--------^_^ %s------------\n",__FUNCTION__);//获取当前触发中断的按键信息p = (struct buttons *)dev;//获取产生中断的gpio口的值value = gpio_get_value(p->gpio);//判断是按下还是松开if(value){//松开printk("kernel:%s up!\n",p->name);button_dev->event.code = p->code;button_dev->event.value = 0;}else{//按下printk("kenel:%s pressed!\n",p->name);button_dev->event.code = p->code;button_dev->event.value = 1;}//此时有数据可读button_dev->have_data = 1;//从等待队列中唤醒阻塞的进程wake_up_interruptible(&button_dev->wq_head);return IRQ_HANDLED; }//实现设备操作接口 int button_open(struct inode *inode, struct file *filp) {printk("--------^_^ %s------------\n",__FUNCTION__);return 0; } ssize_t button_read(struct file *filp , char __user *buf , size_t size, loff_t *flags) {int ret;printk("--------^_^ %s------------\n",__FUNCTION__);//判读open时,有没有设置flags为NONBLOCKif(filp->f_flags & O_NONBLOCK && !button_dev->have_data)return -EAGAIN;//判断此时是否有数据可读wait_event_interruptible(button_dev->wq_head,button_dev->have_data);//将内核数据转换为用户空间数据ret = copy_to_user(buf,&button_dev->event,size);if(ret > 0){printk("copy_to_user error!\n");return -EFAULT;}//将数据返回给应用空间后,清空数据包,同时将hava_data置零memset(&button_dev->event,0,sizeof(button_dev->event));button_dev->have_data = 0;return size; }ssize_t button_write(struct file *filp, const char __user *buf, size_t size, loff_t *flags) {printk("--------^_^ %s------------\n",__FUNCTION__);return size; }long button_ioctl(struct file *filp, unsigned int cmd , unsigned long args) {void __user *argp;struct mem_data data;int ret;printk("--------^_^ %s------------\n",__FUNCTION__);argp = (void __user *)args;switch(cmd){case BUTTON_iOC_GET_DATA:memset(data.buf,0,sizeof(data.buf));memcpy(data.buf, button_dev->virt_mem,sizeof(data.buf));ret = copy_to_user(argp,&data,sizeof(data));if(ret > 0){return -EFAULT;}break;default:printk("unkown cmd!\n");}return 0; }int button_mmap(struct file *filp, struct vm_area_struct *vma) {unsigned int addr;printk("--------^_^ %s------------\n",__FUNCTION__);//1,获得一块物理内存空间-----将申请的虚拟空间转换为对应的物理空间addr = virt_to_phys(button_dev->virt_mem); //2,将物理内存映射到虚拟空间---应用空间 vma->vm_flags |= VM_IO;vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT,PAGE_SIZE, vma->vm_page_prot)) {printk(KERN_ERR "%s: io_remap_pfn_range failed\n",__func__);return -EAGAIN;}return 0; }unsigned int button_poll(struct file *filp, struct poll_table_struct *pts) {unsigned int mask = 0;printk("--------^_^ %s------------\n",__FUNCTION__);//1,将等待队列头注册到系统中(VFS)poll_wait(filp,&button_dev->wq_head,pts);//2,如果产生按键中断-有数据可读,此时返回POLLIN,如果没有数据返回0if(button_dev->have_data)mask |= POLLIN;return mask;}int button_close(struct inode *inode, struct file *filp) {printk("--------^_^ %s------------\n",__FUNCTION__);return 0; }static struct file_operations fops = {.open = button_open,.read = button_read,.write = button_write,.poll = button_poll,.mmap = button_mmap,.unlocked_ioctl = button_ioctl,.release = button_close, };//加载函数和卸载函数 static int __init button_init(void) //加载函数-----在驱动被加载时执行 {int ret,i;printk("--------^_^ %s------------\n",__FUNCTION__);//0,实例化设备对象//参数1 ---- 要申请的空间的大小//参数2 ---- 申请的空间的标识button_dev = kzalloc(sizeof(struct s5pv210_button),GFP_KERNEL);if(IS_ERR(button_dev)){printk("kzalloc error!\n");ret = PTR_ERR(button_dev);return -ENOMEM;}//1,申请设备号-----新方法 #if 0//静态申请设备号button_dev->major = 256;ret = register_chrdev_region(MKDEV(button_dev->major,0),1,"button_drv");if(ret < 0){printk("register_chrdev_region error!\n");ret = -EINVAL;goto err_kfree;} #else//动态申请设备号ret = alloc_chrdev_region(&button_dev->devno,0,1,"button_drv");if(ret < 0){printk("register_chrdev_region error!\n");ret = -EINVAL;goto err_kfree;} #endif//创建cdev//申请cdev的空间button_dev->cdev = cdev_alloc();if(IS_ERR(button_dev->cdev)){ printk("button_dev->cdev error!\n");ret = PTR_ERR(button_dev->cdev);goto err_unregister;}//初始化cdev的成员cdev_init(button_dev->cdev,&fops);//将cdev加入到内核中----链表ret = cdev_add(button_dev->cdev,button_dev->devno,1);//2,创建设备文件-----/dev/buttonbutton_dev->cls = class_create(THIS_MODULE,"button_cls");if(IS_ERR(button_dev->cls)){printk("class_create error!\n");ret = PTR_ERR(button_dev->cls);goto err_cdev_del;}button_dev->dev = device_create(button_dev->cls,NULL,button_dev->devno,NULL,"button");if(IS_ERR(button_dev->dev)){printk("device_create error!\n");ret = PTR_ERR(button_dev->dev);goto err_class;}//3,硬件初始化---申请中断for(i = 0; i < ARRAY_SIZE(buttons_set);i++){ret = request_irq(buttons_set[i].irqno,button_irq_svc,buttons_set[i].flags,buttons_set[i].name,&buttons_set[i]);if(ret != 0){printk("request_irq error!\n");ret = -EBUSY;goto err_device;}}//初始化等待队列头init_waitqueue_head(&button_dev->wq_head);//获取一块虚拟的内存空间---内核中button_dev->virt_mem = kzalloc(PAGE_SIZE,GFP_KERNEL);if(IS_ERR(button_dev->virt_mem)){printk("kzalloc error!\n");ret = -EBUSY;goto err_free_irq;}return 0; err_free_irq:for(i = 0; i < ARRAY_SIZE(buttons_set);i++){free_irq(buttons_set[i].irqno,&buttons_set[i]);} err_device:device_destroy(button_dev->cls,button_dev->devno); err_class:class_destroy(button_dev->cls);err_cdev_del:cdev_del(button_dev->cdev);err_unregister:unregister_chrdev_region(button_dev->devno,1);err_kfree:kfree(button_dev);return ret;}static void __exit button_exit(void) //卸载函数-----在驱动被卸载时执行 {int i;printk("--------^_^ %s------------\n",__FUNCTION__);kfree(button_dev->virt_mem); for(i = 0; i < ARRAY_SIZE(buttons_set);i++){free_irq(buttons_set[i].irqno,&buttons_set[i]);}device_destroy(button_dev->cls,button_dev->devno);class_destroy(button_dev->cls);cdev_del(button_dev->cdev);unregister_chrdev_region(button_dev->devno,1);kfree(button_dev); }//声明和认证 module_init(button_init); module_exit(button_exit); MODULE_LICENSE("GPL");
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include <poll.h> #include <sys/mman.h> #include <linux/input.h>//定义一个按键的数据包 struct button_event{int code; //按键的名称---键值:KEY_DOWNint value; //按键的状态---按下:1,松开:0 };#define BUTTON_iOC_GET_DATA 0x4321 #define PAGE_SIZE 1UL<<12 struct mem_data{char buf[128]; }; int main(void) {int fd;int ret;struct button_event event;struct pollfd pfds[2];char buf[128];char *str = "hello kernel";struct mem_data data;fd = open("/dev/button",O_RDWR);if(fd < 0){perror("open");exit(1);}//测试mmap的功能char *addr = mmap(NULL,PAGE_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if(addr == NULL){perror("mmap");exit(1);}//向映射的物理空间中写数据 strcpy(addr,str);sleep(1);//验证数据是否写入到映射的物理空间----通过ioctl读取数据ret = ioctl(fd,BUTTON_iOC_GET_DATA,&data);if(ret < 0){perror("ioctl");exit(1);}printf("data.buf = %s\n",data.buf); //将读到的数据打印出来sleep(1);pfds[0].fd = 0; //标准输入文件描述符pfds[0].events = POLLIN; //是否可读 pfds[1].fd = fd; //开发板中的键盘pfds[1].events = POLLIN; //按键是否触发中断while(1){ret = poll(pfds,2,-1);if(ret < 0){perror("poll");exit(1);}if(ret > 0){//标准输入可读if(pfds[0].revents & POLLIN){fgets(buf,sizeof(buf),stdin);printf("%s",buf);}//开发板中的按键触发了中断 if(pfds[1].revents & POLLIN){bzero(&event,sizeof(event));ret = read(fd,&event,sizeof(event));if(ret < 0){perror("read");exit(1);}switch(event.code){case KEY_UP:if(event.value)printf("按下了上键!\n");elseprintf("松开了上键!\n");break;case KEY_DOWN:if(event.value)printf("按下了下键!\n");elseprintf("松开了下键!\n");break;case KEY_LEFT:if(event.value)printf("按下了左键!\n");elseprintf("松开了左键!\n");break;case KEY_RIGHT:if(event.value)printf("按下了右键!\n");elseprintf("松开了右键!\n");break;}}}}close(fd);return 0; }
#指定内核源码路径 KERNEL_DIR = /home/farsight/s5pv210/kernel/linux-3.0.8 CUR_DIR = $(shell pwd) MYAPP = testall:#让make进入内核源码编译,同时将当前目录中的c程序作为内核模块一起编译make -C $(KERNEL_DIR) M=$(CUR_DIR) modulesarm-none-linux-gnueabi-gcc -o $(MYAPP) $(MYAPP).cclean:#删除上面编译生成的文件make -C $(KERNEL_DIR) M=$(CUR_DIR) cleanrm -rf $(MYAPP)install:cp *.ko $(MYAPP) /opt/rootfs/drv_module#指定当前目录下哪个文件作为内核模块编 obj-m = button_drv.o
转载于:https://www.cnblogs.com/panda-w/p/10991438.html
代码示例_mmap的实现相关推荐
- 用户自定义协议client/server代码示例
用户自定义协议client/server代码示例 代码参考链接:https://github.com/sogou/workflow message.h message.cc server.cc cli ...
- 2021年大数据Flink(二十六):State代码示例
目录 State代码示例 Keyed State 官网代码示例 需求: 编码步骤 代码示例 Operator State 官网代码示例 需求: 编码步骤: 代码示例 State代码示例 Keyed S ...
- TensorFlow常用操作:代码示例
1,定义矩阵代码示例: import tensorflow as tftf.zeros([3,4]) #定义3行4列元素均为0的矩阵tensor=tf.constant([1,2,3,4])#定义一维 ...
- TensorFlow基本计算单元:代码示例
1,代码示例: import tensorflow as tf a = 3 #创建变量 w = tf.Variable([[0.6,1.2]])#创建行向量 x = tf.Variable([[2.1 ...
- php mms,PHP代码示例_PHP账号余额查询接口 | 微米-中国领先的短信彩信接口平台服务商...
PHP余额查询接口代码示例 请求 $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "http://api.weimi.cc/2/accoun ...
- java结束全部操作代码_Java创建与结束线程代码示例
这篇文章主要介绍了Java创建与结束线程代码示例,小编觉得挺不错的,这里分享给大家,供需要的朋友参考. 本文讲述了在Java中如何创建和结束线程的最基本方法,只针对于Java初学者.一些高级知识如线程 ...
- doc python 颜色_Python wordcloud.ImageColorGenerator方法代码示例
本文整理汇总了Python中wordcloud.ImageColorGenerator方法的典型用法代码示例.如果您正苦于以下问题:Python wordcloud.ImageColorGenerat ...
- 机器学习简单代码示例
机器学习简单代码示例 //在gcc-4.7.2下编译通过. //命令行:g++ -Wall -ansi -O2 test.cpp -o test #include <iostream> u ...
- 手机如何看python代码_python如何绘制iPhone手机图案?(代码示例)
本篇文章给大家带来的内容是介绍python如何绘制iPhone手机图案?(代码示例).有一定的参考价值,有需要的朋友可以参考一下,希望对你们有所帮助. 虽然我用不起苹果手机,但我可以用python画出 ...
- python编程代码示例_python编程线性回归代码示例
用python进行线性回归分析非常方便,有现成的库可以使用比如:numpy.linalog.lstsq例子.scipy.stats.linregress例子.pandas.ols例子等. 不过本文使用 ...
最新文章
- 人类血液中首次发现微塑料颗粒,饮料瓶塑料袋化妆品都是来源
- Qt学习之路(35): Qt容器类之顺序存储容器
- CTFshow 反序列化 web268
- Spring 和 Spring Boot 之间到底有啥区别?
- selenium,webdriver 执行js语句 对象是百度
- sap 订单状态修改时间_SAP中对于获取订单的状态
- 【HDU - 2255】奔小康赚大钱(KM算法模板,二分图最优匹配)
- 03 | AI 术语:让你变得更加专业
- Mac搭建PHP+rabbitMQ环境
- .NET平台开源项目速览(6)FluentValidation验证组件介绍与入门(一)
- 学python有前途吗-2019年转行学Python有还前途吗?如何学习Python?
- Q127:PBRT-V3,理解“体渲染”积分器的关键竟然是这张图
- php 404重定向,如何使用PHP实现在WordPress中将404错误页面重定向到主页
- 数据--第40课 - 图的定义
- 文章2:多功能智能跟随行李箱控制系统设计 | 本科毕业设计 - 【论文终稿】
- 如何利用BERT做文本摘要
- autojs各种插件以及教程模板
- Epoch Based Reclamation 的个人理解
- 淘宝、京东电商的崛起,为什么如今越来越多的企业选择java商城?
- Nosql之Redis的概念介绍+安装配置+Redis数据库基本操作
热门文章
- 基于局部自适应阈值的图像二值化
- 【kuangbin专题】Manacher
- 如何整合Mybatis与Spring框架?
- c语言中按字节运算,C语言中位运算的巧用
- html 加粗_一篇文章带你了解HTML格式化元素
- 数据库学习笔记3-隔离级别 Read Uncommitted
- Mybatis--关于插入数据后返回id的操作
- 云南民大java期中考试_中南民族大学Java语言程序设计期末试卷A卷
- java文件乱码 环境变量_JAVA安装后,环境变量的PATH被我改了,后来发现改错了,但是不知道怎么改回去了,就是一堆乱码的...
- 基于springboot+vue的学生选课系统(前后端分离)