S3C2440独立键盘Linux设备驱动

/****************************************************************************************
*Name:  keyboard.c
*Author:  Ma Dongpeng<madongpeng@hrbeu.edu.cn>
*Time:  2011-02-17 14:08:10
*Version: 1.0.0
*Description: keyborad driver for linux2.6.25
*****************************************************************************************/

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/device.h>
#include <linux/poll.h>
#include <linux/interrupt.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/irq.h>
#include <linux/wait.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>

#define DEVICE_NAME  "keyboard" // 加载模式后,执行”cat /proc/devices”命令看到的设备名称
#define KEYBOARD_MAJOR  252   // 主设备号
#define KEY_NUM    4   //按键数目
#define KEYSTATUS_DOWNX  0
#define KEYSTATUS_UP   1
#define KEY_TIMER_DELAY  15   //以ms为单位,表示延时15ms
#define KEY_TIMER_DELAY1 100
#define KEY_TIMER_DELAY2 20

static int keyboard_major=KEYBOARD_MAJOR;

struct key_irq_desc
{
 int irq;        //中断号
 int pin;        //中断引脚
 int pin_setting;      //设置gpio功能
 int number;
 char *name;
};

// 用来指定按键所用的外部中断引脚及中断触发方式, 名字
static struct key_irq_desc key_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 */
};

struct key_dev
{
 struct cdev cdev;
 char key_values[KEY_NUM];        //记录键值为1表示对应的按键被按下
 unsigned int key_status[KEY_NUM];     //记录按键状态
 wait_queue_head_t key_waitq;       //等待队列
 int key_values_flag;         //记录是否有任何一个按键被按下
};
struct key_dev *key_devp;

static struct timer_list key_timer[KEY_NUM];     //按键的定时器

static char __initdata info[] = "******************keyborad Driver*****************\n";
static struct class *key_class;

/******************************************************************************************
*键盘中断处理程序
*******************************************************************************************/
static irqreturn_t key_interrupt(int irq, void *dev_id)
{
 struct key_irq_desc *key_irqs = (struct key_irq_desc *)dev_id;
 disable_irq(key_irqs->irq);       //关中断进入查询模式

key_devp->key_status[key_irqs->number]=KEYSTATUS_DOWNX;
 key_timer[key_irqs->number].expires=jiffies+KEY_TIMER_DELAY;
 add_timer(&key_timer[key_irqs->number]);    //启动定时器

return IRQ_RETVAL(IRQ_HANDLED);
}

/******************************************************************************************
*处理键盘事件,在key_timer_handler中被调用,记录键值唤醒等待队列
*******************************************************************************************/
static void key_event(int num)
{
 //printk(KERN_ALERT "num=%d\n",num);
 key_devp->key_values[num]=1;
 key_devp->key_values_flag=1;
 wake_up_interruptible(&key_devp->key_waitq);      //唤醒等待队列
}

/******************************************************************************************
*定时器中断处理程序
*******************************************************************************************/
static void key_timer_handler(unsigned long data)
{
 struct key_irq_desc *key_irqs = (struct key_irq_desc *)data;
 if(s3c2410_gpio_getpin(key_irqs->pin)==KEYSTATUS_DOWNX)    //键盘仍然属于按下状态
 {
  if(key_devp->key_status[key_irqs->number]==KEYSTATUS_DOWNX)
  {
   key_devp->key_status[key_irqs->number]=KEYSTATUS_UP;
   key_timer[key_irqs->number].expires=jiffies+KEY_TIMER_DELAY1;//准备进入连按模式,延时较长
   key_event(key_irqs->number);     //记录键值唤醒等待队列
   add_timer(&key_timer[key_irqs->number]);  //启动定时器
  }
  else
  {
   key_timer[key_irqs->number].expires=jiffies+KEY_TIMER_DELAY2;//连按模式,延时较短
   key_event(key_irqs->number);     //记录键值唤醒等待队列
   add_timer(&key_timer[key_irqs->number]);  //启动定时器  
  }
 }
 else             //键盘已经抬起
 {
  key_devp->key_status[key_irqs->number]=KEYSTATUS_UP;
  enable_irq(key_irqs->irq);
 }
}

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwsyxy.html