- 论坛徽章:
- 0
|
linux扫描按键驱动creator
sz111@126.com(原创作品,转载要注明出处)
之前写过一篇linux按键驱动,采用的是中断的方式,很多时候,我们没有更多的中断,只能采用扫描的方式了。具体思路就不做详细解释了,比较简单,先上code吧。MAKEFILE如下:obj-m := pic_key.oKERNEL_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 250static 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 { return result; } pic_key_setup_cdev(); for (i=0;i { s3c2410_gpio_cfgpin(key_info_tab.pin,0);//输入 s3c2410_gpio_pullup(key_info_tab.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);
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/49088/showart_2183701.html |
|