smart210驱动(7)keys

keys.c

/*
* linux-3.10.27
* arm-linux-gcc-4.5.1
*
* @ keys driver
*/

#include <linux/module.h>
#include <linux/init.h>   /* module_init, ... */
#include <linux/kernel.h> /* everything */

#include <linux/cdev.h>   /* cdev_init, ... */
#include <linux/fs.h>     /* file_operations,  */
#include <linux/device.h>  /* class_create,... */
#include <linux/platform_device.h>
#include <linux/slab.h>   /* kmalloc, ... */
#include <asm/io.h>       /* ioremap,... */

#include <linux/uaccess.h>   /* copy_from_user, ... */

#include <linux/irq.h>      /* IRQ_EINT(x), ... */
#include <linux/gpio.h>
#include <linux/interrupt.h>  /* irq_request(),IRQF_xxx, ... */

#include <linux/wait.h>
#include <linux/sched.h>

#include <linux/timer.h>

#define DEF_DEVICE_NAME		"mykeys"
struct priv_data {
	char *name ;
	int major ;

	dev_t dev;
	struct cdev *cdev;
	struct class *class;
};

/*
* GPIO OF KEY FOR SMART210
*  K1  - GPH2-0  - EXINT16
*  K2  - GPH2-1  - EXINT17
*  K3  - GPH2-2  - EXINT18
*  K4  - GPH2-3  - EXINT19
*  K5  - GPH3-0  - EXINT24 
*  K6  - GPH3-1  - EXINT25
*  K7  - GPH3-2  - EXINT26
*  K8  - GPH3-3  - EXINT27
*
*  LOW MEANS PRESSED
*
*/

struct key_dev {
	char *name;
	unsigned gpio;
	int irq;
	unsigned int flags;
	int val;
};


static struct priv_data *priv_data;

#define IRQF_TRIGGER_BOTH_EDGE		IRQF_TRIGGER_FALLING + IRQF_TRIGGER_RISING

static struct key_dev keys[] = 
{
	{"K1", S5PV210_GPH2(0), IRQ_EINT(16),IRQF_TRIGGER_BOTH_EDGE, 10},
	{"K2", S5PV210_GPH2(1), IRQ_EINT(17),IRQF_TRIGGER_BOTH_EDGE, 20},
	{"K3", S5PV210_GPH2(2), IRQ_EINT(18),IRQF_TRIGGER_BOTH_EDGE, 30},
	{"K4", S5PV210_GPH2(3), IRQ_EINT(19),IRQF_TRIGGER_BOTH_EDGE, 40},
	{"K5", S5PV210_GPH3(0), IRQ_EINT(24),IRQF_TRIGGER_BOTH_EDGE, 50},
	{"K6", S5PV210_GPH3(1), IRQ_EINT(25),IRQF_TRIGGER_BOTH_EDGE, 60},
	{"K7", S5PV210_GPH3(2), IRQ_EINT(26),IRQF_TRIGGER_BOTH_EDGE, 70},
	{"K8", S5PV210_GPH3(3), IRQ_EINT(27),IRQF_TRIGGER_BOTH_EDGE, 80},		
};

static DECLARE_WAIT_QUEUE_HEAD(keys_waitq);
static int pressed = 0;
static int key_val = 0;

static struct timer_list mytimer;
static struct key_dev *cur_key = NULL;

void mytimer_callback(unsigned long data)
{	
	if(!cur_key)
		return;
	
	key_val = cur_key->val + gpio_get_value(cur_key->gpio);
	pressed = 1;
	wake_up_interruptible(&keys_waitq);
}
irqreturn_t keys_handler(int irq, void *dev_id)
{
	cur_key = (struct key_dev *)dev_id;
	//pr_info("%s pressed.\n", key->name);

	mod_timer(&mytimer, jiffies + HZ / 50);

	return IRQC_IS_HARDIRQ;
}

static int keys_open (struct inode *inode, struct file *file)
{
	pr_info("%s called .\n", __func__);
	
	return 0;
}

static int keys_close (struct inode *inode, struct file *file)
{
	pr_info("%s called .\n", __func__);	
	
	return 0;
}

static ssize_t keys_read (struct file *file, char __user *usrbuf, size_t len,
	loff_t *offset)
{
	wait_event_interruptible(keys_waitq, pressed);

	if(copy_to_user(usrbuf, &key_val, 1)){
		return -EFAULT;
	}

	/* clear the flag */
	pressed = 0;   
	return 0;
}

const struct file_operations fops = 
{
	.owner  = THIS_MODULE,
	.open = keys_open,
	.release = keys_close,
	.read = keys_read,
};

static int keys_init(void)
{
	int ret = 0, i = 0;
	pr_info("%s called .\n", __func__);

	priv_data = kmalloc(sizeof(*priv_data), GFP_KERNEL);
	if(!priv_data){
		pr_err("no mem.\n");
		return -ENOMEM;
	}

	priv_data->name = DEF_DEVICE_NAME;
	priv_data->major = 0;

	if(priv_data->major){
		priv_data->dev = MKDEV(priv_data->major, 0);
		ret = register_chrdev_region(priv_data->dev, 1, priv_data->name );
	}
	else
	{
		ret = alloc_chrdev_region(&priv_data->dev, 1, 1, priv_data->name );
		priv_data->major = MAJOR(priv_data->dev);
	}

	if(ret < 0){
		pr_err("register chrdev err.\n");
		kfree(priv_data);
		return -EFAULT;
	}

	/* add cdev */
	priv_data->cdev = cdev_alloc();
	if(!priv_data->cdev){
		pr_err("cdev alloc err.\n");
		goto cdev_err;
	}
	cdev_init(priv_data->cdev, &fops);
	priv_data->cdev->ops = &fops;
	priv_data->cdev->owner = THIS_MODULE;
	cdev_add(priv_data->cdev, priv_data->dev, 1);

	/* add device */
	priv_data->class = class_create(THIS_MODULE, priv_data->name);
	if(!priv_data->class){
		pr_err("class create err.\n");
		goto cls_err;
	}

	device_create(priv_data->class, NULL, priv_data->dev, NULL, priv_data->name);

	for(i = 0; i < ARRAY_SIZE(keys); i++){
		if(request_irq(keys[i].irq, keys_handler, keys[i].flags,
			keys[i].name, &keys[i]))
			break;
	}

	init_timer(&mytimer);
	mytimer.function = mytimer_callback;
	add_timer(&mytimer);	
	
	return 0;
cls_err:
	cdev_del(priv_data->cdev);

cdev_err:
	unregister_chrdev_region(priv_data->dev, 1);
	kfree(priv_data);
	return -EFAULT;
}

static void keys_exit(void)
{
	int i = 0;
	pr_info("%s called .\n", __func__);

	del_timer(&mytimer);

	for(i = 0; i < ARRAY_SIZE(keys); i++)
	{
		free_irq(keys[i].irq, &keys[i]);
	}

	device_destroy(priv_data->class, priv_data->dev);
	class_destroy(priv_data->class);

	cdev_del(priv_data->cdev);
	unregister_chrdev_region(priv_data->dev, 1);
	kfree(priv_data);
}

module_init(keys_init);
module_exit(keys_exit);
MODULE_LICENSE("GPL");

测试程序如下:

keys_test.c

#include <stdio.h>
#include <fcntl.h>

int main(void){
	int fd = -1;
	unsigned char key_val = 0;

	fd = open("/dev/mykeys", O_RDWR);
	if(fd < 0){
		printf("open err ! \n");
		return -1;
	}

	while(1){
		read(fd, &key_val, 1);
		printf("key_val : %d \n", key_val);
	}

	return 0;
}

编译测试程序

#!/bin/bash

export PATH=$PATH:/home/flinn/tools/4.5.1/bin
arm-linux-gcc -o keys_test keys_test.c

sudo cp keys_test /home/flinn/smart210-SDK/fs/drv/

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值