www.pudn.com > key_dev.rar > key_dev.c
/*----------------------------------------------------------- * key_dev.c * micro keyboard driver with interrupt mode * copyright(C) jilin huafeng * up_key : port GPB0 * down_key : port GPB1 * left_key : port GPB9 * right_key : port GPB10 * confirm_key : port GPF1 * cancel_key : port GPF2 * key_press_interrupt : EINT5 *-----------------------------------------------------------*/ #include#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static DECLARE_WAIT_QUEUE_HEAD( keys_wait ); #define MICRO_KEY_MAJOR 138 //key_dat : x x x x x right left x x x x x cancel confirm down up // 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 #define NOKEY 0 #define RIGHT_KEY 0x04000 #define LEFT_KEY 0x02000 #define UP_KEY 0x00001 #define DOWN_KEY 0x00002 #define CONFIRM_KEY 0x00004 #define CANCEL_KEY 0x00008 static struct semaphore key_sem; static char key = NOKEY; unsigned long gpfdat, gpfup, gpfcon; unsigned long gpbdat, gpbup, gpbcon; devfs_handle_t devfs_microkey; static void microkey_clearirq( void ) { /*respond to EINT5*/ SRCPND &= ( ~0x00000010 ); //bit4 INTPND = INTPND; EINTPEND &= ( ~0x00000020 ); //bit5 } void delay() { int i, j; for( i = 0; i < 10000; i++ ) { for( j = 0; j < 100; j++ ); } } static void microkey_irq_isr( int irq, void *dev_id, struct pt_regs *regs ) { unsigned long f_dat, b_dat, k_dat; printk( "key pressed\n" ); f_dat = ( *( volatile unsigned long * )gpfdat ); b_dat = ( *( volatile unsigned long * )gpbdat ); k_dat = ( f_dat << 1 ) | b_dat; k_dat = ~k_dat; k_dat &= 0x060f; switch( k_dat ) { case 0x0400: key = RIGHT_KEY; printk("right key\n"); break; case 0x0200: key = LEFT_KEY; printk("left key\n"); break; case 0x0008: key = CANCEL_KEY; printk("cancel key\n"); break; case 0x0004: key = CONFIRM_KEY; printk("confirm key\n"); break; case 0x0002: key = DOWN_KEY; printk("down key\n"); break; case 0x0001: key = UP_KEY; printk("up key\n"); break; default: key = NOKEY; break; } microkey_clearirq(); up( &key_sem ); } static ssize_t microkey_read( struct inode *inode, char *buf, unsigned long count ) { if( key != NOKEY ) { down_interruptible( &key_sem ); put_user( key, buf ); key = NOKEY; return 1; } else { return 0; } } int microkey_open( struct inode *inode, struct file *file ) { sema_init( &key_sem, 0 ); return 0; } void microkey_release( struct inode *inode, struct file *filp ) { printk( "release ok!\n" ); return; } static unsigned int microkey_poll( struct file *file, poll_table *wait ) { //always ready return POLLIN | POLLRDNORM; } struct file_operations microkey_fops = { read : microkey_read, open : microkey_open, release : microkey_release, poll : microkey_poll, }; static int __init microkey_init(void) { static int rc; set_external_irq( IRQ_EINT5, EXT_FALLING_EDGE, GPIO_PULLUP_DIS ); //map port f config register address gpfcon = ioremap( 0x56000050, 4 ); //set port f io status: gpf1/2 : input(00), gpf5:10(EINT5) ( *( volatile unsigned long * )gpfcon ) &= 0xfbc3; //bit1,2 = 00, bit5 = 10 //map port f data register address gpfdat = ioremap( 0x56000054, 4 ); //map port b config register address gpbcon = ioremap( 0x56000010, 4 ); //set port b io status: gpb0/1/9/10 : input(00) ( *( volatile unsigned long * )gpbcon ) &= 0xffc3fff0; //bit0/1/9/10 = 00 //map port b data register address gpbdat = ioremap( 0x56000014, 4 ); disable_irq( IRQ_EINT5 ); enable_irq( IRQ_EINT5 ); rc = request_irq( IRQ_EINT5, microkey_irq_isr, SA_INTERRUPT, "microkey", NULL ); if( rc ) { printk( "<1>microkey irq 5 irq not registered. Error: %d\n", rc ); } printk("*********key_dev init ok!***********\n"); /* Register myirq as character device */ devfs_microkey = devfs_register( NULL, "microkey", DEVFS_FL_DEFAULT, MICRO_KEY_MAJOR, 0, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, µkey_fops, NULL ); return 0; } static void __exit microkey_exit(void) { disable_irq( IRQ_EINT5 ); free_irq( IRQ_EINT5, microkey_irq_isr ); devfs_unregister( devfs_microkey ); } module_init( microkey_init ); module_exit( microkey_exit );