//头文件
#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的实现相关推荐

  1. 用户自定义协议client/server代码示例

    用户自定义协议client/server代码示例 代码参考链接:https://github.com/sogou/workflow message.h message.cc server.cc cli ...

  2. 2021年大数据Flink(二十六):​​​​​​​State代码示例

    目录 State代码示例 Keyed State 官网代码示例 需求: 编码步骤 代码示例 Operator State 官网代码示例 需求: 编码步骤: 代码示例 State代码示例 Keyed S ...

  3. TensorFlow常用操作:代码示例

    1,定义矩阵代码示例: import tensorflow as tftf.zeros([3,4]) #定义3行4列元素均为0的矩阵tensor=tf.constant([1,2,3,4])#定义一维 ...

  4. TensorFlow基本计算单元:代码示例

    1,代码示例: import tensorflow as tf a = 3 #创建变量 w = tf.Variable([[0.6,1.2]])#创建行向量 x = tf.Variable([[2.1 ...

  5. php mms,PHP代码示例_PHP账号余额查询接口 | 微米-中国领先的短信彩信接口平台服务商...

    PHP余额查询接口代码示例 请求 $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "http://api.weimi.cc/2/accoun ...

  6. java结束全部操作代码_Java创建与结束线程代码示例

    这篇文章主要介绍了Java创建与结束线程代码示例,小编觉得挺不错的,这里分享给大家,供需要的朋友参考. 本文讲述了在Java中如何创建和结束线程的最基本方法,只针对于Java初学者.一些高级知识如线程 ...

  7. doc python 颜色_Python wordcloud.ImageColorGenerator方法代码示例

    本文整理汇总了Python中wordcloud.ImageColorGenerator方法的典型用法代码示例.如果您正苦于以下问题:Python wordcloud.ImageColorGenerat ...

  8. 机器学习简单代码示例

    机器学习简单代码示例 //在gcc-4.7.2下编译通过. //命令行:g++ -Wall -ansi -O2 test.cpp -o test #include <iostream> u ...

  9. 手机如何看python代码_python如何绘制iPhone手机图案?(代码示例)

    本篇文章给大家带来的内容是介绍python如何绘制iPhone手机图案?(代码示例).有一定的参考价值,有需要的朋友可以参考一下,希望对你们有所帮助. 虽然我用不起苹果手机,但我可以用python画出 ...

  10. python编程代码示例_python编程线性回归代码示例

    用python进行线性回归分析非常方便,有现成的库可以使用比如:numpy.linalog.lstsq例子.scipy.stats.linregress例子.pandas.ols例子等. 不过本文使用 ...

最新文章

  1. 人类血液中首次发现微塑料颗粒,饮料瓶塑料袋化妆品都是来源
  2. Qt学习之路(35): Qt容器类之顺序存储容器
  3. CTFshow 反序列化 web268
  4. Spring 和 Spring Boot 之间到底有啥区别?
  5. selenium,webdriver 执行js语句 对象是百度
  6. sap 订单状态修改时间_SAP中对于获取订单的状态
  7. 【HDU - 2255】奔小康赚大钱(KM算法模板,二分图最优匹配)
  8. 03 | AI 术语:让你变得更加专业
  9. Mac搭建PHP+rabbitMQ环境
  10. .NET平台开源项目速览(6)FluentValidation验证组件介绍与入门(一)
  11. 学python有前途吗-2019年转行学Python有还前途吗?如何学习Python?
  12. Q127:PBRT-V3,理解“体渲染”积分器的关键竟然是这张图
  13. php 404重定向,如何使用PHP实现在WordPress中将404错误页面重定向到主页
  14. 数据--第40课 - 图的定义
  15. 文章2:多功能智能跟随行李箱控制系统设计 | 本科毕业设计 - 【论文终稿】
  16. 如何利用BERT做文本摘要
  17. autojs各种插件以及教程模板
  18. Epoch Based Reclamation 的个人理解
  19. 淘宝、京东电商的崛起,为什么如今越来越多的企业选择java商城?
  20. Nosql之Redis的概念介绍+安装配置+Redis数据库基本操作

热门文章

  1. 基于局部自适应阈值的图像二值化
  2. 【kuangbin专题】Manacher
  3. 如何整合Mybatis与Spring框架?
  4. c语言中按字节运算,C语言中位运算的巧用
  5. html 加粗_一篇文章带你了解HTML格式化元素
  6. 数据库学习笔记3-隔离级别 Read Uncommitted
  7. Mybatis--关于插入数据后返回id的操作
  8. 云南民大java期中考试_中南民族大学Java语言程序设计期末试卷A卷
  9. java文件乱码 环境变量_JAVA安装后,环境变量的PATH被我改了,后来发现改错了,但是不知道怎么改回去了,就是一堆乱码的...
  10. 基于springboot+vue的学生选课系统(前后端分离)