Linux按钮驱动

按钮中断例程

/*************************************

NAME:EmbedSky_hello.c
COPYRIGHT:www.embedsky.net

*************************************/

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>

#define DEVICE_NAME     "IRQ-Test" //设备名称

struct button_irq_desc {
    int irq;//中断号码
    int pin;//引脚
    int pin_setting;//引脚功能
    int number;//编号
    char *name;	//设备名称
};
//定义两套按钮
#if !defined (CONFIG_SKY2440_IRQ_TEST)
static struct button_irq_desc button_irqs [] = {
	{IRQ_EINT1,	S3C2410_GPF1,	S3C2410_GPF1_EINT1,	0, "KEY1"}, /* K1 */
	{IRQ_EINT4,	S3C2410_GPF4,	S3C2410_GPF4_EINT4,	1, "KEY2"}, /* K2 */
	{IRQ_EINT2,	S3C2410_GPF2,	S3C2410_GPF2_EINT2,	2, "KEY3"}, /* K3 */
	{IRQ_EINT0,	S3C2410_GPF0,	S3C2410_GPF0_EINT0,	3, "KEY4"}, /* K4 */
};
#else
static struct button_irq_desc button_irqs [] = {
	{IRQ_EINT9,	S3C2410_GPG1,	S3C2410_GPG1_EINT9,	0, "KEY1"}, /* K1 */
	{IRQ_EINT11,	S3C2410_GPG3,	S3C2410_GPG3_EINT11,	1, "KEY2"}, /* K2 */
	{IRQ_EINT2,	S3C2410_GPF2,	S3C2410_GPF2_EINT2,	2, "KEY3"}, /* K3 */
	{IRQ_EINT0,	S3C2410_GPF0,	S3C2410_GPF0_EINT0,	3, "KEY4"}, /* K4 */
};
#endif
static volatile char key_values [] = {‘0‘, ‘0‘, ‘0‘, ‘0‘};

static DECLARE_WAIT_QUEUE_HEAD(button_waitq);//生成一个等待队列

static volatile int ev_press = 0;

static irqreturn_t irq_interrupt(int irq, void *dev_id)
{
	struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;
	int down;

	down = !s3c2410_gpio_getpin(button_irqs->pin);

	if (down != (key_values[button_irqs->number] & 1))//检测是否一样,并保存到key_values中
	{
		key_values[button_irqs->number] = ‘0‘ + down;
		ev_press = 1;
		wake_up_interruptible(&button_waitq);
	}

	return IRQ_RETVAL(IRQ_HANDLED);//返回值,标准格式
}

static int tq2440_irq_open(struct inode *inode, struct file *file)
{
	int i;
	int err = 0;

	for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++)
	{
		if (button_irqs[i].irq < 0)//检查完毕后跳出
			continue;
		err = request_irq(button_irqs[i].irq, irq_interrupt, IRQ_TYPE_EDGE_BOTH,
                          button_irqs[i].name, (void *)&button_irqs[i]);
		//共用一个中断处理程序。

		if (err)
			break;
	}

	if (err)
	{
		i--;
		for (; i >= 0; i--)
		{
			if (button_irqs[i].irq < 0)
				continue;
			disable_irq(button_irqs[i].irq);
			free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);
		}
		return -EBUSY;
	}

	ev_press = 1;

	return 0;
}

static int tq2440_irq_close(struct inode *inode, struct file *file)
{
	int i;

	for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++)
	{
		if (button_irqs[i].irq < 0)//没有设置过,就不用打开。
			continue;
		free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);
	}

	return 0;
}

static int tq2440_irq_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
{
	unsigned long err;

	if (!ev_press)
	{
		if (filp->f_flags & O_NONBLOCK)
			return -EAGAIN;
		else
			wait_event_interruptible(button_waitq, ev_press);
	}

	ev_press = 0;

	err = copy_to_user(buff, (const void *)key_values, min(sizeof(key_values), count));

	return err ? -EFAULT : min(sizeof(key_values), count);
}

static unsigned int tq2440_irq_poll( struct file *file, struct poll_table_struct *wait)
{
	unsigned int mask = 0;
	poll_wait(file, &button_waitq, wait);
	if (ev_press)
		mask |= POLLIN | POLLRDNORM;
	return mask;
}

//
static struct file_operations dev_fops = {
	.owner	=   THIS_MODULE,
	.open	=   tq2440_irq_open,
	.release	=   tq2440_irq_close,
	.read	=   tq2440_irq_read,
	.poll	=   tq2440_irq_poll,
};
//定义一个设备
static struct miscdevice misc = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = DEVICE_NAME,
	.fops = &dev_fops,
};

static int __init dev_init(void)
{
	int ret;

	ret = misc_register(&misc);

	printk (DEVICE_NAME" initialized\n");

	return ret;
}

static void __exit dev_exit(void)
{
	misc_deregister(&misc);
}

module_init(dev_init);
module_exit(dev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("www.embedsky.net");
MODULE_DESCRIPTION("IRQ Test for EmbedSky SKY2440/TQ2440 Board");

Linux按钮驱动,布布扣,bubuko.com

时间: 2024-08-17 00:20:01

Linux按钮驱动的相关文章

linux无线网卡驱动安装

环境  在笔记本里的虚拟机10.0版本,centos-6.5 无线网卡fast-fw300um 第一步要查看芯片  lsusb  当你得到芯片之后接下来查看内核,如果内核已经有芯片模块就不用再装了,如果不支持的话,那么接下来就到芯片官网 下载Linux驱动 http://www.realtek.com.tw/default.aspx  **虽然我的无线网卡是fast 生产的 ,但是他并没有给我们Linux的驱动,反倒是芯片商提供有驱动,所以要到芯片官网下载驱动** 首先到官网上下载无线网卡的驱动

linux设备驱动第五篇:驱动中的并发与竟态

综述 在上一篇介绍了linux驱动的调试方法,这一篇介绍一下在驱动编程中会遇到的并发和竟态以及如何处理并发和竞争. 首先什么是并发与竟态呢?并发(concurrency)指的是多个执行单元同时.并行被执行.而并发的执行单元对共享资源(硬件资源和软件上的全局.静态变量)的访问则容易导致竞态(race conditions).可能导致并发和竟态的情况有: SMP(Symmetric Multi-Processing),对称多处理结构.SMP是一种紧耦合.共享存储的系统模型,它的特点是多个CPU使用共

Linux LCD驱动(三)--图形显示

3.  BMP和JPEG图形显示程序3.1  在LCD上显示BMP或JPEG图片的主流程图首先,在程序开始前.要在nfs/dev目录下创建LCD的设备结点,设备名fb0,设备类型为字符设备,主设备号为29,次设备号为0.命令如下:mknod fb0 c 29 0在LCD上显示图象的主流程图如图3.1所示.程序一开始要调用open函数打开设备,然后调用ioctl获取设备相关信息,接下来就是读取图形文件数据,把图象的RGB值映射到显存中,这部分是图象显示的核心.对于JPEG格式的图片,要先经过JPE

Linux LCD驱动(四)--驱动的实现

目录(?)[-] 基本原理 写 framebuffer 驱动程序要做什么 LCD 模块 驱动程序 控制器 什么是 frame buffer 设备 Linux Frame Buffer 驱动程序层次结构 数据结构 接口 一个 LCD controller 驱动程序 分配系统内存作为显存 实现 fb_ops 结构 基本原理 通过 framebuffer ,应用程序用 mmap 把显存映射到应用程序虚拟地址空间,将要显示的数据写入这个内存空间就可以在屏幕上显示出来: 驱动程序分配系统内存作为显存:实现

Linux设备驱动中的阻塞和非阻塞I/O

[基本概念] 1.阻塞 阻塞操作是指在执行设备操作时,托不能获得资源,则挂起进程直到满足操作所需的条件后再进行操作.被挂起的进程进入休眠状态(不占用cpu资源),从调度器的运行队列转移到等待队列,直到条件满足. 2.非阻塞 非阻塞操作是指在进行设备操作是,若操作条件不满足并不会挂起,而是直接返回或重新查询(一直占用CPU资源)直到操作条件满足为止. 当用户空间的应用程序调用read(),write()等方法时,若设备的资源不能被获取,而用户又希望以阻塞的方式来访问设备,驱动程序应当在设备驱动层的

Smart210学习记录------linux串口驱动

转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=27025492&id=327609 一.核心数据结构 串口驱动有3个核心数据结构,它们都定义在<#include linux/serial_core.h> 1.uart_driver uart_driver包含了串口设备名.串口驱动名.主次设备号.串口控制台(可选)等信息,还封装了tty_driver(底层串口驱动无需关心tty_driver). struct

linux网卡驱动移植

这里重要的是物理层PHY receiver,MAC(media access control)层,这里与软件中的协议栈不同,在硬件上MAC是PHY的下一层.DM9000A将MAC和PHY做到一起,也可以像IIS设备那样,SOC内有IIS的控制器,而声卡UDA1341放在片外.网卡当然也有这种设计,它是把PHY的下层MAC放入SOC内,片外的是PHY,当然我暂时还没见过这种的.DM9000A的输入是并行的总线,可以和CPU直接IO.而IIS那种需要通过:CPU CORE BUS->I2S控制器->

Linux设备驱动开发 - 平台设备驱动

Linux2.6的内核中引入了一种新的设备驱动模型-平台(platform)设备驱动,平台设备驱动分为平台设备(platform_device)和平台驱动(platform_driver),平台设备的引入使得Linux设备驱动更加便于移植. 一.平台设备平台设备结构体: 1 struct platform_device { 2 const char * name; /* 设备名 */ 3 int id; 4 struct device dev; /* 设备结构体 */ 5 u32 num_res

Linux摄像头驱动学习之:(一)V4L2_框架分析

这段时间开始搞安卓camera底层驱动了,把以前的的Linux视频驱动回顾一下,本篇主要概述一下vfl2(video for linux 2). 一. V4L2框架: video for linux version 2虚拟视频驱动vivi.c分析:1.分配video_device2.设置3.注册:video_register_device vivi_init    vivi_create_instance        v4l2_device_register   // 不是主要, 只是用于初始