linux按键驱动模块(中断方式) 程序和调试总结

来源:互联网 发布:淘宝卖家4.6 编辑:程序博客网 时间:2024/05/17 02:19

内核驱动模块程序

#include <linux/module.h>

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




static struct class *third_drv_class;
struct class_device *third_drv_class_dev;     








struct pin_desc{
unsigned int pin;
unsigned int key_value;
};




struct pin_desc  pins_desc[4]={
{S3C2410_GPG0,0x01},
{S3C2410_GPG3,0x02},
{S3C2410_GPG5,0x03},
{S3C2410_GPG6,0x04},
};










//定义一个按键值
unsigned char vkey_value;


//定义是否处理完中断
unsigned char  ev_press;




//定义一个等待队列
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);










static irqreturn_t buttons_irq(int irq, void *dev_id)
{
struct pin_desc *pindesc = (struct pin_desc *)dev_id;


unsigned int vpin_value;


vpin_value = s3c2410_gpio_getpin(pindesc->pin);


if(vpin_value)
{
//按键释放
vkey_value= (pindesc->key_value)|0x80;

}
else
{
//按键按下
vkey_value= pindesc->key_value;
}

ev_press = 1; //表示中断发生了
wake_up_interruptible(&button_waitq);

//打印中断号码,16进制显示
//printk("irq = 0x%0x\n",irq);   


return IRQ_RETVAL(IRQ_HANDLED);    
}       
    
//---------------------------------
static int third_drv_open(struct inode *inode, struct file *file)
{
//注册中断函数到内核 GPG0 GPG3 GPG5 GPG6
request_irq(IRQ_EINT8, buttons_irq,IRQT_BOTHEDGE,"K1",&pins_desc[0]);
request_irq(IRQ_EINT11,buttons_irq,IRQT_BOTHEDGE,"K2",&pins_desc[1]);
request_irq(IRQ_EINT13,buttons_irq,IRQT_BOTHEDGE,"K3",&pins_desc[2]);
request_irq(IRQ_EINT14,buttons_irq,IRQT_BOTHEDGE,"K4",&pins_desc[3]);



printk("third_drv_open\n");
return 0;
}










static int third_drv_close(struct inode *inode, struct file *file)
{


free_irq(IRQ_EINT8, &pins_desc[0]);
free_irq(IRQ_EINT11,&pins_desc[1]);
free_irq(IRQ_EINT13,&pins_desc[2]);
free_irq(IRQ_EINT14,&pins_desc[3]);




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


}


static ssize_t third_drv_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
//读取一个字节,如果不是报错
if (count != 1)
return -EINVAL;




/* 如果没有按键动作, 休眠 */
wait_event_interruptible(button_waitq, ev_press);


copy_to_user(buf, &vkey_value, 1);




ev_press = 0; //清零
//----------------------------------
//printk("third_drv_open\n");
return 1;
}   




    








static struct file_operations third_drv_fops = {
    .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
    .open   =   third_drv_open,     
.read =third_drv_read, 
.release= third_drv_close,
};












int major;


static int third_drv_init(void)
{
major = register_chrdev(0,"thirddrv",&third_drv_fops);
third_drv_class = class_create(THIS_MODULE, "thirddrv");
  third_drv_class_dev = class_device_create(third_drv_class, NULL, MKDEV(major, 0), NULL, "buttons"); /* /dev/buttons */


printk("third_drv_init initial\n");


return 0;
}






static void third_drv_exit(void)
{
unregister_chrdev(major, "thirddrv");
class_device_unregister(third_drv_class_dev);
class_destroy(third_drv_class);


printk("third_drv_init exit\n");
}






module_init(third_drv_init);
module_exit(third_drv_exit);




MODULE_LICENSE("GPL");








测试应用程序


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














//测试开发板led开关
int main(int argc, char **argv)
{
int fd;
int vcnt;
unsigned char key_value;



fd = open("/dev/buttons",O_RDWR);
if(fd < 0)
{
printf("can't open device\n");
}


while(1)
{
read(fd,&key_value,1);


printf("key_value =0x%0x\n",key_value);   

}





return 0;


}




打开中断设备
exec 5</dev/buttons_irq


关闭中断设备
exec 5<&-


查看挂载内核模块
cat /proc/devices 


查看中断设备
cat /proc/interrupts 






0 0