JZ2440按键驱动-中断方式实现_Mr.D!的博客-程序员宅基地

技术标签: 驱动  S3C2440  linux  嵌入式驱动开发  内核  JZ2440  嵌入式  

模块名称:buttons_drv.c
开发环境:Ubuntu 16.04
编译环境:Linux 2.6.22.6
最后修改:2019.03.07

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#include <linux/poll.h>

static unsigned char key_val ;
static struct class *buttons_drv_class ; 
static struct class_device *buttons_drv_dev ;		

static volatile unsigned long *gpfcon ;
static volatile unsigned long *gpfdat ;
static volatile unsigned long *gpgcon ;
static volatile unsigned long *gpgdat ;

/* 等待队列:
 * 当没有按键按下时,如果有应用程序调用buttons_drv_read()
 * 它将休眠
 */
static DECLARE_WAIT_QUEUE_HEAD(button_wait); 

/* 中断标记事件
 * 中断服务程序将它置1
 * buttons_drv_read()将它清除
 */
static volatile int ev_press = 0 ;

struct pin_desc {
	unsigned char pin ;
	unsigned char key_val ;
} ;

/* 按键描述结构体 引脚,按键值 */
static struct pin_desc pins_desc[4] = {
	{S3C2410_GPF0,  0x01},
	{S3C2410_GPF2,  0x02}, 
	{S3C2410_GPG3,  0x03}, 
	{S3C2410_GPG11, 0x04}, 
} ;


/* 按键中断处理函数 */
static irqreturn_t buttons_irq_handle(int irq, void *dev_id)
{
	struct pin_desc *my_pin_desc = (struct pin_desc *)dev_id ;
	unsigned int pin_val = 0 ;

	/* 获取引脚电平值 */
	pin_val = s3c2410_gpio_getpin(my_pin_desc->pin) ;

	if(!pin_val)
	{
		key_val = my_pin_desc->key_val ;
	}
	else 
	{
		key_val = my_pin_desc->key_val | 0x80 ;
	}

	ev_press = 1 ;
	wake_up_interruptible(&button_wait) ;
	
	return IRQ_HANDLED ;
}

/* 当应用程序open时,函数将向内核申请中断 */
static int buttons_drv_open(struct inode * inode, struct file * file)
{
	/* 向内核请求外部中断 */
	request_irq(IRQ_EINT0,  buttons_irq_handle, IRQ_TYPE_EDGE_BOTH, "S2", &pins_desc[0]);
	request_irq(IRQ_EINT2,  buttons_irq_handle, IRQ_TYPE_EDGE_BOTH, "S3", &pins_desc[1]);
	request_irq(IRQ_EINT11, buttons_irq_handle, IRQ_TYPE_EDGE_BOTH, "S4", &pins_desc[2]);	
	request_irq(IRQ_EINT19, buttons_irq_handle, IRQ_TYPE_EDGE_BOTH, "S5", &pins_desc[3]);

	return 0 ;	
}

/* 当应用程序read时,函数将按键值传到用户空间 */
static ssize_t buttons_drv_read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off)
{
	if(bytes != 1)
		return -EINVAL ;
	
	wait_event_interruptible(button_wait, ev_press) ;
	copy_to_user(userbuf, &key_val, 1) ;
	ev_press  = 0 ;
	return 1 ;
}

static int buttons_drv_close(struct inode * inode, struct file * file)
{
	/* 释放中断 */
	free_irq(IRQ_EINT0,  &pins_desc[0]) ;
	free_irq(IRQ_EINT2,  &pins_desc[1]) ;
	free_irq(IRQ_EINT11, &pins_desc[2]) ;
	free_irq(IRQ_EINT19, &pins_desc[3]) ;
	
	return 0 ;
}

/* 驱动架构核心结构体 - file_operations */
static struct file_operations buttons_fops = {
	.owner   = THIS_MODULE, 
	.open    = buttons_drv_open, 
	.read    = buttons_drv_read, 
	.release = buttons_drv_close, 
} ;

static int major = 0 ;		//主设备号

/* 驱动入口函数 */
static int buttons_drv_init(void)
{
	/* 注册字符设备 */
	major = register_chrdev(0, "buttons_drv", &buttons_fops) ;

	/* 自动创建设备节点 udev机制 */
	buttons_drv_class = class_create(THIS_MODULE, "buttons_drv") ;

	/* 创建设备节点 */
	buttons_drv_dev = class_device_create(buttons_drv_class, NULL, MKDEV(major, 0), NULL, "buttons") ;

	
#if 0	//使用中断机制不需要映射虚拟地址
	/* 虚拟地址映射 */
	gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16) ;
	gpfdat = gpfcon + 1 ;
	gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16) ;
	gpgdat = gpgcon + 1 ;
#endif
	
	return 0 ;
}

/* 驱动出口函数 */
static void buttons_drv_exit(void)
{
	/* 卸载字符设备 */
	unregister_chrdev(major, "buttons_drv") ;

	/* 删除设备节点 */
	class_device_unregister(buttons_drv_dev) ;

	/* 销毁节点类 */
	class_destroy(buttons_drv_class) ;

#if 0
	/* 解除虚拟地址映射 */
	iounmap(gpfcon) ;
	iounmap(gpgcon) ;
#endif

	return ;
}

/* 驱动入口:加载 */
module_init(buttons_drv_init) ;

/* 驱动出口:卸载 */
module_exit(buttons_drv_exit) ;

/* 许可 */
MODULE_LICENSE("GPL") ;
模块名称:buttons_test.c
开发环境:Ubuntu 16.04
编译环境:Linux 2.6.22.6
最后修改:2019.03.07

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

int main(int argv, char **argc)
{
	int fd ;
	unsigned char key_val ;

	/* 以读写方式打开设备 */
	fd = open("/dev/buttons", O_RDWR) ;
	if(fd < 0)
	{
		printf("can't open!\n") ;
		//return -1 ; 
	}

	while(1)
	{
		/* 从驱动读取按键值到key_val */
		read(fd, &key_val, 1) ;

		/* 串口打印键值 */
		printf("key_val = 0x%x\n", key_val) ;
	}
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_36535963/article/details/88300101

智能推荐

模块与包以及部分Python学习手册的摘录_无知游民lx的博客-程序员宅基地

模块对应于Python源代码文件多个功能相似的模块可以组织成一个包。Python中的模块包括系统模块、第三方模块和用户自定义模块。它们实质上是以.py为扩展名的Python文件通过导入模块,可以使用该模块中的变量、函数和类等。模块化程序设计的概念如果程序中包含多个可以复用的函数或类,则通常把相关的函数和类分组包含在单独的模块中。这些提供计算功能的模块称之为模块(或函数模块),导入并使...

【SpringBoot系列】SpringBoot注解详解_weixin_34186128的博客-程序员宅基地

【SpringBoot系列】SpringBoot注解详解一、注解(annotations)列表@SpringBootApplication:包含了@ComponentScan、@Configuration和@EnableAutoConfiguration注解。其中@ComponentScan让Spring Boot扫描到Configuration类...

Spring Boot实战(二)Spring常用配置 2.4 Profile_qq_3642489的博客-程序员宅基地

2.4.1点睛Profile为在不同环境下使用不同的配置提供了支持(开发环境下的配置和生产环境下的配置肯定是不同的,例如,数据库的配置)。(1)通过设定Environment的 ActiveProfiles来设定当前context需要使用的配置环境。在开发中使用@Profile注解类或者方法,达到在不同情况下选择实例化不同的Bean。(2)通过设定jvm的spring.profiles.ac...

不一样的技术创新——阿里巴巴2016双11背后的技术_weixin_34419321的博客-程序员宅基地

每年的“双11”是阿里技术的大阅兵和创新能力的集中检阅。2016年的“双11”背后,更是蕴藏了异常丰富的技术实践与突破。 历经1个月的编写,最终27篇精华技术文章入册《不一样的技术创新-阿里巴巴2016双11背后的技术》(以下简称《不一样的技术创新》)一书。这27篇“24K纯度”的技术干货,是阿里“双11”八年来技术演进结果的最新展示,凝聚了阿里工程师...

20155333 《网络对抗》 Exp6 信息搜集与漏洞扫描_aodieshao2474的博客-程序员宅基地

20155333 《网络对抗》 Exp6 信息搜集与漏洞扫描基础问题哪些组织负责DNS,IP的管理?全球根服务器均由美国政府授权的ICANN统一管理,负责全球的域名根服务器、DNS和IP地址管理。全球根域名服务器:绝大多数在欧洲和北美(全球13台,用A~M编号),中国仅拥有镜像服务器(备份)。全球一共有5个地区性注册机构:ARIN主要负责北美地区业务,RIPE主要负责欧洲...

技术分析| 音视频服务集群如何实现全球多中心化调度_anyRTC的博客-程序员宅基地

anyRTC提供全球领先的实时音视频云服务,客户涉及社交娱乐,金融保险,政企,安防等行业,累计帮助全球近千家企业客户获得音视频通讯能力。面对庞大客户音视频的需求,利用多中心化调度的服务架构,扛住了千万级的高并发,做到灵活调度,为广大客户带来优质的音视频体验。在客户请求量和流量暴增的情况下,我们的音视频服务无论何时都能做到零故障弹性的伸缩。我们的流媒体传输使用分层传输,而在这样的传输架构下,多中心化的调度服务的作用至关重要。单中心调度服务面临的问题和挑战:一、网络延时大。比如香港到西欧或者北美,物理距

随便推点

✿Android 3.1 --- 久违的 USB、mtp、rtp_weixin_30254435的博客-程序员宅基地

3.1多了三个大包android.hardware.usb、android.mtp、 android.net.rtp !USB、mtp、rtp-------三个字眼,各个血淋淋,让人悲喜交加,Google你为何不早点发?android.mtp让连接的camera和其他设备,直接使用PTP(图像传输协议)的MTP(媒体传输协议)。...

Mysql新增自增长主键列_DreamMakers的博客-程序员宅基地_mysql添加自增主键

有的时候需要对于一个Mysql数据库表添加个自动增长主键,刚开始的时候使用下面的语句:alter table taskinfoconfig add column id int(10) not null auto_increment ;alter table taskinfoconfig add primary key(id);可是在执行的时候发现报错,信息如下:In

Scala基本语法及使用_chenpanjc799055的博客-程序员宅基地

ScalaAuthor: LijbEmail: [email protected]是一门多范式的编程语言,同时支持面向对象和面向函数编程风格。它以一种优雅的方式解决现实问题。虽然它是强静态类型的编程语言,但是它强大的类型推断能力,使其看起来就像是一个动态编程语言一样。Scala语...

生成sprite动画对象的方法_weixin_30438813的博客-程序员宅基地

以下只是一个最原始的方法,从执行效率的角度出发,如果一个场景里面同时包含了100个使用相同动画的sprit,每个 动画sprite都由下面的方法生成的话,有些代码:1.缓冲sprite帧和纹理;2.创建一个精灵节点;3.收集帧列表;这些个只需要执行一次的操作便被重复执行了 100次,浪费cpu,浪费电池电量。。所以说,还是存在相当大的优化空间。。。- (CCSp...

VB 格式化小数,保留N位_小鹰信息技术服务部的博客-程序员宅基地_vbformat保留三位小数

VB格式化小数,小数点后保留三位。一开始用Format(number, &quot;0.000&quot;) 发现一个问题,有时小数点前面的0没有显示 解决的办法:改用FormatNumberFormatNumber(number, 3, vbTrue)   'vbTrue表示保留小数点前面的0 问题解决。...

Transformer BERT KG-BERT_日长永昼的博客-程序员宅基地

第二次组会 10.26研究方向:知识表示学习两个重要的知识表示学习综述:知乎:1. KG笔记十、知识图谱嵌入(KG Embedding)https://zhuanlan.zhihu.com/p/3548671792. 刘知远大神《知识表示学习研究进展》的学习小结https://zhuanlan.zhihu.com/p/3561475383. 知识图谱最新权威综述论文解读:知识表示学习部分https://zhuanlan.zhihu.com/p/141396088下次讨论的论文:Interac