tiny6410按键驱动(三)---中断发

驱动代码如下:

#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 <asm/io.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <mach/hardware.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>

#include <mach/map.h>
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>

#include <plat/gpio-cfg.h>
#include <mach/gpio-bank-n.h>
#include <mach/gpio-bank-l.h>

#include<linux/timer.h>

static unsigned button_major;
static dev_t button_id;  /*设备号*/

static struct cdev button_cdev;
static struct class *button_class;
static struct device *button_device;

static volatile char ev_press;
           

static DECLARE_WAIT_QUEUE_HEAD(button_waitq);  /*生成一个等待队列头wait_queue_head_t,名字为button_waitq*/


struct buttons_irq_decs{
                    int irq;
					char *name;

                   };
static struct buttons_irq_decs button_irqs[] = {
													{IRQ_EINT( 0),"K1"},
													{IRQ_EINT( 1),"K2"},
													{IRQ_EINT( 2),"K3"},
													{IRQ_EINT( 3),"K4"},

												  };

static irqreturn_t buttons_irq(int irq, void *dev_id)  	
{
struct buttons_irq_decs *irq_desc = (struct buttons_irq_decs*)dev_id ;
printk("%s\n" ,irq_desc->name);
ev_press = 1;
wake_up_interruptible(&button_waitq);/*唤醒等待队列button_waitq里睡眠的进程*/
return IRQ_HANDLED;
}

static int myButton_open(struct inode * inode, struct file * file)
{
//printk("%d" , ev_press);

int i;
char err;
for(i=0 ; i<sizeof(button_irqs)/sizeof(button_irqs[0]) ;i++)
		{
		
		err = request_irq(button_irqs[i].irq , &buttons_irq ,IRQ_TYPE_EDGE_BOTH ,button_irqs[i].name ,&button_irqs[i] );
			                                                   /*IRQ_TYPE_EDGE_BOTH表示双边沿触发,即按键按下和松开都会触发中断*/
		/*  request_irq()会自动把GPIO配置为中断引脚
	        request_irq()的第一个参数是硬件中断号,每种中断都对应一个硬件中断号
	             第二个参数是中断处理函数名,
	             第三个参数是中断触发的类型,也称为中断处理的属性,这个按键程序我们用的是双边沿触发,
	             第四个参数是出发中断的硬件名,可以随便取,cat /proc/interrupts中可以看到此名称
	             第五个参数是触发中断的硬件的相关信息*/
	   /*当发生中断时,IRQ_EINT( 0),&button_irqs[0]就会传进中断服务程序irqreturn_t buttons_irq(int irq, void *dev_id)*/
		  
		if(err)
			{
			 printk("button_irqs[i] request faild\n");
             continue;
		     }
		}
printk("myButton_open end\n");

return 0;
}

static int myButton_write(struct file *filp,const char __user *buf,size_t count,loff_t *f_pos)
{
return 0;

}

static int myButton_read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off)
{
if(bytes != 1)
   {
    printk("you can read just one char from the decive\n");
    return -1;
   }
printk("myButton_read start\n");

wait_event_interruptible(button_waitq ,ev_press);
/*当第二个参数不为0时,且button_waiq等待队列里的进程被唤醒,程序才会继续向下执行,
  否则把当前进程放入等待队列button_waitq,让其休眠。
  当发生中断时,在中断服务函数buttons_irq里会把ev_press置1,且唤醒等待队列button_waitq里休眠的进程(及当前进程)
  程序继续向下执行。
  可见当没有按键按下时,进程会在进入休眠。
*/

char value ;
value = readl(S3C64XX_GPNDAT)&(0xf);   /*GPN0~3对应于按键K1~K4*/

if(copy_to_user(userbuf, &value, bytes))    /*成功时返回0,失败时返回没有成功拷贝的字符个数*/
       {
        printk("copy_to_user error\n");
		return -1;
	   }
ev_press =0 ;
printk("myButton_read end\n");
return 0;
}

static int myButton_release(struct inode *inode, struct file *file)
{
int i;
for(i=0 ; i<sizeof(button_irqs)/sizeof(button_irqs[0]) ;i++)
	{
     free_irq(button_irqs[i].irq, &button_irqs[i]);
	}

printk("myButton_release\n");
return 0;

}

struct file_operations button_fiops=
{
.owner = THIS_MODULE,
.open  = myButton_open,
.write = myButton_write,
.read  = myButton_read,
.release = myButton_release,


};


static int myButton_init(void)
{
 
  if(button_major)
	{
     button_id = MKDEV(button_major,0);
	 register_chrdev_region(button_id, 2, "myButton_drv");
	}
    else
    	{
         alloc_chrdev_region(&button_id, 0, 2,"myButton_drv" );
		 button_major = MAJOR(button_id);
	    }
	cdev_init(&button_cdev, &button_fiops);
	cdev_add(&button_cdev, button_id, 2);       /*添加2个设备*/

	button_class = class_create(THIS_MODULE, "myButton");
	button_device = device_create(button_class, NULL, MKDEV(button_major , 0), NULL, "myButton0");  /*创建设备节点/dev/myButton0*/
	button_device = device_create(button_class, NULL, MKDEV(button_major , 1), NULL, "myButton1");  /*创建设备节点/dev/myButton1*/
  
    printk("myButton init succeed\n");
    return 0;
}
static void myButton_exit(void)
{
device_destroy(button_class, MKDEV(button_major , 0));
device_destroy(button_class, MKDEV(button_major , 1));
class_destroy(button_class);
cdev_del(&button_cdev);
unregister_chrdev_region(button_id, 2);

printk("myButton exit succeed\n");

}

module_init(myButton_init);
module_exit(myButton_exit);
MODULE_LICENSE("GPL");

Makefile文件如下:

obj-m := mybutton_drv3.o
KDIR :=/home/lijunliang/windows-files/linux-tiny6410
all :
	make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm
clean :
	rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.bak *.order

测试程序如下:

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



int main(void)
{
int fd;

char keyValue ; 

fd = open("/dev/myButton0",O_RDWR);
while(1)
	{
	   //read(fd ,userbuffer,bufferSize);
	   read(fd ,&keyValue ,1);
	   #if 0 
	   switch(userbuffer[0])
	   		{
              case 0xe: printf("K1 按下\n");
			             break;
			 
			  case 0xd: printf("K2 按下\n");
					     break;
						
			  case 0xb: printf("K3 按下\n");
					     break;	

			  case 0x7: printf("K4 按下\n");
					     break;		

			  default : break;

	   		 }
	  #endif
          
	    
	} 
//printf("%x\n",userbuffer0[0]);

return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值