我是靠谱客的博主 俊逸黄蜂,最近开发中收集的这篇文章主要介绍linux按键驱动和异步通知,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

一:驱动
/button_drv.c*******/

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/uaccess.h>
#include <linux/delay.h>

/* 0x01 OUT //0x00 IN*/
/* 0x01 HIGH //0x00 LOW*/

//GPIO2_0 key
#define GPIO2_0_DIR 0x12142400
#define GPIO2_0_DATA 0x12142004

volatile unsigned int *pGPIO2_0_DIR;
volatile unsigned int *pGPIO2_0_DATA;

#define BUFFER_SIZE 50
char kbuf[BUFFER_SIZE];

#define on 1
#define off 0

/*

  • 0 - disable irq
  • 1 - rising edge triggered
  • 2 - falling edge triggered
  • 3 - rising and falling edge triggered
  • 4 - high level triggered
  • 8 - low level triggered
    */

struct hi3559av100_button
{
int dev_major ;
struct class *cls;
struct device *dev;
int value;
};

struct hi3559av100_button *button_dev;

static unsigned int gpio_chip_num = 2;
module_param(gpio_chip_num, uint, S_IRUGO);
MODULE_PARM_DESC(gpio_chip_num, “gpio chip num”);

static unsigned int gpio_offset_num = 0;
module_param(gpio_offset_num, uint, S_IRUGO);
MODULE_PARM_DESC(gpio_offset_num, “gpio offset num”);

static unsigned int gpio_dir = 0;
module_param(gpio_dir, uint, S_IRUGO);
MODULE_PARM_DESC(gpio_dir, “gpio dir”);

static unsigned int gpio_out_val = 1;
module_param(gpio_out_val, uint, S_IRUGO);
MODULE_PARM_DESC(gpio_out_val, “gpio out val”);

static unsigned int gpio_irq_type = 0;
module_param(gpio_irq_type, uint, S_IRUGO);
MODULE_PARM_DESC(gpio_irq_type, “gpio irq type”);

const int button_devid[2] = {1, 2};//if two num of button
static struct fasync_struct *button_async;

/*
button don’t support long press,only support short press
button init status is high
when press button ,vla is from high to low
only support fall irq
*/

//void button_handler(unsigned long data)
static irqreturn_t button_dev_isr(int irq, void *dev_id)
{
printk("%sn", FUNCTION);

int button_num = *((int *)dev_id);
int button_val[2] = {1,1};
//init status is up and val is high
static unsigned long button_val_backup[2]={1,1};
//init status is up and val is high
unsigned int gpio_num=0;
gpio_num = gpio_chip_num * 8 + gpio_offset_num;
button_val[0] = gpio_get_value(gpio_num);
// interrupt happen ,read
button once
switch(button_num)
{
case 1:
if(button_val[0] != button_val_backup[0])
// old status and new status is different
{
button_val_backup[0] = button_val[0];
// renew current buttton status
mdelay(10);
//
button_val[0] = gpio_get_value(gpio_num);
//read buttton once again
if((button_val[0] == button_val_backup[0]) && (button_val_backup[0] == 0))//new status and old status is same , and old status is low,button is be pressed
{
printk("button[0] has be pressed
value: %dn", button_val[0]);
kill_fasync(&button_async, SIGIO, POLL_IN);
}
else if((button_val[0] == 1) && (button_val_backup[0] == 1))//new status and old status is same,and old status is low,button is be up
{
printk("button[0] has be up value: %dn", button_val[0]);
button_val[0] = 1;
//clean up
button_val_backup[0] = 1;
//clean up
}
}
break;
case 2:
break;
default :
break;
}

return IRQ_HANDLED;
}

//DECLARE_TASKLET(button_tasklet,button_handler,0);

//static irqreturn_t button_dev_isr(int irq, void *dev_id)
//{
// printk("%sn", FUNCTION);

// tasklet_schedule(&button_tasklet);
// return IRQ_HANDLED;
//}

static int button_drv_open(struct inode *inode, struct file *filp)
{
printk("%sn", FUNCTION);

unsigned int gpio_num;
unsigned int irq_num;
unsigned int irqflags = 0;
irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
irqflags |= IRQF_SHARED;
gpio_num = gpio_chip_num * 8 + gpio_offset_num;
if (gpio_request(gpio_num, NULL)) {
pr_err("[%s %d]gpio_request fail! gpio_num=%d n", __func__, __LINE__, gpio_num);
return -1;
}
if (gpio_direction_input(gpio_num)) {
pr_err("[%s %d]gpio_direction_input fail!n",__func__, __LINE__);
gpio_free(gpio_num);
return -1;
}
irq_num = gpio_to_irq(gpio_num);
if (request_irq(irq_num, button_dev_isr, irqflags,"gpio_dev_test", &button_devid[0])) {
gpio_free(gpio_num);
return -1;
}
//if (request_irq(irq_num, button_dev_isr, irqflags,"gpio_dev_test", &button_devid[1])) {
//
gpio_free(gpio_num);
//
return -1;
// }
return 0;

}

static int button_drv_close(struct inode *inode, struct file *filp)
{
printk("%sn", FUNCTION);

unsigned int gpio_num = 0;
gpio_num = gpio_chip_num * 8 + gpio_offset_num;
free_irq(gpio_to_irq(gpio_num), &button_devid[0]);
//free_irq(gpio_to_irq(gpio_num), &button_devid[1]);
gpio_free(gpio_num);
return 0;

}

static ssize_t button_drv_read(struct file *filp, char __user *ubuf, size_t count, loff_t *ppos)
{
printk("%sn", FUNCTION);
int ret = -1;
unsigned int gpio_num=0;
unsigned int val=0;

gpio_num = gpio_chip_num * 8 + gpio_offset_num;
memset(kbuf, 0, sizeof(kbuf));
val = gpio_get_value(gpio_num);
kbuf[0] = val;
printk("%s
kbuf:%dn", __FUNCTION__,kbuf[0]);
ret = copy_to_user(ubuf, kbuf, count);
if (ret) {
printk(KERN_ERR "copy_to_user failn");
return -EINVAL;
} else if(ret == 0) {
printk(KERN_INFO "copy_to_user successn");
}
return ret;

}

static ssize_t button_drv_write(struct file *file, const char __user *ubuf,size_t count, loff_t *ppos)
{
int ret = -1;
printk("%sn", FUNCTION);
memset(kbuf, 0, sizeof(kbuf));

ret = copy_from_user(kbuf, ubuf, count);
if(ret) {
printk(KERN_ERR "copy_from_user failn");
return -EINVAL;
} else if(ret == 0) {
printk(KERN_INFO "copy_from_user successn");
}

//method1
if (!strcmp(kbuf, “1”)) {
printk(“method1 %s kbuf:%sn”, FUNCTION,kbuf);
} else if (!strcmp(kbuf, “0”)) {
printk(“method2 %s kbuf:%sn”, FUNCTION,kbuf);
} else {
printk(KERN_INFO “method1 unknow cmdn”);
}

//method2
if (!strcmp(kbuf, “on”)) {
printk(“method2 %s kbuf:%sn”, FUNCTION,kbuf);
} else if (!strcmp(kbuf, “off”)) {
printk(“method2 %s kbuf:%sn”, FUNCTION,kbuf);
} else {
printk(KERN_INFO “method2 unknow cmdn”);
}
return ret;
}

static long button_drv_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
switch(cmd)
{
case on :
//button on
printk("%s button onn",FUNCTION);
//*pGPIO2_0_DATA |= (0x1<<0);
break;

	case off :
//button off
printk("%s button offn",__FUNCTION__);
//*pGPIO2_0_DATA &= ~(0x1<<0);
break;
default :
printk("%s unkown cmdn",__FUNCTION__);
return -EINVAL;
}
return 0;

}

static int button_drv_fasync (int fd, struct file *filp, int fasyncon)
{
printk("%sn", FUNCTION);
return fasync_helper (fd, filp, fasyncon, &button_async);
}

const struct file_operations button_fops = {
.open = button_drv_open,
.read = button_drv_read,
.write = button_drv_write,
.release = button_drv_close,
.unlocked_ioctl = button_drv_ioctl,
.fasync = button_drv_fasync,
};

static int __init button_drv_init(void)
{
int ret;
printk("%sn", FUNCTION);

button_dev = kzalloc(sizeof(struct hi3559av100_button), GFP_KERNEL);
if(button_dev == NULL) {
printk(KERN_ERR,"kzalloc errorn");
return -ENOMEM;
}
button_dev->dev_major = 0;
button_dev->dev_major = register_chrdev(button_dev->dev_major, "button",
&button_fops);
if(button_dev->dev_major < 0) {
printk("register_chrdev errorn");
ret = -EINVAL;
goto err_free;
}
button_dev->cls = class_create(THIS_MODULE,"button");
if(IS_ERR(button_dev->cls)) {
printk("class_create errorn");
ret = PTR_ERR(button_dev->cls);
goto err_unregister;
}
button_dev->dev = device_create(button_dev->cls, NULL,MKDEV(button_dev->dev_major, 0), NULL, "button");
if(IS_ERR(button_dev->dev)) {
printk("device_create errorn");
ret = PTR_ERR(button_dev->dev);
goto err_class_destroy;
}
return 0;

err_class_destroy:
class_destroy(button_dev->cls);

err_unregister:
unregister_chrdev(button_dev->dev_major, “button”);

err_free:
kfree(button_dev);
return ret;
}

static void __exit button_drv_exit(void)
{
printk("%sn", FUNCTION);

device_destroy(button_dev->cls, MKDEV(button_dev->dev_major, 0));
class_destroy(button_dev->cls);
unregister_chrdev(button_dev->dev_major, "button");
kfree(button_dev);

}

module_init(button_drv_init);
module_exit(button_drv_exit);
MODULE_LICENSE(“GPL”);

二:应用
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <signal.h>

int fd0 = -1;
int fd1 = -1;
int fd2 = -1;

void button_signal_fun(int signum)
{
unsigned char key_val = 0;
static int led_index = 0;
read(fd2, &key_val, 1);
printf(“app reas key_val: %dn”, key_val);

if(!key_val)
{
led_index ++;
if(led_index > 2) {
led_index = 0;
}
}
switch(led_index)
{
case 0 :
write(fd0,"on",2);
write(fd1,"off",3);
break;
case 1 :
write(fd0,"off",3);
write(fd1,"on",2);
break;
case 2 :
write(fd0,"on",2);
write(fd1,"on",2);
break;
default:
break;
}

}

int main()
{

	char *filename0 = NULL;
char *filename1 = NULL;
char *filename2 = NULL;
char buf[100]={0};
int ret = -1;
int Oflags = 0;
filename0 = "/dev/led_green";
filename1 = "/dev/led_red";
filename2 = "/dev/button";
//led0
fd0 = open(filename0, O_RDWR);
if(fd0 < 0) {
printf("app open led_green failn");
return 0;
} else {
printf("app open led_green successrn");
}
//led1
fd1 = open(filename1, O_RDWR);
if(fd1 < 0) {
printf("app open led_red failn");
return 0;
} else {
printf("app open led_red successrn");
}
//button
fd2 = open(filename2, O_RDWR);
if (fd2 < 0) {
printf("app open %s failn", filename2);
return 0;
} else {
printf("app open
%s successrn",filename2);
}
signal(SIGIO, button_signal_fun);
fcntl(fd2, F_SETOWN, getpid());
Oflags = fcntl(fd2, F_GETFL);
fcntl(fd2, F_SETFL, Oflags | FASYNC);
write(fd0,"on",2);
//led0 on
while(1)
{
sleep(1);
}
close(fd0);
close(fd1);
close(fd2);
return 0;

}

最后

以上就是俊逸黄蜂为你收集整理的linux按键驱动和异步通知的全部内容,希望文章能够帮你解决linux按键驱动和异步通知所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(92)

评论列表共有 0 条评论

立即
投稿
返回
顶部