⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 w90p710_keypad.c

📁 Arm7 key driver,w90p710 winbond
💻 C
字号:
#include <linux/init.h>
#include <linux/slab.h>
#include <asm/errno.h>
#include <asm/delay.h>
#include <asm/arch/irqs.h>
#include <linux/mm.h>
#include <linux/poll.h>
#include <linux/module.h>
//#include <linux/jiffies.h>
#include <linux/timer.h>

#include <asm/hardware.h>
#include <asm/io.h>
#include <asm-arm/irq.h>
#include "w90p710_keypad.h"

MODULE_LICENSE("GPL");

//#undef DEBUG
#define	DEBUG
#ifdef DEBUG
#define PDEBUG(fmt, args...) printk( KERN_ALERT "KEY: " fmt, ## args)
#else









#define PDEBUG(fmt, args...)
#endif
#undef DEBUG

#define MAJOR_NUM 192
#define MAX_BUTTON_BUF  16

#define     BUTTON_TIMER_DELAY200MS  (HZ/5)
#define     BUTTON_TIMER_DELAY100MS  (HZ/10)
#define     BUTTON_TIMER_DELAY20MS  (HZ/100)


static void (*buttonEvent)(void);


static unsigned char DEV_NAME[10] = "Keyboard";

static unsigned char KEYBOARD_ARRAY[5][4]={
  {20,19,18,17},
  {16,15,14,13},
  {12,11,10, 9},
  { 8, 7, 6, 5},
  { 4, 3, 2, 1}
};

typedef struct{
  unsigned char row;
  unsigned char col;
}_KEYBOARD_INDEX;

static _KEYBOARD_INDEX keyboard_index;

typedef struct {
   // unsigned int buttonIRQ;
    unsigned char buf[MAX_BUTTON_BUF];
    unsigned int head,tail;
    wait_queue_head_t wq;
}_BUTTON_DEV;

static _BUTTON_DEV buttondev;

#define BUF_HEAD    (buttondev.buf[buttondev.head])
#define BUF_TAIL    (buttondev.buf[buttondev.tail])
#define INCBUF(x,mod)   ((++(x)) & ((mod)-1))

static unsigned char buttonRead(void);
static unsigned char wakeup_flag=0;
static unsigned char timer_counter=0;
static unsigned char counter=0;
static unsigned char key_16=0;
//static int button_irq = 0;
static struct timer_list timer;


static unsigned char buttonRead(void)
{
    unsigned char button_ret;
    button_ret = BUF_TAIL;
    buttondev.tail = INCBUF(buttondev.tail,MAX_BUTTON_BUF);
    return button_ret;
}

static void buttonEvent_dummy(void) {}

static void buttonEvent_1(void)
{
  unsigned char k=9;
  unsigned int temp;

  while(k!=4)
  {
    writel(readl(REG_GPIO_DATAOUT2)|0x3E0,REG_GPIO_DATAOUT2);
    writel(readl(REG_GPIO_DATAOUT2)&(~(0x1<<(k--))),REG_GPIO_DATAOUT2);

    temp = readl(REG_GPIO_DATAIN2) & 0x1E;
    if(temp != 0x1E)
    {
      keyboard_index.row = k-4;
     // PDEBUG("keyboard_index.row =%d,keyboard_index.col = %d\n",keyboard_index.row,keyboard_index.col);
      if(keyboard_index.row>4)
        keyboard_index.row = 0;
      if(keyboard_index.col>3)
        keyboard_index.col = 0;
      if(KEYBOARD_ARRAY[keyboard_index.row][keyboard_index.col] != 19)
      {
     //   PDEBUG("other key!\n");
        BUF_HEAD = KEYBOARD_ARRAY[keyboard_index.row][keyboard_index.col];
        buttondev.head = INCBUF(buttondev.head,MAX_BUTTON_BUF);
        wakeup_flag=1;

        wake_up_interruptible(&(buttondev.wq));
       // del_timer(&timer);
      }
      else
      {

        PDEBUG("counter = %d,key_16=%d\n",counter,key_16);
        key_16 = 1;
        counter++;
        if( !timer_counter )
        {
          timer_counter = 1;
          timer.expires =  jiffies + BUTTON_TIMER_DELAY200MS;
          //  PDEBUG("button_Event1 :add_timer timer_counter=%d\n",++timer_counter);
          add_timer(&timer);
        }

        if(counter>5)
        {
          key_16 = 0;
          counter = 0;
           BUF_HEAD = 20;
          buttondev.head = INCBUF(buttondev.head,MAX_BUTTON_BUF);
          wakeup_flag=1;

           wake_up_interruptible(&(buttondev.wq));
          //   PDEBUG("button_Event1 :del_timer timer_counter=%d\n",--timer_counter);
          if( timer_counter )
          {
            timer_counter = 0;
            del_timer(&timer);
          }

        }
      }

      break;
    }

  }
  writel(readl(REG_GPIO_DATAOUT2) & 0xFFFFFC1F,REG_GPIO_DATAOUT2); //H0~H4 output Low
}

static int button_down(void)
{

  unsigned int temp;

  temp = readl(REG_GPIO_DATAIN2) & 0x1E;

  if(temp != 0x1E)
  {
    //keyboard_index.col = (~(temp>>1) & 0xf);
    switch(temp)
    {
      case 0x1C: keyboard_index.col = 0; break;
      case 0x1A: keyboard_index.col = 1; break;
      case 0x16: keyboard_index.col = 2; break;
      case 0x0E: keyboard_index.col = 3; break;
      default : break;
    }

     return 1;
  }

  return 0;
}


static void timer_handler(unsigned long data)
{
  PDEBUG("timer_handler()\n");
   // PDEBUG("timer_handler :del timer timer_counter=%d\n",--timer_counter);
   if( timer_counter )
   {
     timer_counter = 0;
     del_timer(&timer);
   }

  if(button_down())
  {
    PDEBUG(" timer_handler : button down\n");
    buttonEvent();
  }
  else if(key_16)
  {
  //  PDEBUG("timer_handler in else :del timer timer_counter=%d\n",--timer_counter);
  //  del_timer(&timer);
    counter = 0;
    key_16 =0;
     BUF_HEAD = 19;
     buttondev.head = INCBUF(buttondev.head,MAX_BUTTON_BUF);
     wakeup_flag=1;
     wake_up_interruptible(&(buttondev.wq));


  }
 // del_timer(&timer);
    enable_irq(INT_nIRQ2);
}

static void keyboard_irq(int irq, void *dev_id, struct pt_regs *regs)
{


  int i;
	disable_irq_nosync(INT_nIRQ2);

//  printk("In keyboard_irq!\n");
  if((readl(0xFFF09000) & 0x1) == 0){
      counter = 0;
      if( !timer_counter )
      {
        timer_counter = 1;
        timer.expires =  jiffies + BUTTON_TIMER_DELAY100MS;
        //printk("clear irq when in keyboard irq  1 = 0x%x\n",readl(0xFFF8212C));
  		  writel(readl(0xFFF8212C) | (1<<4),0xFFF8212C);
        add_timer(&timer);
      }
  }
  else
  {
  PDEBUG("clear the isr sorce!\n");
    for(i=0;i<50000;i++) ;
      *(unsigned int volatile *)(0xfff00024) = 0;
  }
   enable_irq(INT_nIRQ2);
	return;

}

static int keyboard_open(struct inode* i,struct file* f)
{
  int result;

	MOD_INC_USE_COUNT;

   buttondev.head=buttondev.tail=0;
   buttonEvent = buttonEvent_1;

  writel( (readl(REG_AIC_SCR4) & 0xFFFFFF3F) | 0x80 ,REG_AIC_SCR4);  //negative edge
 // writel( (readl(REG_AIC_SCR4) & 0xFFFFFF3F)  ,REG_AIC_SCR4);  //low
//  writel((readl(REG_AIC_IMR) | 0x10) ,REG_AIC_IMR);           //mask bit
  enable_irq(INT_nIRQ2);

	result = request_irq(INT_nIRQ2,keyboard_irq,0,DEV_NAME,NULL);
	if(result)
		printk("register the keyboard_irq failed!\n");
//  else
//    printk("register the keyboard_irq successfull!\n");

	return 0;

}

static int keyboard_close(struct inode *inode,struct file *filp)
{
	MOD_DEC_USE_COUNT;
  buttonEvent=buttonEvent_dummy;
	free_irq(INT_nIRQ2,NULL);
	return 0;
}




static ssize_t keyboard_read(struct file *filp, char *buff, size_t read_mode, loff_t *offp)
{
  static unsigned char button_ret;
 retry:
    PDEBUG("keyboard_read: retry start\n");
    if(buttondev.head!=buttondev.tail) {
    button_ret = buttonRead();
    copy_to_user(buff,(char *)&button_ret,sizeof(unsigned char));
    PDEBUG("keyboard_read: the button_ret is 0x%x\n",button_ret);
  //  timer_counter = 0;
    return sizeof(unsigned char);
    }
    else
    {
      if(filp->f_flags & O_NONBLOCK)
        return -EAGAIN;
      PDEBUG("keyboard_read: sleep\n");

    //interruptible_sleep_on(&(buttondev.wq));//为安全起见,
      wait_event_interruptible(buttondev.wq,wakeup_flag);
      wakeup_flag=0;
      PDEBUG("keyboard_read: sleep_after\n");
      if(signal_pending(current))
      {
        printk("rturn -ERESTARTSYS\n");
        return -ERESTARTSYS;
      }
      goto retry;
     }

    return sizeof(unsigned char);

}


static struct file_operations keyboard_fops =
{
	owner: THIS_MODULE,
	open: keyboard_open,
	read: keyboard_read,
	release: keyboard_close,
};

static int __init keyboard_710_reg(void)
{
	int result;


  buttonEvent=buttonEvent_dummy;

	result = register_chrdev(MAJOR_NUM,DEV_NAME,&keyboard_fops);
	if(result<0)
	{
		printk("initial the device error!\n");
		return (result);
	}

  writel(readl(REG_GPIO_CFG2) & 0x00000001,REG_GPIO_CFG2);        //GP43~GP51 in I/O mode
  writel((readl(REG_GPIO_DIR2) & 0xFFFFFFE1) | 0x3E0,REG_GPIO_DIR2); //GP51~GP47 OUTPUT,GP46~GP43 INPUT
  writel(readl(REG_GPIO_DATAOUT2) & 0xFFFFFC1F,REG_GPIO_DATAOUT2); //H0~H4 output Low

  writel((readl(REG_GPIO_CFG5) & 0xF3FFFFFF) | 0x04000000 ,REG_GPIO_CFG5);   //nIRQ2

  init_waitqueue_head(&(buttondev.wq));

  init_timer(&timer);
  timer.function = timer_handler;

	printk("W90P710 POS Keyboard initialized successful\n");

	return (result);

}

static void keyboard_710_exit(void)
{
	unregister_chrdev(MAJOR_NUM,DEV_NAME);

	return;
}

module_init(keyboard_710_reg);
module_exit(keyboard_710_exit);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -