#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/gpio.h>
//#include <mach/platform.h>//kernel 3.4
//#include <mach/gpio_desc.h>
//#include <mach/gpio.h>
//gpio
enum {
PAD_GPIO_A = (0 * 32),
PAD_GPIO_B = (1 * 32),
PAD_GPIO_C = (2 * 32),
PAD_GPIO_D = (3 * 32),
PAD_GPIO_E = (4 * 32),
};
#define KEY_GPIO (PAD_GPIO_B + 31) //GPB31为触发终端源
#define KEY_GPIO_IRQ gpio_to_irq(KEY_GPIO) //根据GPIO编号获取对应的引脚的中断编号
#define DEVICE_NAME "key_irq"
static int major;
static int minor;
struct cdev *key_irq; /* cdev 数据结构 */
struct file_operations key_irq_fops;
static dev_t devno; /* 设备编号 */
static struct class *key_irq_class;
char const irq_types[5] = {
IRQ_TYPE_EDGE_RISING,
IRQ_TYPE_EDGE_FALLING,
IRQ_TYPE_EDGE_BOTH,
IRQ_TYPE_LEVEL_HIGH,
IRQ_TYPE_LEVEL_LOW
};
static irqreturn_t key_irq_irq_handler(unsigned int irq, void *dev_id) //触发中断设置标志位?
{
printk(KERN_ERR"*************************************\n");
printk(KERN_ERR"KEY_IRQ TEST\n");
printk(KERN_ERR"*************************************\n");
return IRQ_HANDLED;
}
static int __init key_irq_init(void)
{
int ret;
/*申请GPIO*/
gpio_free(KEY_GPIO); /*首先释放GPIO*/
ret= gpio_request_one(KEY_GPIO, GPIOF_IN, "KEY IRQ"); /* 申请 IO ,为输入*/
if(ret < 0) {
printk(KERN_ERR"Failed to request GPIO for KEY\n");
}
gpio_direction_input(KEY_GPIO);/* 设置 GPIO 为输入 */
/*申请GPB31对应的中断*/
if(request_irq(KEY_GPIO_IRQ, key_irq_irq_handler, IRQF_TRIGGER_RISING, "key_irqirq", NULL) )
{/* 申请中断 */
printk(KERN_ERR": Can't get IRQ: %d!\n", KEY_GPIO_IRQ);
}
irq_set_irq_type(KEY_GPIO_IRQ,irq_types[0]); /*按键上升沿出发中断*/
disable_irq(KEY_GPIO_IRQ);
enable_irq(KEY_GPIO_IRQ);
ret= alloc_chrdev_region(&devno, minor, 1, DEVICE_NAME); /* 从系统获取主设备号 */
major= MAJOR(devno);
if(ret < 0) {
printk(KERN_ERR"cannot get major %d \n", major);
return-1;
}
key_irq= cdev_alloc(); /* 分配 key_irq 结构 */
if(key_irq != NULL) {
cdev_init(key_irq,&key_irq_fops); /* 初始化 key_irq 结构 */
key_irq->owner= THIS_MODULE;
if(cdev_add(key_irq, devno, 1) != 0) { /* 增加 key_irq 到系统中 */
printk(KERN_ERR"add cdev error!\n");
goto error;
}
}
else{
printk(KERN_ERR"cdev_alloc error!\n");
return-1;
}
key_irq_class= class_create(THIS_MODULE, "key_irq_class");//创建sys/class/key_irq_class
if(IS_ERR(key_irq_class)) {
printk(KERN_INFO"create class error\n");
return-1;
}
device_create(key_irq_class,NULL, devno, NULL, DEVICE_NAME);
printk("Initcompleted!\n");
return 0;
error:
unregister_chrdev_region(devno,1); /* 释放已经获得的设备号 */
return ret;
}
static void __exit key_irq_exit(void)
{
gpio_free(KEY_GPIO); /*释放为按键KEY申请的GPIO资源*/
disable_irq(KEY_GPIO_IRQ);
free_irq(KEY_GPIO_IRQ,NULL);
cdev_del(key_irq);/* 移除字符设备 */
unregister_chrdev_region(devno,1); /* 释放设备号 */
device_destroy(key_irq_class,devno);
class_destroy(key_irq_class);
printk(KERN_INFO"Exit completed!\n");
}
module_init(key_irq_init);
module_exit(key_irq_exit);
MODULE_LICENSE("GPL");
Makefile
obj-m := gpio.o
KDIR := /home/jiancao/linux-4.4/linux ....内核路径
default:
make -C $(KDIR) M=$(PWD) modules
clean:
make -C $(KDIR) M=$(PWD) modules clean
rm -rf modules.order