您的位置:首页 > 其它

字符设备实验之按键中断

2015-03-18 21:34 288 查看
在按键查询驱动上进行修改,主要是open,release函数里关于中断的注册和释放的处理,使用一个等待队列button_waitq将中断处理和read处理关联起来。

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/init.h>

#include <linux/fs.h>

#include <linux/interrupt.h>

#include <linux/irq.h>

#include <linux/sched.h>

#include <linux/pm.h>

#include <linux/slab.h>

#include <linux/sysctl.h>

#include <linux/proc_fs.h>

#include <linux/delay.h>

#include <linux/platform_device.h>

#include <linux/input.h>

#include <linux/gpio_keys.h>

#include <linux/workqueue.h>

#include <linux/gpio.h>

#include <linux/cdev.h>

#include <linux/device.h>

#include <linux/poll.h>

#include <asm/io.h>

#include <asm/irq.h>

#include <asm/uaccess.h>

#include <mach/map.h>

#include <mach/regs-clock.h>

#include <mach/regs-mem.h>

#include <mach/gpio.h>

#include <mach/gpio-smdkc110.h>

#include <mach/regs-gpio.h>

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

ioremap(),iounmap()

class_create(),class_destroy()

class_device_create(),class_device_unregister()

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

static dev_t devno;

static struct cdev *pCdev;

static struct class *thirddrv_class;

static struct device *thirddrv_class_dev;

#define DEVICE_NAME "third_drv"

int major,minor;

volatile unsigned long *gpgcon;

volatile unsigned long *gpgdat;

static DECLARE_WAIT_QUEUE_HEAD(button_waitq);

/* 中断事件标志, 中断服务程序将它置1,third_drv_read将它清0 */

static volatile int ev_press = 0;

struct pin_desc{

unsigned int pin;

unsigned int key_val;

};

/* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */

/* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */

static unsigned char key_val;

struct pin_desc pins_desc[4] = {

{S5PV210_GPH0(0), 0x01},

{S5PV210_GPH0(1), 0x02},

{S5PV210_GPH0(2), 0x03},

{S5PV210_GPH0(3), 0x04},

};

/*

* 确定按键值

*/

static irqreturn_t third_drv_irq(int irq, void *dev_id)

{

struct pin_desc * pindesc = (struct pin_desc *)dev_id;

unsigned int pinval;

pinval = gpio_get_value(pindesc->pin);

if (pinval)

{

/* 松开 */

key_val = 0x80 | pindesc->key_val;

}

else

{

/* 按下 */

key_val = pindesc->key_val;

}

ev_press = 1; /* 表示中断发生了 */

wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */

return IRQ_RETVAL(IRQ_HANDLED);

}

static int third_drv_open(struct inode *inode, struct file *file)

{

//printk("do third_drv_open \n");

/*

* K1,K2,K3,K4对应GPH0,GPH1,GPH2,GPH3

*/

/* 配置K1,K2,K3,K4为输入引脚 */

request_irq(IRQ_EINT(0), third_drv_irq, IRQ_TYPE_EDGE_BOTH, "S2", &pins_desc[0]);

request_irq(IRQ_EINT(1), third_drv_irq, IRQ_TYPE_EDGE_BOTH, "S3", &pins_desc[1]);

request_irq(IRQ_EINT(2), third_drv_irq, IRQ_TYPE_EDGE_BOTH, "S4", &pins_desc[2]);

request_irq(IRQ_EINT(3), third_drv_irq, IRQ_TYPE_EDGE_BOTH, "S5", &pins_desc[3]);

return 0;

}

static int third_drv_release(struct inode *inode, struct file *file)

{

//printk("do third_drv_release \n");

free_irq(IRQ_EINT(0), &pins_desc[0]);

free_irq(IRQ_EINT(1), &pins_desc[1]);

free_irq(IRQ_EINT(2), &pins_desc[2]);

free_irq(IRQ_EINT(3), &pins_desc[3]);

return 0;

}

static int third_drv_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)

{

if (count != 1)

return -EINVAL;

/* 如果没有按键动作, 休眠 */

wait_event_interruptible(button_waitq, ev_press);

/* 如果有按键动作, 返回键值 */

copy_to_user(buff, &key_val, 1);

ev_press = 0;

return 1;

}

static ssize_t third_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)

{

//printk("do third_drv_write \n");

return 0;

}

static struct file_operations third_drv_fops =

{

.owner = THIS_MODULE, /* 这是一个宏,指向编译模块时自动创建的__this_module 变量*/

.open = third_drv_open,

.release = third_drv_release,

.read = third_drv_read,

.write = third_drv_write,

//.poll = third_drv_poll,

};

static int __init third_drv_init(void)

{

//major = register_chrdev(0, DEVICE_NAME, &third_drv_fops);

int ret;

//使用udev自动生成设备文件,并分配设备号

pCdev = cdev_alloc();

if (!pCdev) {

printk(KERN_WARNING "cdev_alloc failed\n");

//goto out;

}

pCdev->owner = THIS_MODULE;

cdev_init(pCdev, &third_drv_fops);

ret = alloc_chrdev_region(&devno, 5, 1, "buttons");

if(ret){

printk(KERN_ERR "alloc char device region faild!\n");

//return ret;

}

major = MAJOR(devno);

minor = MINOR(devno);

ret = cdev_add(pCdev, devno, 1); //cat /proc/devices可以查看到多了一个buttons设备

if(ret){

printk(KERN_ERR "add char device faild!\n");

//goto add_error;

}

#if 1

thirddrv_class = class_create(THIS_MODULE, "buttonsClass");//ls /sys/class/buttonsClass/可以查看到多了一个buttonsClass类

if(IS_ERR(thirddrv_class)){

printk(KERN_ERR "create class error!\n");

}

//ls /sys/class/buttonsClass/buttons5/可以查看到多了一个buttons5设备

thirddrv_class_dev = device_create(thirddrv_class, NULL, devno/*MKDEV(major, 0)*/, NULL, "buttons%d", MINOR(devno)); /* /dev/buttons */

if(IS_ERR(thirddrv_class_dev)){

printk(KERN_ERR "create buttons device error!\n");

}

#endif

printk("third_drv_init \n");

printk("major = %d,minor = %d \n", major,minor);

gpgcon = (volatile unsigned long *)ioremap(0xE0200C00, 16);

gpgdat = gpgcon + 1;

return 0;

}

static void __exit third_drv_exit(void)

{

//unregister_chrdev(major, DEVICE_NAME);

#if 1

device_destroy(thirddrv_class,devno);

class_destroy(thirddrv_class);

#endif

cdev_del(pCdev);

unregister_chrdev_region(devno, 1);

iounmap(gpgcon);

printk("third_drv_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>

/* firstdrvtest on

* firstdrvtest off

*/

int main(int argc, char **argv)

{

int fd;

int cnt = 0;

unsigned char key_vals;

fd = open("/dev/buttons5", O_RDWR);

if (fd < 0)

{

printf("can't open!\n");

return 0;

}

while (1)

{

read(fd, &key_vals, 1);

printf("%04d key pressed: 0x%X\n", cnt++, key_vals);

//sleep(5);

}

return 0;

}

运行测试程序后能看到设备注册了4个中断,名字为S2,S3,S4,S5

使用中断方式能极大减少资源消耗
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: