zoukankan      html  css  js  c++  java
  • kobox : key_waitqueue.c -v1 如何内核线程,如何使用等待队列

    平台:TQ2440 按键驱动

    (1)在init中创建一个内核线程作为等待队列的处理函数,该内核线程是一个while(1)死循环,一直检測等待队列的触发条件

    DECLARE_WAIT_QUEUE_HEAD(key_driver_wq);  
    

    /* create a kernel thread */
    kthread_run(key_wait_queue_handler, "thread_key_waitqueue", "[key_wait_queue]");


    static int key_wait_queue_handler(void *name)
    {
    	int i = 0;
    	int ret;
    	unsigned int pin;
    
    	printk("thread name:[%s]
    ", name);
    
    	while(1)
    	{	
    		wait_event(key_driver_wq, condition == 1);
    
    		if(condition == 1)
    		{
    			...
    		}
    
    		msleep(100);
    
    		if(condition == 1)
    		{
    			condition = 0;
    		}
    	}
    
    	return;
    }
    

    (2)中断中调度等待队列

    static irqreturn_t kobox_gpio_irq_handle(int irq, void *dev_id)
    {
    	int key;
    
    	disable_irq_nosync(irq);
    
    	printk("irq = %d
    ", irq);
    
    	if(dev_id)
    		printk("dev_id:%s
    ", dev_id);
    
    	switch(irq)
    	{
    		case IRQ_EINT1:
    			key = 0;
    			break;
    		case IRQ_EINT4:
    			key = 1;
    			break;
    		case IRQ_EINT2:
    			key = 2;
    			break;
    		case IRQ_EINT0:
    			key = 3;
    			break;
    		default:
    			printk("invalid irq:%d
    ", irq);
     			return IRQ_HANDLED;
     	}
    
    	/* 去抖:延时100ms后,在buttons_timer中读取按键状态,假设还是按下的,就说明是被正常按下的
    		使用timer是一种方式,后面再採用工作队列、tasklet中的方式来处理	*/
    	condition = 1;
    	wake_up(&key_driver_wq);
    	
    	enable_irq(irq);
    	
    	return IRQ_RETVAL(IRQ_HANDLED);
    }

    (3)驱动源代码:


    #include "key.h"
    
    #define S3C_ADDR_BASE	0xF6000000
    #define S3C_ADDR(x)	(S3C_ADDR_BASE + (x))
    #define S3C2410_PA_UART		(0x50000000)
    #define S3C2410_PA_GPIO		(0x56000000)
    #define S3C_VA_UART	S3C_ADDR(0x01000000)	/* UART */
    #define S3C24XX_PA_UART		S3C2410_PA_UART
    #define S3C24XX_VA_UART		S3C_VA_UART
    #define S3C24XX_PA_GPIO		S3C2410_PA_GPIO
    #define S3C24XX_VA_GPIO		((S3C24XX_PA_GPIO - S3C24XX_PA_UART) + S3C24XX_VA_UART)
    
    #define S3C2410_GPIOREG(x) ((x) + S3C24XX_VA_GPIO)
    
    #define S3C2410_GPBCON	   S3C2410_GPIOREG(0x10)
    #define S3C2410_GPBDAT	   S3C2410_GPIOREG(0x14)
    #define S3C2410_GPBUP	   S3C2410_GPIOREG(0x18)
    
    #define S3C2410_GPFCON	   S3C2410_GPIOREG(0x50)
    #define S3C2410_GPFDAT	   S3C2410_GPIOREG(0x54)
    #define S3C2410_GPFUP	   S3C2410_GPIOREG(0x58)
    
    #define S3C2410_EXTINT0	   S3C2410_GPIOREG(0x88)
    #define S3C2410_EXTINT1	   S3C2410_GPIOREG(0x8C)
    #define S3C2410_EXTINT2	   S3C2410_GPIOREG(0x90)
    
    #define S3C2410_CPUIRQ_OFFSET	 (16)
    #define S3C2410_IRQ(x) ((x) + S3C2410_CPUIRQ_OFFSET)
    /* main cpu interrupts */
    #define IRQ_EINT0      S3C2410_IRQ(0)	    /* 16 */
    #define IRQ_EINT1      S3C2410_IRQ(1)		/* 17 */
    #define IRQ_EINT2      S3C2410_IRQ(2)		/* 18 */
    #define IRQ_EINT4t7    S3C2410_IRQ(4)	    /* 20 */
    #define IRQ_EINT4      S3C2410_IRQ(36)	   /* 52 */
    
    #define IRQF_DISABLED		0x00000020
    #define IRQF_SHARED		0x00000080
    #define IRQF_PROBE_SHARED	0x00000100
    #define __IRQF_TIMER		0x00000200
    #define IRQF_PERCPU		0x00000400
    #define IRQF_NOBALANCING	0x00000800
    #define IRQF_IRQPOLL		0x00001000
    #define IRQF_ONESHOT		0x00002000
    #define IRQF_NO_SUSPEND	0x00004000
    #define IRQF_FORCE_RESUME	0x00008000
    #define IRQF_NO_THREAD		0x00010000
    #define IRQF_EARLY_RESUME	0x00020000
    
    typedef struct gpioRes
    {
    	int irqNum;		/* 中断号 */
    	unsigned int ctrlReg;	/* 控制寄存器,用于设置复用为GPIO */
    	unsigned int ctrlBit; 	/* 控制寄存器的哪一位,用于复用为GPIO */
    	unsigned int trigReg;	/* 中断方式寄存器,设置中断的触发方式 */
    	unsigned int trigBit;	/* 中断方式寄存器哪一位,设置中断的触发方式 */
    	unsigned int irqFlag;	/* 共享还是不共享,注冊中断的flag */
    	char irqName[32];		/* 中断名称 */
    	unsigned int gpfPin;	/* GPF的第几个pin */
    	char Reserved[10];		/* 保留 */
    }gpioRes;
    
    unsigned int pressCnt[4] = {0, 0, 0, 0};
    
    #define ARRAY_SIZE(arr) (sizeof(arr)/sizeof((arr)[0]))
    
    static int kobox_key_open(struct inode *inode, struct file *file)
    {
    	return 0;
    }
    
    static int kobox_key_release(struct inode *inode, struct file *file)
    {
    	return 0;
    }
    
    static long kobox_key_ioctl(struct file *file, unsigned int cmd,
    			   unsigned long arg)
    {
    	return 0;
    }
    
    static int kobox_key_read(struct file *file, char __user *buff, size_t count, loff_t *pos)
    {
    	printk("Enter [%s][%d]
    ", __FUNCTION__,__LINE__);
    	copy_to_user(buff, &pressCnt[0], sizeof(pressCnt));
    	
    	return 0;
    }
    
    /*
    GPF相关寄存器:
    
    GPFCON 0x56000050 R/W Configures the pins of port F 0x0
    GPFDAT 0x56000054 R/W The data register for port F Undef.
    GPFUP  0x56000058 R/W Pull-up disable register for port F 0x000
    
    K1: GPF1 -EINT1: GPF1 [3:2] 00 = Input	01 = Output 10 = EINT[1]  11 = Reserved
    K2: GPF4 -EINT4: GPF4 [9:8] 00 = Input	01 = Output 10 = EINT[4]  11 = Reserved
    K3: GPF2 -EINT2: GPF2 [5:4] 00 = Input	01 = Output 10 = EINT2]  11 = Reserved
    K4: GPF0 -EINT0: GPF0 [1:0] 00 = Input	01 = Output 10 = EINT[0]  11 = Reserved
    */
    
    
    gpioRes key_gpio_res[4] =
    {
    	{IRQ_EINT1, S3C2410_GPFCON, 2, S3C2410_EXTINT0, 5, NULL, "key1", 1},	/* key1 */
    	{IRQ_EINT4, S3C2410_GPFCON, 8, S3C2410_EXTINT0, 17, IRQF_SHARED, "key2", 4},	/* key2 */
    	{IRQ_EINT2, S3C2410_GPFCON, 4, S3C2410_EXTINT0, 9, NULL, "key3", 2},	/* key3 */
    	{IRQ_EINT0, S3C2410_GPFCON, 0, S3C2410_EXTINT0, 1, NULL, "key4", 0},	/* key4 */
    };
    
    #define KEY_TIMER_DELAY1    (HZ/50)             //按键按下去抖延时20毫秒       
    #define KEY_TIMER_DELAY2    (HZ/10)             //按键抬起去抖延时100毫秒
    #define KEY_COUNT 4
    //static struct timer_list key_timers[KEY_COUNT];  //定义4个按键去抖动定时器
    //static DECLARE_WAIT_QUEUE_HEAD(button_waitq);    //定义并初始化等待队列
    static int condition = 0;
    DECLARE_WAIT_QUEUE_HEAD(key_driver_wq);  
    static int key_wait_queue_handler(void *name);
    
    static void set_gpio_as_eint(void)
    {
    	int i;
    	unsigned uiVal = 0;
    
    	for(i=0; i<	ARRAY_SIZE(key_gpio_res); i++)
    	{
    		uiVal = readl(key_gpio_res[i].ctrlReg);
    		uiVal &= ~(0x01 << key_gpio_res[i].ctrlBit);
    		uiVal |= (0x01 << (key_gpio_res[i].ctrlBit + 1));
    		writel(uiVal, key_gpio_res[i].ctrlReg);
    	}
    
    	return;
    }
    
    static void set_gpio_as_gpio(void)
    {
    	int i;
    	unsigned uiVal = 0;
    
    	for(i=0; i<	ARRAY_SIZE(key_gpio_res); i++)
    	{
    		uiVal = readl(key_gpio_res[i].ctrlReg);
    		uiVal &= ~(0x01 << key_gpio_res[i].ctrlBit);
    		uiVal &= ~(0x01 << (key_gpio_res[i].ctrlBit + 1));
    		writel(uiVal, key_gpio_res[i].ctrlReg);
    	}
    
    	return;
    }
    
    
    static irqreturn_t kobox_gpio_irq_handle(int irq, void *dev_id)
    {
    	int key;
    
    	disable_irq_nosync(irq);
    
    	printk("irq = %d
    ", irq);
    
    	if(dev_id)
    		printk("dev_id:%s
    ", dev_id);
    
    	switch(irq)
    	{
    		case IRQ_EINT1:
    			key = 0;
    			break;
    		case IRQ_EINT4:
    			key = 1;
    			break;
    		case IRQ_EINT2:
    			key = 2;
    			break;
    		case IRQ_EINT0:
    			key = 3;
    			break;
    		default:
    			printk("invalid irq:%d
    ", irq);
     			return IRQ_HANDLED;
     	}
    
    	/* 去抖:延时100ms后,在buttons_timer中读取按键状态,假设还是按下的,就说明是被正常按下的
    		使用timer是一种方式,后面再採用工作队列、tasklet中的方式来处理	*/
    	condition = 1;
    	wake_up(&key_driver_wq);
    	
    	enable_irq(irq);
    	
    	return IRQ_RETVAL(IRQ_HANDLED);
    }
    
    /*
    GPF相关寄存器:
    
    GPFCON 0x56000050 R/W Configures the pins of port F 0x0
    GPFDAT 0x56000054 R/W The data register for port F Undef.
    GPFUP  0x56000058 R/W Pull-up disable register for port F 0x000
    
    K1: GPF1 -EINT1: GPF1 [3:2] 00 = Input	01 = Output 10 = EINT[1]  11 = Reserved
    K2: GPF4 -EINT4: GPF4 [9:8] 00 = Input	01 = Output 10 = EINT[4]  11 = Reserved
    K3: GPF2 -EINT2: GPF2 [5:4] 00 = Input	01 = Output 10 = EINT2]  11 = Reserved
    K4: GPF0 -EINT0: GPF0 [1:0] 00 = Input	01 = Output 10 = EINT[0]  11 = Reserved
    */
    /* 该函数返回0表示按键被按下,返回非0表示没有再被按下,觉得这是电平毛刺导致的,是噪声信号
    	所以,该函数返回0,表示有按键被按下,返回非0表示是抖动	*/
    static int get_gpio_portf_value(unsigned int pin)
    {
    	int ret;
    	unsigned int uiVal = 0;
    
    	printk("I AM @ [%s][%d], pin:%d
    ", __FUNCTION__,__LINE__, pin);	
    
    	uiVal = readl(S3C2410_GPFDAT);
    	ret = (0x1 << pin) & uiVal;
    
    	printk("I AM @ [%s][%d], ret:%d
    ", __FUNCTION__,__LINE__, ret);	
    
    	return ret;
    }
    
    static int request_irq_for_gpio(void)
    {
    	int i;
    	int ret;
    	unsigned uiVal;
    	int nouse;
    
    	for(i=0; i<ARRAY_SIZE(key_gpio_res);i++)
    	{
    		/* 设置中断触发方式:下降沿有效,触发中断,以便依据GPIO的值来推断是否仍在按下 */
    		uiVal = readl(key_gpio_res[i].trigReg);
    		uiVal |= (0x1 << (key_gpio_res[i].trigBit));
    		uiVal &= ~(0x1 << (key_gpio_res[i].trigBit + 1));
    		writel(uiVal, key_gpio_res[i].trigReg);
    
    		/* 注冊中断 */
    		ret = request_irq(key_gpio_res[i].irqNum, 
    						   kobox_gpio_irq_handle,
    						   key_gpio_res[i].irqFlag,
    						   key_gpio_res[i].irqName,
    						   (void *)key_gpio_res[i].irqName);
    		if(ret)
    			printk("[func:%s][line:%d] request_irq failed, ret:%d!
    ", __FUNCTION__,__LINE__,ret);
    		else
    			printk("[func:%s][line:%d] request_irq ok, irq:%d!
    ", __FUNCTION__,__LINE__, key_gpio_res[i].irqNum);	
    	}
    
    	return 0;
    }
    
    static int key_wait_queue_handler(void *name)
    {
    	int i = 0;
    	int ret;
    	unsigned int pin;
    
    	printk("thread name:[%s]
    ", name);
    
    	while(1)
    	{	
    		wait_event(key_driver_wq, condition == 1);
    
    		if(condition == 1)
    		{
    			/* 将引脚由EINTX设置会GPIO */
    			set_gpio_as_gpio();
    
    			for(i=0; i<ARRAY_SIZE(key_gpio_res); i++)
    			{
    				pin = key_gpio_res[i].gpfPin;
    
    				/* 读取相应引脚GPIO的值,返回0表示按键真正被按下,返回1表示抖动 */
    				ret = get_gpio_portf_value(pin);
    				if(0 == ret)
    				{
    					pressCnt[i]++;
    					printk("key pressed: pressCnt[%d]:%d
    ", i, pressCnt[i]);
    				}
    			}
    			/* 将引脚设置回EINTX */
    			set_gpio_as_eint();
    
    			condition = 0;
    		}
    
    		msleep(1000);
    	}
    
    	return;
    }
    
    
    struct file_operations kobox_key_operations = {
    	.owner          = THIS_MODULE,
    	.open           = kobox_key_open,
    	.read 			= kobox_key_read,
    	.release        = kobox_key_release,
    	.unlocked_ioctl = kobox_key_ioctl,
    };
    
    //GPB0
    int major;
    int minor;
    struct cdev cdev;
    struct class *kobox_key_class;
    struct device *pstdev = NULL;
    #define GPIO_KEY_NAME "kobox_key"
    
    int __init key_drv_init(void)
    {
    	int error;
    	dev_t dev;
    
    	printk("#####enter key_drv_init!
    ");
    
    	major = register_chrdev(0, GPIO_KEY_NAME, &kobox_key_operations);
    	if (major < 0)
    	{
    		printk(" can't register major number
    ");
    		return major;
    	}
    
    	/* create class */
    	kobox_key_class = class_create(THIS_MODULE, GPIO_KEY_NAME);
    	if(IS_ERR(kobox_key_class))
    	{
    		printk("class_create failed!
    ");
    		goto fail;
    	}
    
    	/* create /dev/kobox_gpio */
    	pstdev = device_create(kobox_key_class, NULL, MKDEV(major, 0), NULL, GPIO_KEY_NAME);
    	if(!pstdev)
    	{
    		printk("device_create failed!
    ");
    		goto fail1;
    	}
    
    	/* set gpf0/1/2/4 as extern interrupt pins */
    	set_gpio_as_eint();
    
    	request_irq_for_gpio();
    
    	/* create a kernel thread */
    	kthread_run(key_wait_queue_handler, "thread_key_waitqueue", "[key_wait_queue]");
    	
    	printk("#####key_drv_init ok!
    ");
    	
    	return 0;
    fail1:
    	class_destroy(kobox_key_class);
    fail:
    	unregister_chrdev(major, GPIO_KEY_NAME);
    	return -1;
    }
    
    void __exit key_drv_exit(void)
    {
    	printk("exit gpio drv!
    ");	
    
    	device_destroy(kobox_key_class, MKDEV(major, 0));
    	class_destroy(kobox_key_class);
    	unregister_chrdev(major, GPIO_KEY_NAME);
    
    	return;
    }
    
    module_init(key_drv_init);
    module_exit(key_drv_exit);
    MODULE_LICENSE("GPL");


  • 相关阅读:
    Codevs 2296 仪仗队 2008年省队选拔赛山东
    Codevs 1535 封锁阳光大学
    Codevs 1069 关押罪犯 2010年NOIP全国联赛提高组
    Codevs 1218 疫情控制 2012年NOIP全国联赛提高组
    Codevs 1684 垃圾陷阱
    洛谷 P1108 低价购买
    Vijos P1325桐桐的糖果计划
    Codevs 3289 花匠 2013年NOIP全国联赛提高组
    Codevs 2611 观光旅游(floyed最小环)
    C语言基础之彩色版C语言(内含linux)
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/4253573.html
Copyright © 2011-2022 走看看