平台: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]\n", 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\n", irq); if(dev_id)
printk("dev_id:%s\n", 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\n", 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]\n", __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\n", irq); if(dev_id)
printk("dev_id:%s\n", 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\n", 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\n", __FUNCTION__,__LINE__, pin); uiVal = readl(S3C2410_GPFDAT);
ret = (0x1 << pin) & uiVal; printk("I AM @ [%s][%d], ret:%d\n", __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!\n", __FUNCTION__,__LINE__,ret);
else
printk("[func:%s][line:%d] request_irq ok, irq:%d!\n", __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]\n", 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\n", 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!\n"); major = register_chrdev(0, GPIO_KEY_NAME, &kobox_key_operations);
if (major < 0)
{
printk(" can't register major number\n");
return major;
} /* create class */
kobox_key_class = class_create(THIS_MODULE, GPIO_KEY_NAME);
if(IS_ERR(kobox_key_class))
{
printk("class_create failed!\n");
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!\n");
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!\n"); 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!\n"); 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");

kobox : key_waitqueue.c -v1 如何内核线程,如何使用等待队列的更多相关文章

  1. Java线程与Linux内核线程的映射关系[转]

    Linux从内核2.6开始使用NPTL (Native POSIX Thread Library)支持,但这时线程本质上还轻量级进程. Java里的线程是由JVM来管理的,它如何对应到操作系统的线程是 ...

  2. linux常见进程与内核线程

    发现大量jdb2进程占用io资源.jdb2进程是一个文件系统的写journal的进程 kthreadd:这种内核线程只有一个,它的作用是管理调度其它的内核线程.它在内核初始化的时候被创建,会循环运行一 ...

  3. linux进程的地址空间,核心栈,用户栈,内核线程

    linux进程的地址空间,核心栈,用户栈,内核线程 地址空间: 32位linux系统上,进程的地址空间为4G,包括1G的内核地址空间,和3G的用户地址空间. 内核栈: 进程控制块task_struct ...

  4. Linux内核-内核线程

    线程分类:内核线程.用户线程(指不需要内核支持而完全建立在用户空间的线程库,这种线程效率高,由于Linux内核没有轻量级进程(线程)的概念,因此不能独立的对用户线程进行调度,而是由一个线程运行库来组织 ...

  5. 【转】Java线程与Linux内核线程的映射关系

    Linux从内核2.6开始使用NPTL (Native POSIX Thread Library)支持,但这时线程本质上还轻量级进程. Java里的线程是由JVM来管理的,它如何对应到操作系统的线程是 ...

  6. Linux内核线程

    内核线程是直接由内核本身启动的进程.内核线程实际上是将内核函数委托给独立的进程,与系统中其他进程"并行"执行(实际上,也并行于内核自身的执行),内核线程经常被称为内核"守 ...

  7. Java线程与Linux内核线程的映射关系

    Linux从内核2.6开始使用NPTL (Native POSIX Thread Library)支持,但这时线程本质上还轻量级进程. Java里的线程是由JVM来管理的,它如何对应到操作系统的线程是 ...

  8. Linux内核线程的思考与总结

    1.内核线程,只是一个称呼,实际上就是一个进程,有自己独立的TCB,参与内核调度,也参与内核抢占. 这个进程的特别之处有两点,第一.该进程没有前台.第二.永远在内核态中运行. 2.创建内核线程有两种方 ...

  9. 内核线程的进程描述符task_struct中的mm和active_mm

    task_struct进程描述符中包含两个跟进程地址空间相关的字段mm, active_mm, struct task_struct { // ... struct mm_struct *mm; st ...

随机推荐

  1. HSQLDB相关信息及用法汇总

    运行模式 说明 启动命令 JDBC例 内存(Memory-Only)模式 所有数据都在内存里操作.应用程序退出后则数据被销毁.无需另外启动HSQLDB Server 启动方式1:通过程序中首次调用Co ...

  2. CSS十问——好奇心+刨根问底=CSSer (转)

    最近有时间,想把酝酿的几篇博客都写出来,今天前端小学生带着10个问题,跟大家分享一下学习CSS的一些体会,我觉得想学好CSS,必须保持一颗好奇心和刨根问底的劲头,而不是复制粘贴,得过且过.本人能力有限 ...

  3. linux内存操作--ioremap和mmap学习笔记

    最近做一些相关的视频输出,对于保留framebuffer内存使用情况不是很清楚,现在找了一些资料整理出,准备使用.if (希望看到使用)  goto   用法: 对于一个系统来讲,会有非常多的外设,那 ...

  4. CentOS6.5设备MRBS

    //--------------------------------------软件必须安装-----------------------------------// # yum install –y ...

  5. c# 用正则表达式在指定的字符串中每隔指定个数的文字插入指定字符串

    public static string AddNewLine(string inString,int num,string addString="\r\n") { return ...

  6. Windows Server 2012启用Windows功能NetFx3时出错解决方法

    作者:冰点阳光 | 可以转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址:http://baohua.me/operating-system/windows-server-2012- ...

  7. js 自己容易搞混的笔记查询

    相似的操作 var str2 = "0123456789"; console.log(str2.slice(4,7)); //------------"456" ...

  8. Android笔记 之 旋转木马的音乐效果

    一.前言-- 大家一定在百度音乐上在线听过歌,有没有注意到那个旋转唱片-- 就上面那个,当音乐在播放的时候,那个光碟轮子在转,就想旋转木马一般.感觉好好玩啊. 碰巧想起前阵子做音乐播放器,哎,那这个也 ...

  9. BZOJ 3589 动态树 树链拆分+纳入和排除定理

    标题效果:鉴于一棵树.每个节点有一个右值,所有节点正确启动值他们是0.有两种操作模式,0 x y代表x右所有点的子树的根值添加y. 1 k a1 b1 a2 b2 --ak bk代表质疑. 共同拥有者 ...

  10. nginx 1.4.2 安装笔记

    顺便吐槽一下,有道笔记的排版太难用了, 啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊 ========================================== ...