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

📄 keydrv3.c

📁 在UCLIINUX环境下开发的自定义4*4键盘驱动,象手机键盘那样实现键盘的基本功能
💻 C
字号:
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
#endif

#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT


#include <linux/interrupt.h>

//#include <linux/module.h>

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/ioport.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/fcntl.h>
#include <linux/errno.h>
#include <linux/timer.h>

#include <asm/system.h>
#include <linux/delay.h>


#include <asm/irq.h>


#include "keydrv.h"

static KBD_DEV kbddev;
static void (*kbdEvent)(void);
static struct timer_list kbd_timer;
unsigned long last_down_time;

static int major=253;
char key_name[]="keydrv";
u_char key;
u_char last_raw_code = '1';       //  for later extention.
u_char CAP_FLAG = CAP_OFF;
u_char index = 0;



static u_char table[4][16]={'1' ,'2' ,'3' ,'<',
                          '4' ,'5' ,'6' ,'>',
                          '7' ,'8' ,'9' ,'^',
                          '*' ,'0' ,'#' ,'$',

                          'a' ,'b' ,'c' ,'<',
                          'd' ,'e' ,'f' ,'>',
                          'g' ,'h' ,'i' ,'^',
                          'j' ,'k' ,'l' ,'$', 

                          'm' ,'n' ,'o' ,'<',
                          'p' ,'q' ,'r' ,'>',
                          's' ,'t' ,'u' ,'^',
                          'v' ,'w' ,'x' ,'$',

                          'y' ,'z' ,',' ,'<',
                          '.' ,'!' ,'?' ,'>',
                          '(' ,')' ,'+' ,'^',
                          '-' ,'*' ,'/' ,'$' };
                          
                          
 // f_ops mapping.
static struct file_operations key_fops=
{
//  owner: THIS_MODULE,
  read:  (void(*))key_read,
  open: (void(*))key_open,
  release: (void(*))key_release,
};

// application specific function.

void kbdEvent_dummy(void)
{}

static u_char decode_key(void)
{
  u_char i,raw_code,col_id=0 ,row_id=0 ,tmp,row_mask[4]={0xF7,0xFb,0xFd,0xfe};     //mask=0x0f ;
  // scan coloums  ,  here col to output : high 4 bits,  raw to input : low 4 bits . 
//  printk("<1>start to decode the key..\n");
//  tmp = KEY_PORT_COLS&0x0f;
  tmp = readl(PIO_KEY_IN_BASE) & 0x0f ;
  printk("<1>the col input data is 0x%x\n",tmp);
  if(tmp==0x0e)
    col_id=0;
  else if(tmp==0x0d)
          col_id=1;
       else if(tmp==0x0b)
              col_id=2;
            else if(tmp==0x07)
                   col_id=3;
  printk("<1>the col is %d\n",col_id);

  for (i=0;i<4;i++)
  {
     writel(row_mask[3-i], PIO_KEY_OUT_BASE);
     if(ISKBD_DOWN()){
       printk("<1>get the row: %d\n",i);                         //(KEY_PORT_COLS&mask)!=0x0f){
       row_id=i;                // if the col input is also have signal, then get the col
       break;
     }
     if(i==3)
       printk("<1>scan error!\n");
  }   
  printk("<1>the row is %d\n",row_id);


//  printk("<1>again we set rows to low back.\n");
//  KEY_PORT_ROWS = 0x00;     // we must set alls rows to low in plain time.
  writel(0, PIO_KEY_OUT_BASE);

  raw_code=KEY_MAX_COLS*row_id+col_id;       //    raw_code is  0 -> 15
  printk("<1>we get the raw_code: %d\n",raw_code);
           //   '>', '<' , to select the talbe .   
           //
          //        inserted to data buf.   
 
  printk("<1>now the s_talbe is: %d\n\n",s_table);
                               
                               
  //  to get the index of the talbe.                             
  if(row_code==last_row_code && row_id <=3 && col_id<=3 && row_code!=1)
	{
		if(jiffies < (last_down_time + KBD_SWIFT_TIME))
		{
			if(index==3)
				index = 0;
			else
			  index++
		}
	}	  	 	                               
  else
  	index = 0;                             
  	                            
  last_row_code = row_code;                                                                 
  if(raw_code==12)
       CAP_FLAG = ~CAP_FLAG ;
  if(row_id <=3 && col_id<=3 && row_code!=1)     
    return (CAP_FLAG ? (table[index][raw_code]-32):table[index][raw_code]) ;
  else
    return table[index][raw_code];
}  	     
   

static u_char readbuf(void)
{
        u_char ret;
        ret = BUF_TAIL;
        kbddev.tail = INCBUF(kbddev.tail,MAX_KBD_BUF);
 //       printk("<1>tail increased! now the pos is:%d\n",kbddev.tail);
        return ret;
}




static int __init keydrv_init_module(void)
{
  int retv;
 
/* define a interrupt number here

such as in arm: set_external_irq(IRQ_KBD, EXT_LOWLEVEL,GPIO_PULLUP_EN);
 */
  kbdEvent = kbdEvent_dummy;
  retv=register_chrdev(major,key_name,&key_fops);
  if(retv<0)
    {
      printk("<1>register fail!\n");
      return retv;
    }
  if(major==0)
       major=retv;

/*
//  Enable interrupt

  retv = request_irq(PIO_KEY_INT_IRQ,key_interrupt,SA_INTERRUPT,key_name,key_interrupt);
  
  printk("request_irq done, you can use open to see the irq list ifo..\n");
*/
  if(retv<0)
    return retv;
  kbddev.head = kbddev.tail = 0;
  kbddev.kbdStatus = KEYSTATUS_UP;
  init_waitqueue_head(&(kbddev.wq));
  init_timer(&kbd_timer);
  kbd_timer.function = kbd_timer_handler;
  printk("<1>register keydrv seccuss major_key is : %d\n",major);
  return 0;
}

static void __exit keydrv_cleanup(void)
{
   int retv;
   retv=unregister_chrdev(major,key_name);
   if(retv<0)
      {
         printk("<1>unreginster fail!\n");
         return;
      }
   printk("<1>keydrv:good_bye!\n");
}


static int key_open(struct inode *inode,struct file *filp)
{
 writel(0, PIO_KEY_OUT_BASE);
// KEY_PORT_ROWS = 0x00;      //  we set all rows to low 
// printk("<1>rows is set to 0x07,so should just a line effect\n");
// printk("<1>rows have set to ox00\n");
 kbd_timer.expires = jiffies + KBD_TIMER_DELAY;   // 100ms
 add_timer(&kbd_timer);
 kbddev.head = kbddev.tail = 0;
 kbdEvent = kbdEvent_raw;
 MOD_INC_USE_COUNT;
// printk("<1>open key dev\n");
 return 0;
}


static int key_release(struct inode *inode,struct file *filp)
{
 kbdEvent = kbdEvent_dummy;
 MOD_DEC_USE_COUNT;
 printk("<1>key dev released!\n");
 return 0;
}

static ssize_t key_read(struct file *filp,char *buffer,size_t count,loff_t *ppos)
{
        u_char ret;

retry:
//  printk("<1>IN DRIVER: now entering read...\n");
  if(kbddev.head!=kbddev.tail){
//        printk("<1>IN DRIVER: have data now read buffer..\n");
        ret = readbuf();
        copy_to_user(buffer,(char *)&ret,sizeof(char));
        return sizeof(char);
  }else{
//        printk("<1>IN DRIVER: don't have data\n");
        if(filp->f_flags & O_NONBLOCK)
          return -EAGAIN;
//        printk("IN DRIVER: now waiting...\n");

//        printk("<1>begin to sleep_on..  ");
        interruptible_sleep_on(&(kbddev.wq));   // if it is block mode.

//        printk("<1>waked form interruptible_sleep_on() yet\n");

        if(signal_pending(current))
                return -ERESTARTSYS;
        goto retry;
  }
  
  return sizeof(char); // actually this line is never have the chance to run.
}

static void kbd_timer_handler(unsigned long data)
{
      switch(kbddev.kbdStatus)
      {
                case KEYSTATUS_UP:
                        if(ISKBD_DOWN()){
                           kbddev.kbdStatus = KEYSTATUS_DOWNX;
                           
                           kbd_timer.expires = jiffies + KBD_TIMER_DELAY1;   // 10ms
//                           printk("now KEYSTATUS_DOWNX, add a timer 10ms..");
                        }
                        else{        
                        kbd_timer.expires = jiffies + KBD_TIMER_DELAY;   // 100ms
//                      printk("idle time\n");
                        }
                        add_timer(&kbd_timer);
                        break;
                case KEYSTATUS_DOWNX:
                        if(ISKBD_DOWN()){
                           kbddev.kbdStatus = KEYSTATUS_DOWN;
                           kbd_timer.expires = jiffies + KBD_TIMER_DELAY;  // probe repeat key
                           last_down_time = jiffies;                       // record the key input time.
     //                      printk("real input,now get the key\n");
                           get_kbd();   // get the key and write key buffer and wake up the interrupted exec.
                          // last_key = key;    // for later extention
                        }
                        else{
                           printk("noise input\n");
                           kbd_timer.expires = jiffies + KBD_TIMER_DELAY;  
                           kbddev.kbdStatus = KEYSTATUS_UP;
                        }
                        add_timer(&kbd_timer);
                        break;
                case KEYSTATUS_DOWN:
                        if(ISKBD_DOWN()){
                           kbd_timer.expires = jiffies + KBD_TIMER_DELAY;  // rep dalay time.  just waiting button up.
                           printk("repeat input\n");
                        }
                        else{
                           kbddev.kbdStatus = KEYSTATUS_UP;
                           kbd_timer.expires = jiffies + KBD_TIMER_DELAY;
                           printk("released the key\n");
                        }
                        add_timer(&kbd_timer);
                        break;
                default:
                        printk("error input state\n");
                        break;
        }

}

static void get_kbd(void)
{

  key = decode_key();     // we just get the key data one time, store in key.
//  printk("<1>in get_kbd() we get the return key is :%c\n",key);
//  printk("<1>now entering kebEvent()..\n");
  kbdEvent();             //  it is a function pointer , we have initialezed it by kbdEvent_raw() ;
}

static void kbdEvent_raw(void)
{
        printk("<1>now we have got the decode_key is: %c\n",key);
   
        if(kbddev.kbdStatus == KEYSTATUS_DOWN)
          BUF_HEAD = key ;              //  here KEY_UP = 0X80 , as a identifier of KEY_DOWN code.

 /*         else
          BUF_HEAD = key ;              //  here KEY_UP = 0X80 , as a identifier of KEY_DOWN code.
            else
                BUF_HEAD = key |KEY_UP ;                         //  here is KEY_UP code.
 */
        kbddev.head = INCBUF(kbddev.head,MAX_KBD_BUF);
//        printk("<1> head increased!,now the pos is:%d\n",kbddev.head);

//        printk("<1>now to wake_up_interruptible now.. ");
        wake_up_interruptible(&(kbddev.wq));
//        printk("<1>wake_up yet..\n");
}



module_init(keydrv_init_module);
module_exit(keydrv_cleanup);
//MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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