中断编程5-作业 Level11day11

1-按键驱动之异步信号实验

1.1, 应用代码

//---------------key_test.c----------------------
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>

#define KEY_ENTER 28
#define EAGAIN 35

int fd;

struct key_value_dsc{
	int code;		//表示按键的类型:home, esc, Q, W, E, R, T...
	int date;		//表示按下还是抬起 1/0
};

struct key_value_dsc key_value;

void catch_signal(int signo)
{
	int ret;
	
	if(signo == SIGIO)
	{
		printf("__APP__:catch_signal\n");
		
		//可以直接去读数据, 一定可以读到数据
		ret = read(fd, &key_value, sizeof(struct key_value_dsc));
		
		if(ret < 0){
			perror("read:");
			exit(1);
		}
		
		if(key_value.code == KEY_ENTER)
		{
			if(key_value.date == 1)
			{
				printf("__APP__key enter pressed\n",key_value.date);
			}
			else if(key_value.date == 0) 
			{
				printf("__APP__key enter up\n",key_value.date);
			}
		}
	}
	
}

int main(int argc, char **argv)
{
	int ret, flag;
	char in_buf[128] = {0};
	
	fd = open("/dev/INTRRUPT KEY3",O_RDWR);

	if(fd < 0){
		perror("open:");
		exit(1);
	}

	//1.设置信号处理方法
	signal(SIGIO, catch_signal);

	//2.将当前进程设置成SIGIO的属主进程
	fcntl(fd,F_SETOWN,getpid());

	//3. 将IO模式设置成异步模式
	flag = fcntl(fd,F_GETFL); 
	fcntl(fd,F_SETFL,flag | FASYNC);

	while(1)
	{
		printf("__APP__: wating\n");
		sleep(1);
	}
	
	close(fd);
	return 0;
}

1.2, 驱动代码

//--------key_drv.c--------------
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/input-event-codes.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <asm/io.h>


#define GPX1CON_ADDR 0x11000c20
#define GPX1_SIZE 8

//设计一个全局设备对象--描述按键信息
struct key_irq_str{
	int irqno;
	unsigned int dev_major;
	unsigned int dev_minor;
	struct class* pkey_class;	
	struct device* pkey_device;
	void* reg_virt_base;
	wait_queue_head_t wq;
	int key_state;	//表示是否有数据
	struct fasync_struct* fasync;
};
struct key_irq_str *pkey_irq_str;

//设计一个描述按键的数据的对象
struct key_value_dsc{
	int code;		//表示按键的类型:home, esc, Q, W, E, R, T...
	int date;		//表示按下还是抬起 1/0
};
struct key_value_dsc key3_value_dsc = {
	.code = 0,
	.date = 0,
};

int key_drv_fasync(int fd, struct file * filp, int on)
{
	//只需要调用一个函数,记录信号该发送给谁
	return fasync_helper(fd, filp, on, &pkey_irq_str->fasync);
}

irqreturn_t key_irq_handler(int irqno, void *devid)
{
	unsigned int GPX1DAT;
	
	printk("--------------%s------------------\n",__FUNCTION__);
	
	GPX1DAT = readl(pkey_irq_str->reg_virt_base + 4);
	
	if( GPX1DAT &= 0x1<<2 ){
		printk("__KERN__:Enter up\n");	 
		key3_value_dsc.code = KEY_ENTER;
		key3_value_dsc.date = 0;
	}
	else{
		printk("__KERN__:Enter down\n");
		key3_value_dsc.code = KEY_ENTER;
		key3_value_dsc.date = 1;
	}

	//表示有数据,需要唤醒整个等待队列
	wake_up_interruptible(&(pkey_irq_str->wq));
	
	//同时设置标志位
	pkey_irq_str->key_state = 1;
	
	//发送信号
	kill_fasync(&(pkey_irq_str->fasync), SIGIO, POLLIN);
	
	return IRQ_HANDLED;
}

int key_drv_open (struct inode* inode, struct file *filp){
	printk("__KERN__:open\n");
	return 0;
}

ssize_t key_drv_read (struct file *filp, char __user *buf, size_t count, loff_t *fpos){
	int ret;

	//兼容阻塞和非阻塞模式。如果当前是非阻塞模式,并且没有数据,立马返回一个出错码
	if(filp->f_flags & O_NONBLOCK && !pkey_irq_str->key_state)
	{
		return EAGAIN;
	}
	
	wait_event_interruptible(pkey_irq_str->wq, pkey_irq_str->key_state);

	//表示有数据
	ret = copy_to_user(buf, &key3_value_dsc, count);

	if(ret == 0)
	{
		//printk("__KERN__:read\n");
	}
	else
	{
		printk("__KERN__:Err to read\n");
	}
	
	key3_value_dsc.code = 0;
	key3_value_dsc.date = 0;

	pkey_irq_str->key_state = 0;
	
	return count;
}

ssize_t key_drv_write (struct file *filp, const char __user *buf, size_t count, loff_t *fpos){
	

	return 0;
}


int key_drv_release (struct inode *inod, struct file *filp){
	printk("__KERN__:release\n");
	return 0;
}


const struct file_operations key_drv_fops = {
	.open = key_drv_open,
	.read = key_drv_read,
	.write = key_drv_write,
	.release = key_drv_release,
	.fasync = key_drv_fasync,
};

int get_irqno_from_node(void)
{
	//获取到设备树中的节点

	struct device_node *np = of_find_node_by_path("/key_int_node");
	
	if(np){
		printk("find node ok\n");
	}
	else{
		printk("find node failed\n");
	}
	//通过节点去获取到中断号码
	pkey_irq_str->irqno = irq_of_parse_and_map(np,0);
	
	printk("irqno = %d\n",pkey_irq_str->irqno);

	return pkey_irq_str->irqno;
}

static int __init key_drv_init(void)
{
	
	int ret;
	
	//1.设定一个全局的设备对象
	pkey_irq_str = kzalloc(sizeof(struct key_irq_str), 1);

	//2.申请主设备号,设置次设备号
	pkey_irq_str->dev_major = register_chrdev(0, "key_drv_test", &key_drv_fops);

	pkey_irq_str->dev_minor = 0;

	//3.创建设备节点
	pkey_irq_str->pkey_class = class_create(THIS_MODULE, "key_interrupt_dev");

	pkey_irq_str->pkey_device = device_create(pkey_irq_str->pkey_class,NULL,MKDEV(pkey_irq_str->dev_major, pkey_irq_str->dev_minor),NULL,"INTRRUPT KEY%d",3);
	
	//4.硬件初始化--地址映射或中断申请
	
	ret = get_irqno_from_node();

	ret = request_irq(pkey_irq_str->irqno, key_irq_handler, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, "IRQ_EINT10", NULL);

	if(ret != 0)
	{
		printk("request_irq ERROR!\n");
		return ret;
	}

	pkey_irq_str->reg_virt_base = ioremap(GPX1CON_ADDR, GPX1_SIZE);

	//5. 初始化等待队列头
	init_waitqueue_head(&(pkey_irq_str->wq));
	pkey_irq_str->key_state = 0;

	
	
	return 0;
}

static void __exit key_drv_exit(void)
{
	iounmap(pkey_irq_str->reg_virt_base);
	free_irq(pkey_irq_str->irqno,NULL);
	device_destroy(pkey_irq_str->pkey_class, MKDEV(pkey_irq_str->dev_major, pkey_irq_str->dev_minor));
	class_destroy(pkey_irq_str->pkey_class);
	unregister_chrdev(pkey_irq_str->dev_major, "key_drv_test");
	kfree(pkey_irq_str);
}


module_init(key_drv_init);
module_exit(key_drv_exit);
MODULE_LICENSE("GPL");

1.3, Makefie代码

ROOTFS_DIR = /home/linux/Level11

APP_NAME = key_test

CROSS_COMPILE = arm-none-linux-gnueabi-
CC = $(CROSS_COMPILE)gcc

ifeq ($(KERNELRELEASE), )

KERNEL_DIR = /home/linux/Level10/day6/linux-5.4.79
CUR_DIR = $(shell pwd)

all :
		make -C  $(KERNEL_DIR) M=$(CUR_DIR) modules -j6 ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-
		$(CC) $(APP_NAME).c -o $(APP_NAME)

clean :
		make -C  $(KERNEL_DIR) M=$(CUR_DIR) clean
		rm $(APP_NAME) ./1/$(APP_NAME)
		clear

install:
		cp -raf  *.ko  $(APP_NAME)   ./1/
		
else
obj-m += key_drv.o

endif

1.4, 效果展示

[root@farsight ]# ./key_test
[  242.155750] __KERN__:open
__APP__: wating
__APP__: wating
__APP__: wating
__APP__: wating
__APP__: wating
__APP__: wating
__APP__: wating
[  249.189787] --------------key_irq_handler------------------
[  249.193888] __KERN__:Enter down
__APP__: wating
__APP__:catch_signal
__APP__key enter pressed
__APP__: wating
[  249.385048] --------------key_irq_handler------------------
[  249.389152] __KERN__:Enter up
__APP__:catch_signal
__APP__key enter up
__APP__: wating
__APP__: wating
__APP__: wating
__APP__: wating
__APP__: wating
[  253.459049] --------------key_irq_handler------------------
[  253.463145] __KERN__:Enter down
__APP__:catch_signal
__APP__key enter pressed
__APP__: wating
[  253.649413] --------------key_irq_handler------------------
[  253.653514] __KERN__:Enter up
__APP__:catch_signal
__APP__key enter up
__APP__: wating
__APP__: wating
__APP__: wating
__APP__: wating
__APP__: wating
__APP__: wating
[  258.725804] __KERN__:release

2-按键驱动之中断下半部tasklet实验

2.1, 驱动程序

//--------------------- key_drv.c--------------------
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/input-event-codes.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <asm/io.h>


#define GPX1CON_ADDR 0x11000c20
#define GPX1_SIZE 8

//设计一个全局设备对象--描述按键信息
struct key_irq_str{
	int irqno;
	unsigned int dev_major;
	unsigned int dev_minor;
	struct class* pkey_class;	
	struct device* pkey_device;
	void* reg_virt_base;
	wait_queue_head_t wq;
	int key_state;	//表示是否有数据
	struct fasync_struct* fasync;
	struct tasklet_struct mytasklet;
};
struct key_irq_str *pkey_irq_str;

//设计一个描述按键的数据的对象
struct key_value_dsc{
	int code;		//表示按键的类型:home, esc, Q, W, E, R, T...
	int date;		//表示按下还是抬起 1/0
};
struct key_value_dsc key3_value_dsc = {
	.code = 0,
	.date = 0,
};

void key_drv_tasklet_half_func(unsigned long date)
{
	//表示有数据,需要唤醒整个等待队列
	wake_up_interruptible(&(pkey_irq_str->wq));
	
	//同时设置标志位
	pkey_irq_str->key_state = 1;
	
	//发送信号
	kill_fasync(&(pkey_irq_str->fasync), SIGIO, POLLIN);
}



int key_drv_fasync(int fd, struct file * filp, int on)
{
	//只需要调用一个函数,记录信号该发送给谁
	return fasync_helper(fd, filp, on, &pkey_irq_str->fasync);
}

irqreturn_t key_irq_handler(int irqno, void *devid)
{
	unsigned int GPX1DAT;
	
	printk("--------------%s------------------\n",__FUNCTION__);
	
	GPX1DAT = readl(pkey_irq_str->reg_virt_base + 4);
	
	if( GPX1DAT &= 0x1<<2 ){
		printk("__KERN__:Enter up\n");	 
		key3_value_dsc.code = KEY_ENTER;
		key3_value_dsc.date = 0;
	}
	else{
		printk("__KERN__:Enter down\n");
		key3_value_dsc.code = KEY_ENTER;
		key3_value_dsc.date = 1;
	}

	//启动中断处理函数的下半部
	tasklet_schedule(&pkey_irq_str->mytasklet);

	return IRQ_HANDLED;
}

int key_drv_open (struct inode* inode, struct file *filp){
	printk("__KERN__:open\n");
	return 0;
}

ssize_t key_drv_read (struct file *filp, char __user *buf, size_t count, loff_t *fpos){
	int ret;

	//兼容阻塞和非阻塞模式。如果当前是非阻塞模式,并且没有数据,立马返回一个出错码
	if(filp->f_flags & O_NONBLOCK && !pkey_irq_str->key_state)
	{
		return EAGAIN;
	}
	
	wait_event_interruptible(pkey_irq_str->wq, pkey_irq_str->key_state);

	//表示有数据
	ret = copy_to_user(buf, &key3_value_dsc, count);

	if(ret == 0)
	{
		//printk("__KERN__:read\n");
	}
	else
	{
		printk("__KERN__:Err to read\n");
	}
	
	key3_value_dsc.code = 0;
	key3_value_dsc.date = 0;

	pkey_irq_str->key_state = 0;
	
	return count;
}

ssize_t key_drv_write (struct file *filp, const char __user *buf, size_t count, loff_t *fpos){
	

	return 0;
}


int key_drv_release (struct inode *inod, struct file *filp){
	printk("__KERN__:release\n");
	return 0;
}


const struct file_operations key_drv_fops = {
	.open = key_drv_open,
	.read = key_drv_read,
	.write = key_drv_write,
	.release = key_drv_release,
	.fasync = key_drv_fasync,
};

int get_irqno_from_node(void)
{
	//获取到设备树中的节点

	struct device_node *np = of_find_node_by_path("/key_int_node");
	
	if(np){
		printk("find node ok\n");
	}
	else{
		printk("find node failed\n");
	}
	//通过节点去获取到中断号码
	pkey_irq_str->irqno = irq_of_parse_and_map(np,0);
	
	printk("irqno = %d\n",pkey_irq_str->irqno);

	return pkey_irq_str->irqno;
}

static int __init key_drv_init(void)
{
	
	int ret;
	
	//1.设定一个全局的设备对象
	pkey_irq_str = kzalloc(sizeof(struct key_irq_str), 1);

	//2.申请主设备号,设置次设备号
	pkey_irq_str->dev_major = register_chrdev(0, "key_drv_test", &key_drv_fops);

	pkey_irq_str->dev_minor = 0;

	//3.创建设备节点
	pkey_irq_str->pkey_class = class_create(THIS_MODULE, "key_interrupt_dev");

	pkey_irq_str->pkey_device = device_create(pkey_irq_str->pkey_class,NULL,MKDEV(pkey_irq_str->dev_major, pkey_irq_str->dev_minor),NULL,"INTRRUPT KEY%d",3);
	
	//4.硬件初始化--地址映射或中断申请
	
	ret = get_irqno_from_node();

	ret = request_irq(pkey_irq_str->irqno, key_irq_handler, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, "IRQ_EINT10", NULL);

	if(ret != 0)
	{
		printk("request_irq ERROR!\n");
		return ret;
	}

	pkey_irq_str->reg_virt_base = ioremap(GPX1CON_ADDR, GPX1_SIZE);

	//5. 初始化等待队列头
	init_waitqueue_head(&(pkey_irq_str->wq));
	pkey_irq_str->key_state = 0;

	//6. 初始化tasklet
	tasklet_init(&(pkey_irq_str->mytasklet), key_drv_tasklet_half_func, 233);
	
	return 0;
}

static void __exit key_drv_exit(void)
{
	tasklet_kill(&pkey_irq_str->mytasklet);
	iounmap(pkey_irq_str->reg_virt_base);
	free_irq(pkey_irq_str->irqno,NULL);
	device_destroy(pkey_irq_str->pkey_class, MKDEV(pkey_irq_str->dev_major, pkey_irq_str->dev_minor));
	class_destroy(pkey_irq_str->pkey_class);
	unregister_chrdev(pkey_irq_str->dev_major, "key_drv_test");
	kfree(pkey_irq_str);
}


module_init(key_drv_init);
module_exit(key_drv_exit);
MODULE_LICENSE("GPL");

2.2, 应用程序代码

//--------------------- key_test.c--------------------
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>


#define KEY_ENTER 28
#define EAGAIN 35

int fd;

struct key_value_dsc{
	int code;		//表示按键的类型:home, esc, Q, W, E, R, T...
	int date;		//表示按下还是抬起 1/0
};

struct key_value_dsc key_value;

void catch_signal(int signo)
{
	int ret;
	
	if(signo == SIGIO)
	{
		printf("__APP__:catch_signal\n");
		
		//可以直接去读数据, 一定可以读到数据
		ret = read(fd, &key_value, sizeof(struct key_value_dsc));
		
		if(ret < 0){
			perror("read:");
			exit(1);
		}
		
		if(key_value.code == KEY_ENTER)
		{
			if(key_value.date == 1)
			{
				printf("__APP__key enter pressed\n",key_value.date);
			}
			else if(key_value.date == 0) 
			{
				printf("__APP__key enter up\n",key_value.date);
			}
		}
	}
	
}

int main(int argc, char **argv)
{
	int ret, flag;
	char in_buf[128] = {0};
	
	fd = open("/dev/INTRRUPT KEY3",O_RDWR);

	if(fd < 0){
		perror("open:");
		exit(1);
	}

	//1.设置信号处理方法
	signal(SIGIO, catch_signal);

	//2.将当前进程设置成SIGIO的属主进程
	fcntl(fd,F_SETOWN,getpid());

	//3. 将IO模式设置成异步模式
	flag = fcntl(fd,F_GETFL); 
	fcntl(fd,F_SETFL,flag | FASYNC);

	while(1)
	{
		printf("__APP__: wating\n");
		sleep(1);
	}
	
	close(fd);
	return 0;
}

2.3 Makefile代码

ROOTFS_DIR = /home/linux/Level11

APP_NAME = key_test

CROSS_COMPILE = arm-none-linux-gnueabi-
CC = $(CROSS_COMPILE)gcc

ifeq ($(KERNELRELEASE), )

KERNEL_DIR = /home/linux/Level10/day6/linux-5.4.79
CUR_DIR = $(shell pwd)

all :
		make -C  $(KERNEL_DIR) M=$(CUR_DIR) modules -j6 ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-
		$(CC) $(APP_NAME).c -o $(APP_NAME)

clean :
		make -C  $(KERNEL_DIR) M=$(CUR_DIR) clean
		rm $(APP_NAME) ./1/$(APP_NAME)
		clear

install:
		cp -raf  *.ko  $(APP_NAME)   ./1/
		
else
obj-m += key_drv.o

endif


2.4 效果展示:

[root@farsight ]# ./key_test
[  242.155750] __KERN__:open
__APP__: wating
__APP__: wating
__APP__: wating
__APP__: wating
__APP__: wating
__APP__: wating
__APP__: wating
[  249.189787] --------------key_irq_handler------------------
[  249.193888] __KERN__:Enter down
__APP__: wating
__APP__:catch_signal
__APP__key enter pressed
__APP__: wating
[  249.385048] --------------key_irq_handler------------------
[  249.389152] __KERN__:Enter up
__APP__:catch_signal
__APP__key enter up
__APP__: wating
__APP__: wating
__APP__: wating
__APP__: wating
__APP__: wating
[  253.459049] --------------key_irq_handler------------------
[  253.463145] __KERN__:Enter down
__APP__:catch_signal
__APP__key enter pressed
__APP__: wating
[  253.649413] --------------key_irq_handler------------------
[  253.653514] __KERN__:Enter up
__APP__:catch_signal
__APP__key enter up
__APP__: wating
__APP__: wating
__APP__: wating
__APP__: wating
__APP__: wating
__APP__: wating
[  258.725804] __KERN__:release

3-按键驱动之中断下半部工作队列实验

3.1 驱动代码

//--------------------- key_drv.c--------------------
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/input-event-codes.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <asm/io.h>

#define GPX1CON_ADDR 0x11000c20
#define GPX1_SIZE 8

//设计一个全局设备对象--描述按键信息
struct key_irq_str{
	int irqno;
	unsigned int dev_major;
	unsigned int dev_minor;
	struct class* pkey_class;	
	struct device* pkey_device;
	void* reg_virt_base;
	wait_queue_head_t wq;
	int key_state;	//表示是否有数据
	struct fasync_struct* fasync;
	struct work_struct mywork;
};
struct key_irq_str *pkey_irq_str;

//设计一个描述按键的数据的对象
struct key_value_dsc{
	int code;		//表示按键的类型:home, esc, Q, W, E, R, T...
	int date;		//表示按下还是抬起 1/0
};
struct key_value_dsc key3_value_dsc = {
	.code = 0,
	.date = 0,
};

void key_drv_work_half_func(struct work_struct *work)
{
	//表示有数据,需要唤醒整个等待队列
	wake_up_interruptible(&(pkey_irq_str->wq));
	
	//同时设置标志位
	pkey_irq_str->key_state = 1;
	
	//发送信号
	kill_fasync(&(pkey_irq_str->fasync), SIGIO, POLLIN);
}



int key_drv_fasync(int fd, struct file * filp, int on)
{
	//只需要调用一个函数,记录信号该发送给谁
	return fasync_helper(fd, filp, on, &pkey_irq_str->fasync);
}

irqreturn_t key_irq_handler(int irqno, void *devid)
{
	unsigned int GPX1DAT;
	
	printk("--------------%s------------------\n",__FUNCTION__);
	
	GPX1DAT = readl(pkey_irq_str->reg_virt_base + 4);
	
	if( GPX1DAT &= 0x1<<2 ){
		printk("__KERN__:Enter up\n");	 
		key3_value_dsc.code = KEY_ENTER;
		key3_value_dsc.date = 0;
	}
	else{
		printk("__KERN__:Enter down\n");
		key3_value_dsc.code = KEY_ENTER;
		key3_value_dsc.date = 1;
	}

	//启动中断处理函数的下半部
	schedule_work(&pkey_irq_str->mywork);

	return IRQ_HANDLED;
}

int key_drv_open (struct inode* inode, struct file *filp){
	printk("__KERN__:open\n");
	return 0;
}

ssize_t key_drv_read (struct file *filp, char __user *buf, size_t count, loff_t *fpos){
	int ret;

	//兼容阻塞和非阻塞模式。如果当前是非阻塞模式,并且没有数据,立马返回一个出错码
	if(filp->f_flags & O_NONBLOCK && !pkey_irq_str->key_state)
	{
		return EAGAIN;
	}
	
	wait_event_interruptible(pkey_irq_str->wq, pkey_irq_str->key_state);

	//表示有数据
	ret = copy_to_user(buf, &key3_value_dsc, count);

	if(ret == 0)
	{
		//printk("__KERN__:read\n");
	}
	else
	{
		printk("__KERN__:Err to read\n");
	}
	
	key3_value_dsc.code = 0;
	key3_value_dsc.date = 0;

	pkey_irq_str->key_state = 0;
	
	return count;
}

ssize_t key_drv_write (struct file *filp, const char __user *buf, size_t count, loff_t *fpos){
	

	return 0;
}


int key_drv_release (struct inode *inod, struct file *filp){
	printk("__KERN__:release\n");
	return 0;
}


const struct file_operations key_drv_fops = {
	.open = key_drv_open,
	.read = key_drv_read,
	.write = key_drv_write,
	.release = key_drv_release,
	.fasync = key_drv_fasync,
};

int get_irqno_from_node(void)
{
	//获取到设备树中的节点

	struct device_node *np = of_find_node_by_path("/key_int_node");
	
	if(np){
		printk("find node ok\n");
	}
	else{
		printk("find node failed\n");
	}
	//通过节点去获取到中断号码
	pkey_irq_str->irqno = irq_of_parse_and_map(np,0);
	
	printk("irqno = %d\n",pkey_irq_str->irqno);

	return pkey_irq_str->irqno;
}

static int __init key_drv_init(void)
{
	
	int ret;
	
	//1.设定一个全局的设备对象
	pkey_irq_str = kzalloc(sizeof(struct key_irq_str), 1);

	//2.申请主设备号,设置次设备号
	pkey_irq_str->dev_major = register_chrdev(0, "key_drv_test", &key_drv_fops);

	pkey_irq_str->dev_minor = 0;

	//3.创建设备节点
	pkey_irq_str->pkey_class = class_create(THIS_MODULE, "key_interrupt_dev");

	pkey_irq_str->pkey_device = device_create(pkey_irq_str->pkey_class,NULL,MKDEV(pkey_irq_str->dev_major, pkey_irq_str->dev_minor),NULL,"INTRRUPT KEY%d",3);
	
	//4.硬件初始化--地址映射或中断申请
	
	ret = get_irqno_from_node();

	ret = request_irq(pkey_irq_str->irqno, key_irq_handler, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, "IRQ_EINT10", NULL);

	if(ret != 0)
	{
		printk("request_irq ERROR!\n");
		return ret;
	}

	pkey_irq_str->reg_virt_base = ioremap(GPX1CON_ADDR, GPX1_SIZE);

	//5. 初始化等待队列头
	init_waitqueue_head(&(pkey_irq_str->wq));
	pkey_irq_str->key_state = 0;

	//6. 初始化work
	INIT_WORK(&(pkey_irq_str->mywork), key_drv_work_half_func);
	
	return 0;
}

static void __exit key_drv_exit(void)
{
	cancel_work_sync(&pkey_irq_str->mywork);
	iounmap(pkey_irq_str->reg_virt_base);
	free_irq(pkey_irq_str->irqno,NULL);
	device_destroy(pkey_irq_str->pkey_class, MKDEV(pkey_irq_str->dev_major, pkey_irq_str->dev_minor));
	class_destroy(pkey_irq_str->pkey_class);
	unregister_chrdev(pkey_irq_str->dev_major, "key_drv_test");
	kfree(pkey_irq_str);
}


module_init(key_drv_init);
module_exit(key_drv_exit);
MODULE_LICENSE("GPL");

3.2 应用代码

//--------------------- key_test.c--------------------
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>


#define KEY_ENTER 28
#define EAGAIN 35

int fd;

struct key_value_dsc{
	int code;		//表示按键的类型:home, esc, Q, W, E, R, T...
	int date;		//表示按下还是抬起 1/0
};

struct key_value_dsc key_value;

void catch_signal(int signo)
{
	int ret;
	
	if(signo == SIGIO)
	{
		printf("__APP__:catch_signal\n");
		
		//可以直接去读数据, 一定可以读到数据
		ret = read(fd, &key_value, sizeof(struct key_value_dsc));
		
		if(ret < 0){
			perror("read:");
			exit(1);
		}
		
		if(key_value.code == KEY_ENTER)
		{
			if(key_value.date == 1)
			{
				printf("__APP__key enter pressed\n",key_value.date);
			}
			else if(key_value.date == 0) 
			{
				printf("__APP__key enter up\n",key_value.date);
			}
		}
	}
	
}

int main(int argc, char **argv)
{
	int ret, flag;
	char in_buf[128] = {0};
	
	fd = open("/dev/INTRRUPT KEY3",O_RDWR);

	if(fd < 0){
		perror("open:");
		exit(1);
	}

	//1.设置信号处理方法
	signal(SIGIO, catch_signal);

	//2.将当前进程设置成SIGIO的属主进程
	fcntl(fd,F_SETOWN,getpid());

	//3. 将IO模式设置成异步模式
	flag = fcntl(fd,F_GETFL); 
	fcntl(fd,F_SETFL,flag | FASYNC);

	while(1)
	{
		printf("__APP__: wating\n");
		sleep(1);
	}
	
	close(fd);
	return 0;
}

3.3 Makefile代码

ROOTFS_DIR = /home/linux/Level11

APP_NAME = key_test

CROSS_COMPILE = arm-none-linux-gnueabi-
CC = $(CROSS_COMPILE)gcc

ifeq ($(KERNELRELEASE), )

KERNEL_DIR = /home/linux/Level10/day6/linux-5.4.79
CUR_DIR = $(shell pwd)

all :
		make -C  $(KERNEL_DIR) M=$(CUR_DIR) modules -j6 ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-
		$(CC) $(APP_NAME).c -o $(APP_NAME)

clean :
		make -C  $(KERNEL_DIR) M=$(CUR_DIR) clean
		rm $(APP_NAME) ./1/$(APP_NAME)
		clear

install:
		cp -raf  *.ko  $(APP_NAME)   ./1/
		
else
obj-m += key_drv.o

endif

3.4 效果展示:

[root@farsight ]# ./key_test
[  242.155750] __KERN__:open
__APP__: wating
__APP__: wating
__APP__: wating
__APP__: wating
__APP__: wating
__APP__: wating
__APP__: wating
[  249.189787] --------------key_irq_handler------------------
[  249.193888] __KERN__:Enter down
__APP__: wating
__APP__:catch_signal
__APP__key enter pressed
__APP__: wating
[  249.385048] --------------key_irq_handler------------------
[  249.389152] __KERN__:Enter up
__APP__:catch_signal
__APP__key enter up
__APP__: wating
__APP__: wating
__APP__: wating
__APP__: wating
__APP__: wating
[  253.459049] --------------key_irq_handler------------------
[  253.463145] __KERN__:Enter down
__APP__:catch_signal
__APP__key enter pressed
__APP__: wating
[  253.649413] --------------key_irq_handler------------------
[  253.653514] __KERN__:Enter up
__APP__:catch_signal
__APP__key enter up
__APP__: wating
__APP__: wating
__APP__: wating
__APP__: wating
__APP__: wating
__APP__: wating
[  258.725804] __KERN__:release