📄 keypad.c
字号:
//#define MYDEBUG#include "khead.h"#include "mx1hw.h"//#define PDEBUG printk#define KEYPAD_IRQ 13 struct keypad_struct{// wait_queue_head_t gkeypadWait; int gKeypadFlag; int gDataFlag; /* flag if the driver buf is full */};static struct keypad_struct keypadmx1;static int gMajor = 0;static int g_keyvalue = 0;static long g_keyjif = 0;static DECLARE_WAIT_QUEUE_HEAD(wait);// functions and interfacestatic int keypad_open(struct inode *inode, struct file *filp);static int keypad_release(struct inode *inode, struct file *filp);static ssize_t keypad_read(struct file *filp, char *buf, size_t size, loff_t * l);static ssize_t keypad_write(struct file *filp, const char *buf, size_t size, loff_t * l);static int keypad_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);static void keypad_intr_handler(int irq, void *dev_id, struct pt_regs *regs);static unsigned int keypad_poll(struct file * filp, struct poll_table_struct * wait_t);struct file_operations keypad_fops = { open:keypad_open, release:keypad_release, read:keypad_read, write:keypad_write, poll:keypad_poll, ioctl:keypad_ioctl,};void WREG(unsigned long reg, unsigned long val){ asm volatile ("str %1, [%0]"::"r" (reg), "r"(val) :"memory");}unsigned long REG(unsigned long reg){ unsigned long tmp = 0; asm volatile ("ldr %0, [%1]"::"r" (tmp), "r"(reg) :"memory"); return tmp;}static int keypad_open(struct inode *inode, struct file *filp){ PDEBUG("*** open ***\n"); MOD_INC_USE_COUNT; return 0;}static int keypad_release(struct inode *inode, struct file *filp){ PDEBUG("*** close ***\n"); MOD_DEC_USE_COUNT; return 0;}static unsigned int keypad_poll(struct file * filp, struct poll_table_struct * wait_t){ poll_wait(filp, &wait, wait_t); return ( keypadmx1.gDataFlag==0) ? 0 : (POLLIN | POLLRDNORM);}void delay(int n){ int i, j; for(i=0;i<10000;i++){ for(j=0;j<n;j++){ } }}#define usleep(n) delay(n)static int key_vector[5][5]={ { 0, 0, 0, 0, 0}, { 0, 1, 2, 3, 4}, { 0, 5, 6, 7, 8}, { 0, 9,10,11,12}, { 0,13,14,15,16}};static int row_value=0,line_value=0;static void convert_key(){ int tmp; if(row_value==ROW1) tmp = 1; else if(row_value==ROW2) tmp = 2; else if(row_value==ROW3) tmp = 3; else if(row_value==ROW4) tmp = 4; else tmp =0; g_keyvalue = key_vector[line_value][tmp];}static void line_poll(){ if(!((row_value&ROW1)|| (row_value&ROW2)|| (row_value&ROW3)|| (row_value&ROW4))) { g_keyvalue=0; return; }//no keydown detected; row_value &= (row_value&ROW1)| (row_value&ROW2)| (row_value&ROW3)| (row_value&ROW4);//mask other bits *(volatile U32*)PTC_IMR &= ~(0xF<<14);//interrupt masked //line output high,prepare for poll *(volatile U32*)PTA_DR |= 0x7<<17; *(volatile U32*)PTB_DR |= 0x1<<19; usleep(1);//begin polling *(volatile U32*)PTA_DR &= ~0x1<<17;//line 1 usleep(1); if(!(*(volatile U32*)PTC_SSR&row_value)) { line_value = 1; goto convert; } *(volatile U32*)PTA_DR |= 0x1<<17;//not line 1 *(volatile U32*)PTB_DR &= ~(0x1<<19);//line 2 usleep(1); if(!((*(volatile U32*)PTC_SSR)&row_value)) { line_value = 2; goto convert; } *(volatile U32*)PTB_DR |= (0x1<<19);//not line 2 *(volatile U32*)PTA_DR &= ~0x1<<18;//line 3 usleep(1); if(!(*(volatile U32*)PTC_SSR&row_value)) { line_value = 3; goto convert; } *(volatile U32*)PTA_DR |= 0x1<<18;//not line 3 *(volatile U32*)PTA_DR &= ~0x1<<19; usleep(1); if(!((*(volatile U32*)PTC_SSR)&row_value)) { line_value = 4; goto convert; } *(volatile U32*)PTA_DR |= 0x1<<19;//not line 4 line_value = 0; row_value =0;convert: convert_key(); *(volatile U32*)PTA_DR &= ~(0x7<<17);//output 0 *(volatile U32*)PTB_DR &= ~(0x1<<19); *(volatile U32*)PTC_IMR |= 0xF<<14;//interrupt enabled }static void keypad_intr_handler(int irq, void *dev_id, struct pt_regs *regs){ unsigned long flags; //printk("jiffies-keyjif: \t\t\t%ld\n", jiffies-g_keyjif);#if 1 //remove trembling if(jiffies - g_keyjif <= 19) { //printk("discarded.\n"); *(volatile U32*)PTC_ISR |= 0xF<<14; //clear all 14~17 interrupts(write 1 to clear) return; }#endif row_value=*(volatile U32*)PTC_ISR; g_keyjif=jiffies;// PDEBUG("PTC_ISR: 0x%x\n",*(volatile U32*)PTC_ISR); save_flags_cli(flags); keypadmx1.gDataFlag = 1; restore_flags(flags); line_poll(); //usleep(200); wake_up_interruptible(&wait); *(volatile U32*)PTC_ISR |= 0xF<<14; //clear all 15~30 interrupts(write 1 to clear)}static ssize_tkeypad_read(struct file *filp, char *buf, size_t size, loff_t * l){ int nonBlocking; unsigned long flags; int ret = 0; PDEBUG("*** read ***\n"); nonBlocking = filp->f_flags & O_NONBLOCK; PDEBUG("nonBlocking:%d\n", nonBlocking); if( keypadmx1.gDataFlag == 1) { *(U32*)buf=g_keyvalue; save_flags_cli(flags); keypadmx1.gDataFlag = 0; restore_flags(flags); ret = 2; }else{ if(!nonBlocking ){ interruptible_sleep_on(&wait); *(U32*)buf=g_keyvalue; save_flags_cli(flags); keypadmx1.gDataFlag = 0; restore_flags(flags); ret = 2; }else ret =0; } g_keyvalue = 0; return ret;} static ssize_tkeypad_write(struct file *filp, const char *buf, size_t size, loff_t * l){ PDEBUG("*** write ***\n"); return 0;}static intkeypad_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ unsigned long tmp; tmp = arg; PDEBUG("cmd: 0x%08x, arg: 0x%08x\n", cmd, (int) arg); return 0; }static void GPIO_init(void){//row *(volatile U32*)PTC_GIUS |= 0xF<<14; //GPC 14~17:GPIO function; *(volatile U32*)PTC_DDIR &= ~(0xF<<14); //14~17 input *(volatile U32*)PTC_PUEN |= 0xF<<14; //pull high *(volatile U32*)PTC_ICR1 |= 0x50000000; //PC 15,PC14,negtive edge interrupt(01), pin 15 *(volatile U32*)PTC_ICR2 |= 0x00000005; //PC16,PC17,negtive edge interrupt(01), pin 16~30 *(volatile U32*)PTC_IMR &= ~(0xF<<14); //all 14~17 interrupts masked *(volatile U32*)PTC_ISR |= 0xF<<14; //clear all 14~17 interrupts(write 1 to clear)//line *(volatile U32*)PTA_GIUS |= 0x7<<17;//GPA 17~19;GPIO function; *(volatile U32*)PTA_DDIR |= 0x7<<17;//17~19 output; *(volatile U32*)PTA_PUEN &= ~(0x7<<17);//tri-state; *(volatile U32*)PTA_OCR2 |= 0xFC; *(volatile U32*)PTA_DR &= ~(0x7<<17);//output 0 *(volatile U32*)PTB_GIUS |= 0x1<<19;//GPB 19 *(volatile U32*)PTB_DDIR |= 0x1<<19;//output *(volatile U32*)PTB_PUEN &= ~(0x1<<19);//tri-state *(volatile U32*)PTB_OCR2 |= 0xC0; *(volatile U32*)PTB_DR &= ~(0x1<<19);//output 0 // *(volatile U32*)PTD_GIUS |= 0x7ff8000; //use PTD 15~26// *(volatile U32*)PTD_DDIR &= ~0x7ff8000; //input// *(volatile U32*)PTD_PUEN |= 0x7ff8000; //pull high// *(volatile U32*)PTD_ICR1 |= 0x07000000; //negtive edge interrupt(01), pin 15// *(volatile U32*)PTD_ICR1 |= 0x00155555; //negtive edge interrupt(01), pin 16~30 //*(volatile U32*)PTD_ICR1 |= 0x0; //positive edge interrupt(00), pin 15 //*(volatile U32*)PTD_ICR1 |= 0x0; //negtive edge interrupt(00), pin 16~30// *(volatile U32*)PTD_IMR &= ~0x7ff8000; //all 15~30 interrupts masked// *(volatile U32*)PTD_ISR |= 0x7ff8000; //clear all 15~30 interrupts(write 1 to clear)}static devfs_handle_t devfs_handle;int init_module(){ int result; printk("KEYPAD driver " __DATE__ " / " __TIME__ "\n"); /* register our character device */ result = devfs_register_chrdev(0, "keypad", &keypad_fops); if (result < 0) { printk("keypad driver: Unable to register driver\n"); return -ENODEV; } devfs_handle = devfs_register(NULL, "keypad", DEVFS_FL_DEFAULT, result, 0, S_IFCHR | S_IRUSR | S_IWUSR, &keypad_fops, NULL); printk("make node for keypad with 'mknod keypad c %d 0'\n", result); gMajor = result; if (request_irq (KEYPAD_IRQ, keypad_intr_handler, SA_INTERRUPT, "KEYPAD", NULL)) printk ("*** Cannot register interrupt handler for KEYPAD ! ***\n"); else printk("KEYPAD interrupt handler registered\n"); printk("Keypad init.\n"); GPIO_init(); *(volatile U32*)PTC_IMR |= 0xF<<14; // enable pin 14~17 //*(volatile U32*)PTD_IMR = 0x7fff0000; //enable pin 15~30 //*(volatile U32*)PTD_IMR = 0x7ff8000; //enable pin 20~28 return 0;}void cleanup_module(){ if (gMajor > 0) { devfs_unregister_chrdev(gMajor, "keypad"); devfs_unregister(devfs_handle); } free_irq(KEYPAD_IRQ, 0); printk("Say goodbye to keypad\n");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -