行尸之惧第四季线上看:linux 按键驱动
来源:百度文库 编辑:偶看新闻 时间:2024/04/30 12:21:33
源代码文件
#include
#include
#include
#include
#include
#include
#if !defined(CONFIG_TANGOX)
#error "Unsupport architecture (TANGOX only)."
#elif defined(CONFIG_TANGO2_SMP863X) && (EM86XX_REVISION < 4)
#error "Unsupport Tango2 (ES4 or above) or Tango3 chip."
#endif
#include
// For poll and select.
#include
#include
#include
#ifdef CONFIG_TANGO2
#include
#elif defined(CONFIG_TANGO3)
#include
#endif
MODULE_DESCRIPTION ( "EM86xx/SMP86xx tamedia front key driver\n" ) ;
MODULE_AUTHOR ( "rui" ) ;
MODULE_LICENSE ( "GPL" ) ;
#define TAKEY_BUF_MAXCOUNT 8
#define KEY_X1 9
#define KEY_X2 10
#define KEY_X3 11
#define KEY_Y1 13
#define KEY_Y2 14
#define KEY_Y3 15
#define KEY_Y4 6
#define TAKEY_DEV_NAME "takey"
static int major = 222 ;
module_param( major, int, 0 ) ;
struct timer_list takey_timer ;
int takey_delay = 50 * HZ / 1000 ; // 50ms
unsigned char char_buffer[8] = { 0, } ;
unsigned char key_count ;
unsigned char head ;
unsigned char tail ;
struct semaphore sem ;
spinlock_t lock ;
static int takey_open( struct inode *, struct file * ) ;
static int takey_release( struct inode *, struct file * ) ;
static int takey_read( struct file *, char *, size_t, loff_t * ) ;
static int takey_write( struct file *, const char *, size_t, loff_t * ) ;
static unsigned int takey_poll( struct file *, struct poll_table_struct * ) ;
static struct file_operations takey_fops =
{
.owner = THIS_MODULE,
.open = takey_open,
.read = takey_read,
.write = takey_write,
.poll = takey_poll,
.release = takey_release,
};
DECLARE_WAIT_QUEUE_HEAD( takey_wait_queue ) ;
static void initStatus( void )
{
em86xx_gpio_setdirection( KEY_X1, GPIO_OUTPUT ) ;
em86xx_gpio_write( KEY_X1, 1 ) ;
em86xx_gpio_setdirection( KEY_X1, GPIO_INPUT) ;
em86xx_gpio_setdirection( KEY_X2, GPIO_OUTPUT ) ;
em86xx_gpio_write( KEY_X2, 1 ) ;
em86xx_gpio_setdirection( KEY_X2, GPIO_INPUT) ;
em86xx_gpio_setdirection( KEY_X3, GPIO_OUTPUT ) ;
em86xx_gpio_write( KEY_X3, 1 ) ;
em86xx_gpio_setdirection( KEY_X3, GPIO_INPUT) ;
em86xx_gpio_setdirection( KEY_Y1, GPIO_OUTPUT ) ;
em86xx_gpio_write( KEY_Y1, 1 ) ;
em86xx_gpio_setdirection( KEY_Y2, GPIO_OUTPUT ) ;
em86xx_gpio_write( KEY_Y2, 1 ) ;
em86xx_gpio_setdirection( KEY_Y3, GPIO_OUTPUT ) ;
em86xx_gpio_write( KEY_Y3, 1 ) ;
em86xx_uart1_gpio_setdirection( KEY_Y4, GPIO_OUTPUT ) ;
em86xx_uart1_gpio_write( KEY_Y4, 1 ) ;
}
static int setData( const int key, const int data )
{
if ( em86xx_gpio_read( key ) == 0 )
{
while ( em86xx_gpio_read( key ) == 0 ) ;
if ( key_count < TAKEY_BUF_MAXCOUNT)
{
char_buffer[ tail++ ] = data ;
if ( tail >= TAKEY_BUF_MAXCOUNT )
{
tail = 0 ;
}
key_count++ ;
}
wake_up_interruptible( &takey_wait_queue ) ;
mod_timer( &takey_timer, jiffies + takey_delay ) ;
return 1 ;
}
return 0 ;
}
static void takey_timerhandle( void )
{
spin_lock( lock ) ;
initStatus() ;
// KEY_Y1
em86xx_gpio_write( KEY_Y1, 0 ) ;
if ( setData( KEY_X1, 1 ) == 1 )
{
return ;
}
if ( setData( KEY_X2, 5 ) == 1 )
{
return ;
}
if ( setData( KEY_X3, 9 ) == 1 )
{
return ;
}
// KEY_Y2
em86xx_gpio_write( KEY_Y2, 0 ) ;
if ( setData( KEY_X1, 2 ) == 1 )
{
return ;
}
if ( setData( KEY_X2, 6 ) == 1 )
{
return ;
}
if ( setData( KEY_X3, 10 ) == 1 )
{
return ;
}
// KEY_Y3
em86xx_gpio_write( KEY_Y3, 0 ) ;
if ( setData( KEY_X1, 3 ) == 1 )
{
return ;
}
if ( setData( KEY_X2, 7 ) == 1 )
{
return ;
}
if ( setData( KEY_X3, 11 ) == 1 )
{
return ;
}
// KEY_Y4
em86xx_uart1_gpio_write( KEY_Y4, 0 ) ;
if ( setData( KEY_X1, 4 ) == 1 )
{
return ;
}
if ( setData( KEY_X2, 8 ) == 1 )
{
return ;
}
if ( setData( KEY_X3, 12 ) == 1 )
{
return ;
}
spin_unlock( lock ) ;
mod_timer( &takey_timer, jiffies + takey_delay ) ;
}
static int takey_open( struct inode *inode_ptr, struct file *filep )
{
key_count = 0 ;
filep->f_op = &takey_fops ;
return 0;
}
static int takey_release( struct inode *inode_ptr, struct file *filep )
{
return 0;
}
static int takey_read( struct file *filep, char *buffer, size_t count, loff_t * fp )
{
char data[1] = { 0, } ;
down( &sem ) ;
// Do nothing if the buffer is empty.
if ( key_count == 0 )
{
up( &sem ) ;
return 0 ;
}
data[0] = char_buffer[head] ;
if ( copy_to_user( buffer, (char*)data, 1 ) )
{
up( &sem ) ;
return -EFAULT ;
}
head++ ;
if ( head >= TAKEY_BUF_MAXCOUNT )
{
head = 0 ;
}
key_count-- ;
up( &sem ) ;
return 1;
}
static int takey_write( struct file *filep, const char *buffer, size_t size, loff_t * fp )
{
unsigned char nkey ;
down( &sem ) ;
if ( key_count >= TAKEY_BUF_MAXCOUNT )
{
up( &sem ) ;
return 0 ;
}
if ( copy_from_user( &nkey, buffer, 1 ) )
{
up( &sem ) ;
return -EFAULT ;
}
if ( nkey < 1 || nkey > 12 )
{
up( &sem ) ;
return 0;
}
if ( key_count < TAKEY_BUF_MAXCOUNT )
{
char_buffer[tail++] = nkey;
if ( tail >= TAKEY_BUF_MAXCOUNT )
{
tail = 0;
}
key_count++;
wake_up_interruptible( &takey_wait_queue ) ;
}
up( &sem ) ;
return 1;
}
static unsigned int takey_poll( struct file *filep, struct poll_table_struct *ptable )
{
unsigned int mask = 0;
down( &sem ) ;
poll_wait( filep, &takey_wait_queue, ptable ) ;
if ( key_count != 0 )
{
mask |= ( POLLIN | POLLRDNORM ) ;
}
up( &sem ) ;
return mask;
}
static int takey_init( void )
{
int result = 0 ;
spin_lock_init( &lock ) ;
init_MUTEX( &sem ) ;
result = register_chrdev( major, TAKEY_DEV_NAME, &takey_fops ) ;
if ( result < 0 )
{
printk ( "register_chrdev takey failed.\n" ) ;
return result ;
}
init_timer( &takey_timer ) ;
takey_timer.expires = jiffies + takey_delay ;
takey_timer.function = (void *) takey_timerhandle ;
add_timer( &takey_timer ) ;
return 0;
}
static void takey_exit( void )
{
del_timer( &takey_timer ) ;
unregister_chrdev( major, TAKEY_DEV_NAME ) ;
spin_unlock( lock ) ;
}
module_init( takey_init ) ;
module_exit( takey_exit ) ;
makefile
kerdir=/root/8655/smp86xx_kernel_source_R2.6.22-19/linux-2.6.22.19/
obj-m := takey.o
modules:
$(MAKE) -C $(kerdir) M=$(shell pwd) modules
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
测试程序
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main( void )
{
int fd ;
struct pollfd Events[1] ;
int ret ;
char buff[2] = { 0, } ;
fd = open( "/dev/takey", O_RDWR | O_NOCTTY ) ;
memset( Events, 0, sizeof( Events ) ) ;
Events[0].fd = fd ;
Events[0].events = POLLIN | POLLERR ;
while ( 1 )
{
ret = poll( (struct pollfd*)&Events, 1, 5000 ) ;
if ( ret < 0 )
{
printf( "poll error .\n" ) ;
return EXIT_FAILURE ;
}
if ( ret == 0 )
{
printf( "5 seconds no data .\n" ) ;
continue ;
}
if ( Events[0].revents & POLLERR )
{
printf( "device error .\n" ) ;
return EXIT_FAILURE ;
}
if ( Events[0].revents & POLLIN )
{
memset( buff, 0, sizeof buff ) ;
read( fd, buff, 1 ) ;
printf( "data : %d\n", buff[0] ) ;
}
}
close( fd ) ;
return EXIT_SUCCESS ;
}