20150218【改进Poll定时查询】IMX257实现GPIO-IRQ中断按键获取键值驱动程序

【改进Poll定时查询】IMX257实现GPIO-IRQ中断按键获取键值驱动程序

2015-02-18 李海沿

 

按键驱动程序中,如果不使用read函数中使程序休眠的,而是还是使用查询方式的话,可以使用Poll函数,来控制一定时间内,如果有按键发生,则立即返回键值。

同时,poll也可以同时监控多个(比如说按键,鼠标,等)一旦发生事件则立即返回。

我们在linux查看帮助:

20150218【改进Poll定时查询】IMX257实现GPIO-IRQ中断按键获取键值驱动程序

从帮助中的说明得知,

poll, ppoll - wait for some event on a file descriptor

poll就是监控某个设备的事件。

 

修改驱动程序

1.增加头文件 #include <linux/poll.h>

2.增加key_poll 方法

 

static unsigned key_poll(struct file *file,poll_table *wait)

 

file_opreation中增加:

.poll = key_poll,

 

20150218【改进Poll定时查询】IMX257实现GPIO-IRQ中断按键获取键值驱动程序

 

3.在key_poll函数中设置函数不睡眠

20150218【改进Poll定时查询】IMX257实现GPIO-IRQ中断按键获取键值驱动程序

 

4.此时可以把以前的read函数中的中断睡眠代码注释掉

20150218【改进Poll定时查询】IMX257实现GPIO-IRQ中断按键获取键值驱动程序

 

5.编译代码,测试

 

附上驱动程序。

 

  1 /******************************

  2     linux key_query

  3  *****************************/

  4 #include <linux/module.h>

  5 #include <linux/init.h>

  6 #include <linux/kernel.h>

  7 #include <linux/delay.h>

  8 #include <linux/types.h>

  9 #include <linux/ioctl.h>

 10 #include <linux/gpio.h>

 11 #include <linux/fs.h>

 12 #include <linux/device.h>

 13 #include <linux/uaccess.h>

 14 #include <linux/irq.h>

 15 #include <linux/wait.h>

 16 #include <linux/sched.h>//error: 'TASK_INTERRUPTIBLE' undeclared 

 17 #include <linux/interrupt.h>

 18 #include <linux/poll.h>

 19 

 20 #include "mx257_gpio.h"

 21 #include "mx25_pins.h"

 22 #include "iomux.h"

 23 

 24 #define Driver_NAME "key_interrupt"

 25 #define DEVICE_NAME "key_interrupt"

 26 

 27 #define GPIO2_21    MX25_PIN_CLKO

 28 #define GPIO3_15    MX25_PIN_EXT_ARMCLK

 29 #define GPIO2_10    MX25_PIN_A24

 30 #define GPIO2_11    MX25_PIN_A25

 31 #define GPIO2_8     MX25_PIN_A22

 32 #define GPIO2_9     MX25_PIN_A23

 33 #define GPIO2_6     MX25_PIN_A20

 34 #define GPIO2_7     MX25_PIN_A21

 35 //command

 36 #define key_input     0

 37 #define version        1

 38 //定义各个按键按下的键值

 39 struct pin_desc{

 40     unsigned int pin;

 41     unsigned int key_val;

 42 };

 43 //当按键按下时,键值分别为 以下值

 44 struct pin_desc pins_desc[8] = {

 45     {GPIO2_6,    0x01},

 46     {GPIO2_7,    0x02},

 47     {GPIO2_8,    0x03},

 48     {GPIO2_9,    0x04},

 49     {GPIO2_10,    0x05},

 50     {GPIO2_11,    0x06},

 51     {GPIO2_21,    0x07},

 52     {GPIO3_15,    0x08},

 53 };

 54 //定义一个全局变量,用于保存按下的键值

 55 static unsigned int key_val;

 56 

 57 //interrupt head

 58 static DECLARE_WAIT_QUEUE_HEAD(key_interrupt_wait);

 59 static volatile unsigned char ev_press;  

 60 

 61 static int major=0;

 62 

 63 //auto to create device node

 64 static struct class *drv_class = NULL;

 65 static struct class_device *drv_class_dev = NULL;

 66 

 67 

 68 /* 应用程序对设备文件/dev/key_query执行open(...)时,

 69  * 就会调用key_open函数*/

 70 static int key_open(struct inode *inode, struct file *file)

 71 {

 72     printk("<0>function open!\n\n");

 73     

 74     return 0;

 75 }

 76 

 77 /* 中断程序key_irq */

 78 static irqreturn_t key_irq(int irq, void *dev_id)

 79 {

 80     struct pin_desc * pindesc = (struct pin_desc *)dev_id;

 81     //发生了中断

 82     //printk("<0>function interrupt key_irq!\n\n");

 83     //获取按键键值

 84     if(gpio_get_value(IOMUX_TO_GPIO(pindesc->pin))){

 85         /* 按下 */

 86         key_val = pindesc->key_val;

 87     }else{

 88         key_val = 0x80 | pindesc->key_val;

 89     }

 90     printk("<0>get key 0x%x",key_val);    

 91     ev_press = 1;

 92     wake_up_interruptible(&key_interrupt_wait);

 93 

 94     return IRQ_RETVAL(IRQ_HANDLED);

 95 }

 96 

 97 

 98 static int key_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)

 99 {

100     int ret;

101     //如果按键没有按下,没有中断,休眠

102     //wait_event_interruptible(key_interrupt_wait,ev_press);

103 

104     ret = copy_to_user(buff,&key_val,sizeof(key_val));

105     if(ret){

106         ;

107     }

108     ev_press = 0;

109     return sizeof(key_val);

110 

111     //int cnt=0;

112     //unsigned char key_vals[8];

113 

114     /*

115     // reading the pins value

116     key_vals[0] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_6)) ? 1 : 0;

117     key_vals[1] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_7)) ? 1 : 0;

118     key_vals[2] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_8)) ? 1 : 0;

119     key_vals[3] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_9)) ? 1 : 0;

120     key_vals[4] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_10)) ? 1 : 0;

121     key_vals[5] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_11)) ? 1 : 0;

122     key_vals[6] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_21)) ? 1 : 0;

123     key_vals[7] = gpio_get_value(IOMUX_TO_GPIO(GPIO3_15)) ? 1 : 0;

124     

125     //printk("<0>%04d key pressed: %d %d %d %d %d %d %d %d\n",cnt++,key_vals[0],key_vals[1],key_vals[2],key_vals[3],key_vals[4],key_vals[5],key_vals[6],key_vals[7]); 

126     */

127 }

128 

129 static ssize_t key_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)

130 {

131     printk("<0>function write!\n\n");

132     

133     return 1;

134 }

135 

136 static int  key_release(struct inode *inode, struct file *filp)

137 {

138     printk("<0>function release!\n\n");

139     //释放中断

140     free_irq(IOMUX_TO_IRQ(GPIO2_21),  &pins_desc[6]);

141     //free_irq(IOMUX_TO_IRQ(GPIO3_15),&pins_desc[7]);

142     free_irq(IOMUX_TO_IRQ(GPIO2_11),  &pins_desc[5]);

143     free_irq(IOMUX_TO_IRQ(GPIO2_10),  &pins_desc[4]);

144     free_irq(IOMUX_TO_IRQ(GPIO2_9),   &pins_desc[3]);

145     //free_irq(IOMUX_TO_IRQ(GPIO2_8), &pins_desc[2]);

146     free_irq(IOMUX_TO_IRQ(GPIO2_7),   &pins_desc[1]);

147     free_irq(IOMUX_TO_IRQ(GPIO2_6),   &pins_desc[0]);

148     return 0;

149 }

150 

151 static int key_ioctl(struct inode *inode,struct file *flip,unsigned int command,unsigned long arg)

152 {

153     int ret;

154     printk("<0>function ioctl!\n\n");

155     switch (command) {

156         case key_input:    

157             //设置所有的引脚为输入

158             gpio_direction_input(IOMUX_TO_GPIO(GPIO2_21));

159             gpio_direction_input(IOMUX_TO_GPIO(GPIO3_15));

160             gpio_direction_input(IOMUX_TO_GPIO(GPIO2_10));

161             gpio_direction_input(IOMUX_TO_GPIO(GPIO2_11));

162             gpio_direction_input(IOMUX_TO_GPIO(GPIO2_8));

163             gpio_direction_input(IOMUX_TO_GPIO(GPIO2_9));

164             gpio_direction_input(IOMUX_TO_GPIO(GPIO2_6));

165             gpio_direction_input(IOMUX_TO_GPIO(GPIO2_7));

166             printk("<0>have setting all pins to gpio input mod !\n");

167             //设置GPIO引脚为上拉模式

168             mxc_iomux_set_pad(GPIO2_6, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);

169             mxc_iomux_set_pad(GPIO2_7, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);

170             //mxc_iomux_set_pad(GPIO2_8, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);

171             mxc_iomux_set_pad(GPIO2_9, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);

172             mxc_iomux_set_pad(GPIO2_10, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);

173             mxc_iomux_set_pad(GPIO2_11, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);

174             mxc_iomux_set_pad(GPIO2_21, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);

175             //mxc_iomux_set_pad(GPIO3_15, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);

176 

177             //设置GPIO引脚中断  ,下降沿触发

178             request_irq(IOMUX_TO_IRQ(GPIO2_6), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_6", &pins_desc[0]);

179             request_irq(IOMUX_TO_IRQ(GPIO2_7), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_7", &pins_desc[1]);

180             request_irq(IOMUX_TO_IRQ(GPIO2_9), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_9", &pins_desc[3]);

181             request_irq(IOMUX_TO_IRQ(GPIO2_10), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_10", &pins_desc[4]);

182             request_irq(IOMUX_TO_IRQ(GPIO2_11), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_11", &pins_desc[5]);

183             request_irq(IOMUX_TO_IRQ(GPIO2_21), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_21", &pins_desc[6]);

184             //request_irq(IOMUX_TO_IRQ(GPIO3_15), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO3_15", &pins_desc[7]);

185             //request_irq(IOMUX_TO_IRQ(GPIO2_8), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_8", &pins_desc[2]);

186             printk("<0>have setting all pins to gpio interrupt mod by IRQF_TRIGGER_FALLING !\n");

187 

188             break;

189         case version:

190             printk("<0>hello,the version is 0.1.0\n\n");

191             break;

192         default:

193               printk("<0>command error \n");

194             printk("<0>ioctl(fd, (unsigned int)command, (unsigned long) arg;\n");

195             printk("<0>command: <key_input> <version>\n\n");

196             return -1;

197     }

198     return 0;    

199 }

200 static unsigned key_poll(struct file *file,poll_table *wait)

201 {

202     unsigned int mask = 0;

203     //程序不立即睡眠,而是继续等待

204     poll_wait(file,&key_interrupt_wait,wait);

205     //如果按键按下

206     if(ev_press)

207         mask |= POLLIN | POLLRDNORM;

208 

209     return mask;

210 }

211 

212 /* 这个结构是字符设备驱动程序的核心

213  * 当应用程序操作设备文件时所调用的open、read、write等函数,

214  * 最终会调用这个结构中指定的对应函数

215  */

216 static struct file_operations key_fops = {

217     .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */

218     .open   =   key_open,     

219     .read    =    key_read,       

220     .write    =    key_write,       

221     .release=   key_release,

222     .ioctl  =   key_ioctl,    

223     .poll   =   key_poll,

224 };

225     

226 /*

227  * 执行insmod命令时就会调用这个函数 

228  */

229 static int __init  key_irq_init(void)

230 {

231     printk("<0>\nHello,this is %s module!\n\n",Driver_NAME);

232     //register and mknod

233     major = register_chrdev(0,Driver_NAME,&key_fops);

234     drv_class = class_create(THIS_MODULE,Driver_NAME);

235     drv_class_dev = device_create(drv_class,NULL,MKDEV(major,0),NULL,DEVICE_NAME);    /*/dev/key_query*/

236 

237     //set all pins to GPIO mod  ALF5

238     mxc_request_iomux(GPIO2_21, MUX_CONFIG_ALT5);

239     mxc_request_iomux(GPIO3_15, MUX_CONFIG_ALT5);

240       mxc_request_iomux(GPIO2_10, MUX_CONFIG_ALT5);

241        mxc_request_iomux(GPIO2_11, MUX_CONFIG_ALT5);

242     mxc_request_iomux(GPIO2_8, MUX_CONFIG_ALT5);

243     mxc_request_iomux(GPIO2_9, MUX_CONFIG_ALT5);

244     mxc_request_iomux(GPIO2_6, MUX_CONFIG_ALT5);

245     mxc_request_iomux(GPIO2_7, MUX_CONFIG_ALT5);

246     //request IOMUX GPIO

247     gpio_request(IOMUX_TO_GPIO(GPIO2_21), "GPIO2_21");

248      gpio_request(IOMUX_TO_GPIO(GPIO3_15), "GPIO3_15");

249      gpio_request(IOMUX_TO_GPIO(GPIO2_10), "GPIO2_10");

250        gpio_request(IOMUX_TO_GPIO(GPIO2_11), "GPIO2_11");

251     gpio_request(IOMUX_TO_GPIO(GPIO2_8), "GPIO2_8");

252      gpio_request(IOMUX_TO_GPIO(GPIO2_9), "GPIO2_9");

253       gpio_request(IOMUX_TO_GPIO(GPIO2_6), "GPIO2_6");

254     gpio_request(IOMUX_TO_GPIO(GPIO2_7), "GPIO2_7");

255     

256 

257     return 0;

258 }

259 

260 /*

261  * 执行rmmod命令时就会调用这个函数 

262  */

263 static void __exit key_irq_exit(void)

264 {

265     printk("<0>\nGoodbye,%s!\n\n",Driver_NAME);

266 

267     unregister_chrdev(major,Driver_NAME);

268     device_unregister(drv_class_dev);

269     class_destroy(drv_class);

270 

271     /* free gpios */

272     mxc_free_iomux(GPIO2_21, MUX_CONFIG_ALT5);

273     mxc_free_iomux(GPIO3_15, MUX_CONFIG_ALT5);

274     mxc_free_iomux(GPIO2_10, MUX_CONFIG_ALT5);

275     mxc_free_iomux(GPIO2_11, MUX_CONFIG_ALT5);

276     mxc_free_iomux(GPIO2_8, MUX_CONFIG_ALT5);

277     mxc_free_iomux(GPIO2_9, MUX_CONFIG_ALT5);

278     mxc_free_iomux(GPIO2_6, MUX_CONFIG_ALT5);

279     mxc_free_iomux(GPIO2_7, MUX_CONFIG_ALT5);

280 

281     gpio_free(IOMUX_TO_GPIO(GPIO2_21));

282     gpio_free(IOMUX_TO_GPIO(GPIO3_15));

283     gpio_free(IOMUX_TO_GPIO(GPIO2_10));

284     gpio_free(IOMUX_TO_GPIO(GPIO2_11));

285     gpio_free(IOMUX_TO_GPIO(GPIO2_8));

286     gpio_free(IOMUX_TO_GPIO(GPIO2_9));

287     gpio_free(IOMUX_TO_GPIO(GPIO2_6));

288     gpio_free(IOMUX_TO_GPIO(GPIO2_7));

289 

290 }

291 

292 /* 这两行指定驱动程序的初始化函数和卸载函数 */

293 module_init(key_irq_init);

294 module_exit(key_irq_exit);

295 

296 /* 描述驱动程序的一些信息,不是必须的 */

297 MODULE_AUTHOR("Lover雪");

298 MODULE_VERSION("0.1.0");

299 MODULE_DESCRIPTION("IMX257 key Driver");

300 MODULE_LICENSE("GPL");
View Code

 

 

修改应用程序

1.我们首先包含头文件 #include <poll.h>

2.定义结构体

struct pollfd fds[1]; //方括号中为要监控的设备数量

fds[0].fd = fd; //加入要监控的设备描述符

fds[0].events = POLLIN;

20150218【改进Poll定时查询】IMX257实现GPIO-IRQ中断按键获取键值驱动程序

3. 监控的结果是 POLLIN

POLLIN There is data to read.

从帮助得知,一旦时间发送就意思有消息读取,接着,一旦我们poll监控到数据,我们就开始read函数来读取数据。

20150218【改进Poll定时查询】IMX257实现GPIO-IRQ中断按键获取键值驱动程序

 

 

附上修改后的应用程序代码:

 

 1 #include <stdio.h>

 2 #include <stdlib.h>

 3 #include <unistd.h>

 4 #include <sys/types.h>

 5 #include <sys/stat.h>

 6 #include <fcntl.h>

 7 #include <termios.h>

 8 #include <errno.h>

 9 #include <limits.h>

10 #include <asm/ioctls.h>

11 #include <time.h>

12 #include <pthread.h>

13 #include <poll.h>

14 

15 #include "mx257_gpio.h"

16 

17 #define key_input     0

18 #define version       1

19 

20 

21 int main(int argc, char **argv)

22 {

23     int fd;

24     int i=0,cnt=0;

25     unsigned char key_val[1];

26     struct pollfd fds[1];    

27     int ret;

28     fd = open("/dev/key_interrupt",O_RDWR);

29     if(fd < 0){

30         printf("can't open !!!\n");

31     }

32     ioctl(fd,version,NULL);

33     ioctl(fd,key_input,NULL);

34 

35     fds[0].fd = fd;

36     fds[0].events = POLLIN;

37     while(1){

38         ret = poll(fds,1,5000);

39         if(ret == 0)

40             printf("time out\n");

41         else{

42             read(fd,key_val,1);

43             printf("%04d key pressed: 0x%x\n",cnt++,key_val[0]);    

44         }

45     }

46     return 0;

47 }
View Code

 

 

 

 

运行程序:

20150218【改进Poll定时查询】IMX257实现GPIO-IRQ中断按键获取键值驱动程序

 

可以发现,其实程序时不断的在查询,每5秒之内若是没有时间发生则打印time out,若是有时间发生,则立即读取内核空间的键值。

 

既然是不断的查询,那我们来看一下,它是不是很耗费CPU资源呢:

后台运行,使用top命令查看cpu使用率

20150218【改进Poll定时查询】IMX257实现GPIO-IRQ中断按键获取键值驱动程序

 

可以发现,函数在不断的运行,每过5s打印time out

使用top命令,查看cpu资源

20150218【改进Poll定时查询】IMX257实现GPIO-IRQ中断按键获取键值驱动程序

可以发现,虽然这个程序没有使用中断休眠函数,也是在不断的查询,但是使用poll后,cpu几乎不占用。

kill 杀死后台程序

20150218【改进Poll定时查询】IMX257实现GPIO-IRQ中断按键获取键值驱动程序

 

你可能感兴趣的:(IO)