首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 嵌入开发 > 驱动开发 >

linux按键设备驱动解决方法

2013-04-09 
linux按键设备驱动最近我在写字符设备驱动程序,前两天想自己动手写个按键的驱动程序,但是结果并不是我所期

linux按键设备驱动
最近我在写字符设备驱动程序,前两天想自己动手写个按键的驱动程序,但是结果并不是我所期待的,希望您能帮我一下,谢谢啦!
程序源代码如下:
#include <linux/module.h> 
#include <linux/types.h> 
#include <linux/fs.h> 
#include <linux/errno.h> 
#include <linux/mm.h> 
#include <linux/sched.h> 
#include <linux/init.h> 
#include <linux/cdev.h> 
#include <asm/io.h> 
#include <asm/system.h> 
#include <asm/uaccess.h> 
#include <linux/semaphore.h>
#include <linux/poll.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
 
#define count 1
#define KEY_NUM 4
#define KEY_UP 1
#define MYKEY_DOWN 0
 
typedef unsigned char key_ret;
 
static  struct kbd_dev
{
 unsigned int keystatus[KEY_NUM]; /* 按键状态,但是我还没有使用它 */
 struct cdev *cdev;
};
 
static struct key_info
{
 int irq_no;      /* 中断号 */
 char gpio_port[4];    /* 端口号 */
 int key_no;      /* 键值 */
};
 
static struct key_info key_info_tab[4] = 
{
 {IRQ_EINT0, "GPF1", 1}, 
 {IRQ_EINT1, "GPF2", 2}, 
 {IRQ_EINT2, "GPF3", 3},
 {IRQ_EINT4, "GPF4", 4},
};
 
static int major = 280;
static int minor = 0;
static struct kbd_dev *kbd_devp = NULL;
static struct timer_list key_timer[KEY_NUM]; /* 四个内核定时器,用于消抖 */
volatile unsigned long *gpfcon;
 
static irqreturn_t key_irq_handler(int irq, void *dev_id)

 printk("handle with irq : %d,irq_no:%d\n",irq,*(int *)dev_id);
 
 /* 禁止该中断 */
 disable_irq_nosync(irq);
 printk("disbale_irq_nosync :%d\n",irq);
 
 /* 设置1s后处理定时处理函数 */
 key_timer[*(int *)dev_id - 1].expires = jiffies + HZ;
 add_timer(&key_timer[*(int *)dev_id - 1]);
 
 return IRQ_HANDLED;
}
 
static void timer_delay(unsigned long which)
{
 printk("the irq_no:%d down\n",which);
 /* 使能对应的中断 */
 enable_irq(which);
}
 
static ssize_t kbd_read (struct file *filp, char __user *user, size_t size, loff_t *off)
{
 return 0;
}

static ssize_t kbd_write (struct file *filp, const char __user *user, size_t size, loff_t *off)
{
 return 0;
}

static int kbd_open(struct inode *inode, struct file *filp)
{
 return 0;
}

static int kbd_release (struct inode *inode, struct file *filp)
{
 return 0;
}
 
static struct file_operations kbd_fops = 
{
 .owner = THIS_MODULE,
 .open = kbd_open,
 .release = kbd_release,
 .read = kbd_read,
 .write = kbd_write,


};
 
static int kbd_init(void)
{
 int devno;    /* 设备号 */
 int result,err;
 int i;
 devno = MKDEV(major,minor);
 if(major)         /* 如果主设备号等于0,则动态分配设备号 */
  result = register_chrdev_region(devno, count, "kbd");
 else
 {
  result = alloc_chrdev_region(&devno, 0, count, "kbd");
  MAJOR(devno);
 }
 if(result)       /* 如果分配失败,则返回 */
 {
  printk("alloc char device failure!\n");
  return result;
 }
 
 /* 为设备结构分配内存空间 */
 kbd_devp = kmalloc(sizeof(struct kbd_dev),GFP_KERNEL);
 
if(!kbd_devp)
 {
  printk("alloc memory failuere!\n");
  return -ENOMEM;
  goto unregister;
 }
 /* 为分配的设备结构的内存空间进行初始化 */
 memset(kbd_devp, 0, sizeof(struct kbd_dev));
 kbd_devp->cdev = cdev_alloc();   /* 分配一个字符设备结构给kbd_devp->dev */
 cdev_init(kbd_devp->cdev, &kbd_fops);  /* 初始化字符设备结构 */
 kbd_devp->cdev->owner= THIS_MODULE;
 err = cdev_add(kbd_devp->cdev, devno, count);  /* 向系统添加字符设备结构 */
 if(err == 0)
printk("cdev_add success!\n");
 
gpfcon = ioremap(0x56000050,4);  /* 映射按键对应的物理地址 */
 *gpfcon = 0x22a;                 /* 设置控制按键的端口为中断 */
 
 for(i = 0; i < KEY_NUM; i++)
 {
  /* 注册这四个按键中断,低电平触发,给中断处理程序传入键值 */
  if(request_irq(key_info_tab[i].irq_no, key_irq_handler, IRQ_TYPE_LEVEL_LOW, 
      key_info_tab[i].gpio_port, &key_info_tab[i].key_no))
  {
   printk("can't get irq:%i\n",key_info_tab[i].irq_no);
   return 0;
  }
  kbd_devp->keystatus[i] = KEY_UP;   /* 设置按键状态为松开 */
   /* 初始化四个内核定时器,给定时器处理函数传入中断号 */
  setup_timer(&key_timer[i], timer_delay, key_info_tab[i].irq_no);
 }
 
 printk("device add success!\n");
 return 0;
 
 unregister:
  unregister_chrdev_region(MKDEV(major,minor), count);
  return result;
  
}
 
static void kbd_exit(void)
{
 int i;
 for(i = 0; i < KEY_NUM; i++)
 {
  free_irq(key_info_tab[i].irq_no, &key_info_tab[i].key_no);
 }
 iounmap(gpfcon);
 
 cdev_del(kbd_devp->cdev);
 kfree(kbd_devp->cdev);
 kfree(kbd_devp);
 unregister_chrdev_region(MKDEV(major,minor), count);
 printk("device remove success!\n");
}
 
module_init(kbd_init);
module_exit(kbd_exit);
MODULE_LICENSE("GPL");
 
我在我的开发板上使用# insmod key.ko 插入模块,使用命令# mknod /dev/kbd c 280 0创建设备节点,然后就直接按开发板的按键,串口上的输出是(这只是一个按键的信息,其他三个按键的输出信息与这个类似):
handle with irq : 16,irq_no:1
    disbale_irq_nosync :16


    the irq_no:16 down
    handle with irq : 16,irq_no:1
    disbale_irq_nosync :16
    the irq_no:16 down
其中第1、2行同时输出的,然后等待1s,再输出3、4、5行,再等待1s,输出第6行。
我的疑问是:
输出1、2行之后,当前中断已经被屏蔽掉,直到1s后进入定时处理函数恢复中断,此中断才可以继续使用,我按键只按了一下,应该只显示前三行的信息,后三行的信息我不知道怎么来的。
我使用命令:
# cat /proc/devices
输出(其他信息省略掉了,一下类似):
Character devices:
280 kbd
 
# lsmod
   Not tainted
    key 3204 0 - Live 0xbf067000
 
# cat /proc/interrupts
 CPU0
 16:         18    s3c-ext0  GPF1
 17:         10    s3c-ext0  GPF2
 18:          2    s3c-ext0  GPF3
 48:          2     s3c-ext  GPF4

[解决办法]
原理图呢?谁知道你这是什么按键啊
[解决办法]
这应该是发生了抖动的问题,将
key_timer[*(int *)dev_id - 1].expires = jiffies + HZ;
add_timer(&key_timer[*(int *)dev_id - 1]);
放到
disable_irq_nosync(irq);
printk("disbale_irq_nosync :%d\n",irq);
前面试试看
[解决办法]
按下,中断一次,弹起,同样中断一次
可以这样试试: 按下不放手,过5或者10秒钟再放手,看看输出信息。

热点排行