通过自己的一个案例来体会一下驱动编程的的思想

#include <linux/module.h>             //驱动层           
#include <linux/kernel.h>
#include <mach/gpio.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <plat/gpio-cfg.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/delay.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/timer.h>


struct  keyinfo  {
	unsigned int  gpio;
	char  name[12];
	int  value;
	int  irq;
};

static  struct  keyinfo   g_arrkey[] = {
		{EXYNOS4_GPX3(2),  "key1",  1, 0},
		{EXYNOS4_GPX3(3),  "key2",  1, 0},
		{EXYNOS4_GPX3(4),  "key3",  1, 0},
		{EXYNOS4_GPX3(5),  "key4",  1, 0},
};

static struct fasync_struct* g_ptfasync = NULL;
static  DECLARE_WAIT_QUEUE_HEAD(wq);   
static  bool condition = 0;
static  struct  timer_list  g_ttimer;



static  irqreturn_t  key_irq_handler(int irq, void * arg)
{
	struct  keyinfo*   pkey = (struct  keyinfo*)arg;
	
	g_ttimer.data = (unsigned long)pkey;
	mod_timer(&g_ttimer, jiffies + HZ / 200);

	return  IRQ_HANDLED;
}

static  void  key_timer_handler(unsigned long arg)
{
//	struct  keyinfo* pk = (struct  keyinfo*)arg;
//	printk("timer_handler: %s pressed!\n",  pk->name);

	kill_fasync(&g_ptfasync, SIGIO, POLL_IN);
	condition = 1;
	wake_up_interruptible(&wq);
}

static  ssize_t   key_read(struct file * filp, char __user * buff, size_t count, loff_t * offset)
{
	int i = 0;
	char buf[32] = {0};
	int ret = 0;

	wait_event_interruptible(wq, condition);
	condition = 0;

	for(i = 0; i < ARRAY_SIZE(g_arrkey); i++)
	{	
		if(!gpio_get_value(g_arrkey[i].gpio))
		{
			sprintf(buf, "%s is pressed!", g_arrkey[i].name);
			break;
		}
	}

	ret = copy_to_user(buff, buf, min(strlen(buf), count));
	return  min(strlen(buf), count);
}

static  int  key_fasync(int fd, struct file* filp, int on)
{
	printk("---drv_fasync---\n");
	return  fasync_helper(fd, filp,  on, &g_ptfasync);
}

static  struct file_operations  g_tfops = {
		.owner		=	THIS_MODULE,
		.read		=	key_read,
		.fasync 	=	key_fasync,
};

static  struct miscdevice  g_tmiscdev = {
	.minor 	=	MISC_DYNAMIC_MINOR,
	.name	=	"key_irq",
	.fops	=	&g_tfops,
};

static  int  __init  my_fasync_init(void)
{
	int i = 0;
	int ret = 0;

	for(i = 0; i < ARRAY_SIZE(g_arrkey); i++)
	{
		gpio_request(g_arrkey[i].gpio, g_arrkey[i].name);
		s3c_gpio_cfgpin(g_arrkey[i].gpio, S3C_GPIO_INPUT);
		g_arrkey[i].irq = gpio_to_irq(g_arrkey[i].gpio);
		ret = request_irq(g_arrkey[i].irq, key_irq_handler, 
			IRQF_SHARED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 
			g_arrkey[i].name, &g_arrkey[i]);
	}

	setup_timer(&g_ttimer, key_timer_handler, 0);
	misc_register(&g_tmiscdev);
	return 0;
}

static void __exit my_fasync_exit(void)
{
	int i = 0;
	misc_deregister(&g_tmiscdev);
	del_timer_sync(&g_ttimer);

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

module_init(my_fasync_init);
module_exit(my_fasync_exit);

MODULE_LICENSE("GPL");
#include <stdio.h>                   //应用层
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>


int  fd = 0;
void  sig_handler(int sig);

int main(int argc, char* argv[])
{
	fd = open(argv[1], O_RDWR);
	if(fd < 0)
	{
		printf("open failed!\n");
		return -1;
	}
	
	signal(SIGIO, sig_handler);

	int oldflag = 0;
	fcntl(fd, F_SETOWN, getpid());
	oldflag =  fcntl(fd, F_GETFL);
	printf("app: set FASYNC before...\n");
	fcntl(fd, F_SETFL, oldflag | FASYNC);
	printf("app: set FASYNC after...\n");
	
	/* 当前程序就可以任意操作 */
	while(1)
	{
		printf("hello  haha!\n");
		sleep(1);
	}

	close(fd);
	return 0;
}

void  sig_handler(int sig)
{
	char buf[32] = {0};
	printf("***sig handler***\n");	
	read(fd, buf, sizeof(buf));
	printf("read: %s\n", buf);
}

有类似的一段断码程序分析博客:点击打开链接 https://blog.csdn.net/psvoldemort/article/details/21184525


函数的逻辑图如下:

猜你喜欢

转载自blog.csdn.net/qq_35769746/article/details/81020929