行尸之惧第四季线上看: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 ;
}