Chinaunix首页 | 论坛 | 博客
  • 博客访问: 928812
  • 博文数量: 96
  • 博客积分: 10071
  • 博客等级: 上将
  • 技术积分: 1118
  • 用 户 组: 普通用户
  • 注册时间: 2007-09-20 17:54
文章分类

全部博文(96)

文章存档

2011年(3)

2010年(3)

2009年(29)

2008年(54)

2007年(7)

分类: LINUX

2010-02-22 10:50:20

linux扫描按键驱动
creator
sz111@126.com(原创作品,转载要注明出处)


    之前写过一篇linux按键驱动,采用的是中断的方式,很多时候,我们没有更多的中断,只能采用扫描的方式了。具体思路就不做详细解释了,比较简单,先上code吧。
MAKEFILE如下:
obj-m := pic_key.o
KERNEL_DIR=/usr/local/src/linux-2.6.21/
PWD=$(shell pwd)
all:
make -C $(KERNEL_DIR) M=$(PWD) modules

code如下:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

/*
//GPD0--GPD9==> KEY0--KEY9
//GPD10:BOOKMARK
//GPD11:T_RIGHT
//GPD12:T_LEFT
//GPD13:T_ENTER
//GPD14:OVERTURN
//GPD15:BLOWUP
//GPB0:MENU
//GPG1:CANCEL
//GPG2:UP
//GPG3:DOWN
//GPG4:LEFT
//GPB5:RIGHT
//GPB6:OK
//GPB9:PLAY/PAUSE
*/
static struct key_info
{
    unsigned int pin;
    int key_code;
    char *name;
}key_info_tab[] = 
{
    {S3C2410_GPD0, 0x01, "Key 01" },
    {S3C2410_GPD1, 0x02, "Key 02" },
    {S3C2410_GPD2, 0x03, "Key 03" },
    {S3C2410_GPD3, 0x04, "Key 04" },
    {S3C2410_GPD4, 0x05, "Key 05" },
    {S3C2410_GPD5, 0x06, "Key 06" },
    {S3C2410_GPD6, 0x07, "Key 07" },
    {S3C2410_GPD7, 0x08, "Key 08" },
    {S3C2410_GPD8, 0x09, "Key 09" },
    {S3C2410_GPD9, 0x0A, "Key 0A" },
    {S3C2410_GPD10, 0x0B, "Key 0B" },
    {S3C2410_GPD11, 0x0C, "Key 0C" },
    {S3C2410_GPD12, 0x0D, "Key 0D" },
    {S3C2410_GPD13, 0x0E, "Key 0E" },
    {S3C2410_GPD14, 0x0F, "Key 0F" },
    {S3C2410_GPD15, 0x10, "Key 10" },
    {S3C2410_GPB0, 0x11, "Key 11" },
    {S3C2410_GPG1, 0x12, "Key 12" },
    {S3C2410_GPG2, 0x13, "Key 13" },
    {S3C2410_GPG3, 0x14, "Key 14" },
    {S3C2410_GPG4, 0x15, "Key 15" },
    {S3C2410_GPB5, 0x16, "Key 16" },
    {S3C2410_GPB6, 0x17, "Key 17" },
    {S3C2410_GPB9, 0x18, "Key 18" },
};

#define TRUE 1
#define FALSE 0

#define DEVICE_NAME "pic_key"
#define MAX_KEY_BUF 16 //KEY BUFFER SIZE
#define KEY_NUM  24  //key num 
#define BUF_HEAD (pic_key_dev.buf[pic_key_dev.head])
#define BUF_TAIL (pic_key_dev.buf[pic_key_dev.tail])
#define INCBUF(x,mod) ((++(x))&((mod)-1))

#define SCANKEY_TIME 20//50ms

#define PIC_KEY_MAJOR 250
static dev_t pic_key_major = PIC_KEY_MAJOR;



typedef unsigned int KEY_RET;

struct pic_key_dev_t
{
    struct cdev cdev;
    unsigned int buf[MAX_KEY_BUF];
    unsigned int head,tail;
    unsigned int key_value;
    wait_queue_head_t wq;    
};
struct pic_key_dev_t pic_key_dev;
struct timer_list key_timer;



#define ISKEY_DOWN(key) (s3c2410_gpio_getpin(key_info_tab[key].pin) == 0)
static void pic_key_timer(unsigned long data);
static int pic_key_open(struct inode *inode, struct file *filp);
static int pic_key_release(struct inode *inode, struct file *filp);
static ssize_t pic_key_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos);
static ssize_t pic_key_read(struct file *file,char __user *buffer, size_t count, loff_t *ppos);


static unsigned int get_key_value(void)
{
int key;
unsigned int ret=0;
for (key=0;key
{
if (ISKEY_DOWN(key))
{
ret |= (1<
}
}
return ret;
}

#define FLGKEY_KEY_MASK 0x00ffffff//24key
#define FLGKEY_PRESSED              0x00000000
#define FLGKEY_RELEASED             0x01000000
#define FLGKEY_CONTINUE             0x02000000
#define FLGKEY_HOLD                 0x02000000
#define FLGKEY_LONGPRESSED          0x04000000
#define FLGKEY_LONGHOLD             0x04000000
#define FLGKEY_ACT_MASK             0x0f000000      // Key action mask

#define KEY_HOLD_COUNT          10
#define KEY_HOLD_CONTINUE       1//2
#define KEY_LONG_HOLD_COUNT     10//9

static unsigned int       uiLastKeyStatus         = 0;
static unsigned int       uiLastMDStatus          = 0;
static unsigned int       uiStableKeyStatus       = 0;
static unsigned int       uiStableMDStatus        = 0;
static unsigned int       uiLastStableKeyStatus   = 0;
static unsigned int       uiKeyMaskPress          = FLGKEY_KEY_MASK;
static unsigned int       uiKeyMaskRelease        = FLGKEY_KEY_MASK;
static unsigned int       uiKeyMaskContinue       = FLGKEY_KEY_MASK;
static unsigned int       uiKeyMaskLong           = 0;

static unsigned int       uiKeyHoldCount          = 0;
static unsigned int       uiKeyLongHoldCount      = 0;
static bool bKeyHoldFlag            = FALSE;
static unsigned int g_uiKeyScanFlags;
static void handle_pic_key_event(unsigned int keycode)  
{
    BUF_HEAD = keycode;
    pic_key_dev.head = INCBUF(pic_key_dev.head,MAX_KEY_BUF);
    printk(KERN_ERR "key_value:%x\n",keycode);
    wake_up_interruptible(&(pic_key_dev.wq));
}

static void pic_key_timer(unsigned long data)  
{  
unsigned int          uiCurKeyStatus, uiTempKeyStatus;
    unsigned int          uiKeyChanged;
    unsigned int          uiKeyPressed, uiKeyReleased, uiKeyContinue;

    unsigned int           bKeyCode;

    uiCurKeyStatus          =
    uiTempKeyStatus         = get_key_value();

    uiCurKeyStatus         &= (uiLastKeyStatus & FLGKEY_KEY_MASK);    
    uiKeyChanged            = uiCurKeyStatus ^ uiStableKeyStatus;
    uiKeyPressed            = uiKeyChanged & uiCurKeyStatus;
    uiKeyReleased           = uiKeyChanged & (~uiCurKeyStatus);
    uiKeyContinue           = uiCurKeyStatus & uiStableKeyStatus & uiLastStableKeyStatus;
    uiLastStableKeyStatus   = uiStableKeyStatus & ~(uiKeyContinue);
    uiStableKeyStatus       = uiCurKeyStatus;
    uiLastKeyStatus         = uiTempKeyStatus;    

    if (uiKeyPressed)
    {
        uiTempKeyStatus = uiKeyPressed & uiKeyMaskPress;

        if (uiTempKeyStatus)
        {
             g_uiKeyScanFlags |= (FLGKEY_PRESSED | uiTempKeyStatus);
        }
    }
    if (uiKeyReleased)
    {
        uiTempKeyStatus = uiKeyReleased & uiKeyMaskRelease;

        if (uiTempKeyStatus != 0)
        {
g_uiKeyScanFlags |= (FLGKEY_RELEASED | uiKeyReleased);
            bKeyHoldFlag = FALSE;
            uiKeyHoldCount = 0;
            uiKeyLongHoldCount = 0;
        }
    }

    if (uiKeyContinue)
    {
        uiTempKeyStatus = uiKeyContinue & uiKeyMaskContinue;

        if (uiTempKeyStatus)
        {
            uiKeyHoldCount++;
            if (bKeyHoldFlag == FALSE && uiKeyHoldCount > KEY_HOLD_COUNT ||
                bKeyHoldFlag == TRUE  && uiKeyHoldCount > KEY_HOLD_CONTINUE)
            {
                uiKeyHoldCount = 0;

                // Play keypad tone
                if (bKeyHoldFlag == FALSE)
                {
                    bKeyHoldFlag = TRUE;
                    g_uiKeyScanFlags |= (FLGKEY_HOLD | uiKeyContinue);
                }

                // Continue key pressed event
                

                if (bKeyHoldFlag)
                {
                    uiKeyLongHoldCount++;
                    if (uiKeyLongHoldCount > KEY_LONG_HOLD_COUNT)
                    {
                        uiKeyLongHoldCount = 0;
                        g_uiKeyScanFlags &= ~FLGKEY_HOLD;
                        g_uiKeyScanFlags |= FLGKEY_LONGHOLD;
                    }
                }
            }
        }
    }
    
    if (g_uiKeyScanFlags)
    {
     handle_pic_key_event(g_uiKeyScanFlags);
      g_uiKeyScanFlags = 0;
    }
    init_timer(&key_timer);  
    key_timer.expires = jiffies + SCANKEY_TIME*HZ/1000;  ;  
    key_timer.function = (void*)pic_key_timer;  
    add_timer(&key_timer); 
}

static const struct file_operations pic_key_fops =
{
    .owner = THIS_MODULE,
    .read  = pic_key_read,
    .write = pic_key_write,
    .open  = pic_key_open,
    .release = pic_key_release,
};


static void pic_key_setup_cdev(void)
{
    int i;
    int err,devno = MKDEV(pic_key_major,0);
    cdev_init(&pic_key_dev.cdev,&pic_key_fops);
    pic_key_dev.cdev.owner = THIS_MODULE;
    pic_key_dev.cdev.ops = &pic_key_fops;
    //pic_key_dev.key_status = 0;
    err = cdev_add(&pic_key_dev.cdev, devno, 1);
    if (err)
    {
        printk(KERN_NOTICE "Error %d adding pic_key",err);        
    }    
   
    init_waitqueue_head(&(pic_key_dev.wq));   
    
    init_timer(&key_timer);  
    key_timer.expires = jiffies + HZ;  
    key_timer.function = (void*)pic_key_timer;  
    add_timer(&key_timer); 

}

static int pic_key_open(struct inode *inode, struct file *filp)
{
    filp->private_data = &pic_key_dev;
    printk(KERN_NOTICE "pic_key opened\n");
    return 0;
}

static int pic_key_release(struct inode *inode, struct file *filp)
{
    printk(KERN_NOTICE "pic_key released\n");
    return 0;
}

static ssize_t pic_key_write(struct file *filp, const char __user *buffer, size_t count, loff_t *ppos)
{
    return 0;
}


static ssize_t pic_key_read(struct file *filp,char __user *buffer, size_t count, loff_t *ppos)
{
    KEY_RET key_ret;
    struct pic_key_dev_t *dev;
    dev = (struct pic_key_dev_t*)filp->private_data;
retry:
    if (pic_key_dev.head != pic_key_dev.tail)
    {
        key_ret = BUF_TAIL;
        dev->tail = INCBUF(dev->tail,MAX_KEY_BUF);
        copy_to_user(buffer,(char*)&key_ret,sizeof(KEY_RET));
        return sizeof(KEY_RET);
    }else
    {
        if (filp->f_flags & O_NONBLOCK)
        {
            return -EAGAIN;
        }
        interruptible_sleep_on(&(dev->wq));
        if (signal_pending(current))
        {
            return -ERESTARTSYS;
        }
        goto retry;
    }
    
    return sizeof(KEY_RET);
}

static int __init pic_key_init(void)
{
    int result;
    int i;
    
    dev_t devno = MKDEV(pic_key_major,0);
    if (pic_key_major)
    {
        result = register_chrdev_region(devno, 1, DEVICE_NAME);
    }else
    {
        result = alloc_chrdev_region(&devno, 0, 1, DEVICE_NAME);
        pic_key_major = MAJOR(devno);
    }
    if (result < 0)
    {
        return result;
    }
    pic_key_setup_cdev();
    
    for (i=0;i
    {
     s3c2410_gpio_cfgpin(key_info_tab[i].pin,0);//输入
     s3c2410_gpio_pullup(key_info_tab[i].pin,2);//上拉
}
    return 0;
}
static void __exit pic_key_exit(void)
{
    int i;
    cdev_del(&pic_key_dev.cdev);
    unregister_chrdev_region(MKDEV(pic_key_major,0),1);
    del_timer(&key_timer);
}

MODULE_AUTHOR("Creator");
MODULE_LICENSE("Dual BSD/GPL");

module_init(pic_key_init);
module_exit(pic_key_exit);

阅读(2767) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~