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 );