天嵌 ARM开发社区

 找回密码
 注册
查看: 3189|回复: 9

关于按键驱动的问题

[复制链接]
记事本 发表于 2011-12-25 11:29:06 | 显示全部楼层 |阅读模式
EmbedSky-irq.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#define DEVICE_NAME     "IRQ-Test"
struct button_irq_desc {
    int irq;//按键对应的中断号
    int pin;//按键所对应的GPIO脚
    int pin_setting;//
    int number;//定义键值 以传递给应用层
    char *name; //按键名称
};
#if !defined (CONFIG_SKY2440_IRQ_TEST)
static struct button_irq_desc button_irqs [] = {
{IRQ_EINT1, S3C2410_GPF1, S3C2410_GPF1_EINT1, 0, "KEY1"}, /* K1 */
{IRQ_EINT4, S3C2410_GPF4, S3C2410_GPF4_EINT4, 1, "KEY2"}, /* K2 */
{IRQ_EINT2, S3C2410_GPF2, S3C2410_GPF2_EINT2, 2, "KEY3"}, /* K3 */
{IRQ_EINT0, S3C2410_GPF0, S3C2410_GPF0_EINT0, 3, "KEY4"}, /* K4 */
};
#else
static struct button_irq_desc button_irqs [] = {
{IRQ_EINT9, S3C2410_GPG1, S3C2410_GPG1_EINT9, 0, "KEY1"}, /* K1 */
{IRQ_EINT11, S3C2410_GPG3, S3C2410_GPG3_EINT11, 1, "KEY2"}, /* K2 */
{IRQ_EINT2, S3C2410_GPF2, S3C2410_GPF2_EINT2, 2, "KEY3"}, /* K3 */
{IRQ_EINT0, S3C2410_GPF0, S3C2410_GPF0_EINT0, 3, "KEY4"}, /* K4 */
};
#endif
static volatile char key_values [] = {'0', '0', '0', '0'};
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
static volatile int ev_press = 0;//没有按键按下

static irqreturn_t irq_interrupt(int irq, void *dev_id)
{
struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;
int down;
down = !s3c2410_gpio_getpin(button_irqs->pin);//读取dat寄存器的值,down=1表示有键按下
if (down != (key_values[button_irqs->number] & 1))
{
  key_values[button_irqs->number] = '0' + down;
  ev_press = 1;
  wake_up_interruptible(&button_waitq);
}
return IRQ_RETVAL(IRQ_HANDLED);
}

static int tq2440_irq_open(struct inode *inode, struct file *file)
{
int i;
int err = 0;
for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++)
{
  if (button_irqs.irq < 0)
   continue;
  err = request_irq(button_irqs.irq, irq_interrupt, IRQ_TYPE_EDGE_BOTH,
                          button_irqs.name, (void *)&button_irqs);//申请中断四个终端共用一个中断处理程序:中断号,中断处理函数,双沿触发
  if (err)
   break;
}
if (err)
{
  i--;
  for (; i >= 0; i--)
  {
   if (button_irqs.irq < 0)
    continue;
   disable_irq(button_irqs.irq);
   free_irq(button_irqs.irq, (void *)&button_irqs);
  }
  return -EBUSY;
}
ev_press = 1;
return 0;
}

static int tq2440_irq_close(struct inode *inode, struct file *file)
{
int i;
for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++)
{
  if (button_irqs.irq < 0)
   continue;
  free_irq(button_irqs.irq, (void *)&button_irqs);
}
return 0;
}

static int tq2440_irq_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
{
unsigned long err;
if (!ev_press)
{
  if (filp->f_flags & O_NONBLOCK)//默认为阻塞方式处理
   return -EAGAIN;
  else
   wait_event_interruptible(button_waitq, ev_press);
}//执行到此处ev_press值为1,有按键按下了;
ev_press = 0;
err = copy_to_user(buff, (const void *)key_values, min(sizeof(key_values), count));//把按键键值拷贝给用户空间
return err ? -EFAULT : min(sizeof(key_values), count);
}
static unsigned int tq2440_irq_poll( struct file *file, struct poll_table_struct *wait)
{
unsigned int mask = 0;
poll_wait(file, &button_waitq, wait);
if (ev_press)
  mask |= POLLIN | POLLRDNORM;
return mask;
}

static struct file_operations dev_fops = {
.owner =   THIS_MODULE,
.open =   tq2440_irq_open,
.release =   tq2440_irq_close,
.read =   tq2440_irq_read,
.poll =   tq2440_irq_poll,//对应于select系统调用,多路监控
};
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,//次设备号
.name = DEVICE_NAME,
.fops = &dev_fops,
};
static int __init dev_init(void)
{
int ret;
ret = misc_register(&misc);//注册混杂设备,主设备号为10;
printk (DEVICE_NAME" initialized\n");
return ret;
}
static void __exit dev_exit(void)
{
misc_deregister(&misc);
}
module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("www.embedsky.net");
MODULE_DESCRIPTION("IRQ Test for EmbedSky SKY2440/TQ2440 Board");
自己写的测试程序app-button.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
int main(void)
{
int buttons_fd;
int key_value;
buttons_fd = open("/dev/IRQ-Test", 0);
if (buttons_fd < 0) {
  perror("open device buttons");
  exit(1);
}
for (;;) {
  fd_set rds;
  int ret;
  FD_ZERO(&rds);
  FD_SET(buttons_fd, &rds);
  ret = select(buttons_fd + 1, &rds, NULL, NULL, NULL);
  if (ret < 0) {
   perror("select");
   exit(1);
  }
  if (ret == 0) {
   printf("Timeout.\n");
  } else if (FD_ISSET(buttons_fd, &rds)) {
   int ret = read(buttons_fd, &key_value, sizeof key_value);
   if (ret != sizeof key_value) {
    if (errno != EAGAIN)
     perror("read buttons\n");
    continue;
   } else {
    printf("buttons_value: %d\n", key_value+1);
   }
   
  }
}
close(buttons_fd);
return 0;
}
程序运行之后截图入下:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

评分

参与人数 1 +8 收起 理由
milan222m + 8 赞一个!

查看全部评分

 楼主| 记事本 发表于 2011-12-25 11:30:23 | 显示全部楼层
谁帮忙给看看 到底是测试程序的问题还是驱动的问题呢?
亚瑟王 发表于 2011-12-30 11:55:27 | 显示全部楼层
应用程序的问题:驱动中read函数传递出来的一个数组,而你的应用程序读的时候缺采用的是一个变量。最后的结果就是你传递到read里面的变量保存的应该是驱动的read里面传出来的数组的首地址。
 楼主| 记事本 发表于 2011-12-31 15:18:11 | 显示全部楼层
亚瑟王 发表于 2011-12-30 11:55
应用程序的问题:驱动中read函数传递出来的一个数组,而你的应用程序读的时候缺采用的是一个变量。最后的结 ...

版主 我就是不太明白 驱动程序里把键值送到了buff里,应用程序是怎么拿到的呢?应用程序是从buttons_fd指定的文件里读取键值 两者是怎么关联的呢?
 楼主| 记事本 发表于 2011-12-31 15:26:03 | 显示全部楼层
亚瑟王 发表于 2011-12-30 11:55
应用程序的问题:驱动中read函数传递出来的一个数组,而你的应用程序读的时候缺采用的是一个变量。最后的结 ...

按照你的提示我改了下应用程序 就成了下面的样子了!
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
int main(void)
{
int buttons_fd;
int key_values[4];
buttons_fd = open("/dev/IRQ-Test", 0);
if (buttons_fd < 0) {
  perror("open device buttons");
  exit(1);
}
for (;;) {
  fd_set rds;
  int ret;
  FD_ZERO(&rds);
  FD_SET(buttons_fd, &rds);
  ret = select(buttons_fd + 1, &rds, NULL, NULL, NULL);
  if (ret < 0) {
   perror("select");
   exit(1);
  }
  if (ret == 0) {
   printf("Timeout.\n");
  } else if (FD_ISSET(buttons_fd, &rds)) {
   int ret = read(buttons_fd, key_values, sizeof (key_values));
   if (ret != sizeof (key_values)) {
    if (errno != EAGAIN)
     perror("read buttons\n");
    continue;
   } else {
    printf("buttons_value: %d\n", key_value+1);
   }
   
  }
}
close(buttons_fd);
return 0;
}


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
亚瑟王 发表于 2012-1-10 18:18:18 | 显示全部楼层
应用程序的read函数就是调用的驱动的read,他们这样联系起来的。
老铁 发表于 2012-4-19 10:10:20 | 显示全部楼层
亚瑟王 发表于 2012-1-10 18:18
应用程序的read函数就是调用的驱动的read,他们这样联系起来的。

我的开发板里没有这个IRQ-Test设备啊?怎么回事啊?
亚瑟王 发表于 2012-4-19 14:00:58 | 显示全部楼层
老铁 发表于 2012-4-19 10:10
我的开发板里没有这个IRQ-Test设备啊?怎么回事啊?

亲,你烧写的什么内核?
老铁 发表于 2012-4-19 15:06:58 | 显示全部楼层
本帖最后由 老铁 于 2012-4-19 15:07 编辑
亚瑟王 发表于 2012-4-19 14:00
亲,你烧写的什么内核?

谢谢啊,解决了,我用的是2.6.30.4的内核,配置单上把那个配置为【M】了,我改成了【*】就可以了
亚瑟王 发表于 2012-4-21 13:14:14 | 显示全部楼层
老铁 发表于 2012-4-19 15:06
谢谢啊,解决了,我用的是2.6.30.4的内核,配置单上把那个配置为【M】了,我改成了【*】就可以了

如果你配置为M,需要用make modules编译出对应的驱动模块(名称为*.ko,*号为具体名称),然后在系统启动后加载该ko文件。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

i.MX8系列ARM cortex A53 M4 工控板上一条 /1 下一条

Archiver|手机版|小黑屋|天嵌 嵌入式开发社区 ( 粤ICP备11094220号-2 )

GMT+8, 2024-6-11 04:36 , Processed in 1.062500 second(s), 23 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表