韦根驱动

韦根驱动

#include  < linux / types.h >
#include 
< linux / module.h >
#include 
< linux / init.h >
#include 
< linux / poll.h >
#include 
< linux / errno.h >
#include 
< linux / gpio.h >
#include 
< linux / interrupt.h >
#include 
< linux / miscdevice.h >
#include 
< linux / ioport.h >
#include 
< linux / device.h >
#include 
< asm / io.h >
#include 
< asm / irq.h >
#include 
< mach / irqs.h >
#include 
< mach / regs - gpio.h >

#include 
" ../ioctl_new.h "

static  spinlock_t    wiegand_lock;
static   int             wiegand_in  =   0 ;
static   int             wiegand_in_cur  =   0 ;
static   int             wiegand_in_stime  =   0 ;
static   int             wiegand_in1_stime  =   0 ;
static   int             wiegand_in2_stime  =   0 ;
static  unsigned  char  wiegand_data[ 40 ];
static  WIEGAND_TYPE    wiegand_mode;

inline 
void  wiegand_delay( int  microseconds)
{
    
int  i;
    
while  (microseconds -- )
    {
        
for  (i = 0 ; i < 65 ; i ++ ) __asm( " NOP " );
    }
}

static   int  wiegand_gettickcount( void )
{
    
static   int  __start_time  =   0 // second
     struct  timeval tv;

    do_gettimeofday(
& tv);

    
if  (__start_time  ==   0 )
        __start_time 
=  tv.tv_sec;

    
return  ((tv.tv_sec  -  __start_time)  *   1000   +  tv.tv_usec  /   1000 );
}

inline 
void  wiegand_minus_interrupt( void )
{
    
if  (wiegand_in  !=  WGNSTAT_RECVFULL)
    {
        
if  (wiegand_gettickcount()  -  wiegand_in_stime  >=   100 )
            wiegand_in_cur 
=   0 ;
        wiegand_in_stime 
=  wiegand_gettickcount();
        wiegand_data[wiegand_in_cur
++ =   0 ;
        
if  (wiegand_in_cur  >=   34 )
            wiegand_in 
=  WGNSTAT_RECVFULL;
        
else   if  (wiegand_in_cur  >=   26 )
            wiegand_in 
=  WGNSTAT_RECV26;
    }
}

inline 
void  wiegand_plus_interrupt( void )
{
    
if  (wiegand_in  !=  WGNSTAT_RECVFULL)
    {
        
if  (wiegand_gettickcount()  -  wiegand_in_stime  >=   100 )
            wiegand_in_cur 
=   0 ;
        wiegand_in_stime 
=  wiegand_gettickcount();
        wiegand_data[wiegand_in_cur
++ =   1 ;
        
if  (wiegand_in_cur  >=   34 )
            wiegand_in 
=  WGNSTAT_RECVFULL;
        
else   if  (wiegand_in_cur  >=   26 )
            wiegand_in 
=  WGNSTAT_RECV26;
    }
}

static  irqreturn_t wiegand_minus1_interrupt( int  irq,  void   * dev_id)
{
    spin_lock(
& wiegand_lock);
//     printk("wiegand_minus1_interrupt\n");
     if  (wiegand_gettickcount()  -  wiegand_in2_stime  >   200 )
    {
        wiegand_minus_interrupt();
        wiegand_in1_stime 
=  wiegand_in_stime;
    }
    spin_unlock(
& wiegand_lock);
    
return  IRQ_HANDLED;
}

static  irqreturn_t wiegand_plus1_interrupt( int  irq,  void   * dev_id)
{
    spin_lock(
& wiegand_lock);
//     printk("wiegand_plus1_interrupt\n");
     if  (wiegand_gettickcount()  -  wiegand_in2_stime  >   200 )
    {
        wiegand_plus_interrupt();
        wiegand_in1_stime 
=  wiegand_in_stime;
    }
    spin_unlock(
& wiegand_lock);
    
return  IRQ_HANDLED;
}


static   int  wiegand_open( struct  inode  *  inode,  struct  file  *  filp);
static   int  wiegand_release( struct  inode  *  inode, struct  file  *  filp);
static  ssize_t wiegand_read( struct  file  * flip,  char   * buf, size_t len, loff_t  * pos);
static  ssize_t wiegand_write( struct  file  * flip,  const   char   * buf, size_t len, loff_t  * pos);
static   long  wiegand_ioctl( struct  file  * file, unsigned  int  cmd, unsigned  long  arg);

static   struct  file_operations wiegand_fops  =  {
    owner:        THIS_MODULE,
    open:        wiegand_open,
    release:    wiegand_release,
    read:        wiegand_read,
    write:        wiegand_write,
    unlocked_ioctl:        wiegand_ioctl,
};

static   struct  miscdevice wiegand_dev  =  {
    WIEGAND_MINOR,
    WIEGAND_MODULE_NAME,
    
& wiegand_fops
};

static   void  config_wiegand_pins( void )
{
    s3c2410_gpio_cfgpin(WGNIN_0, WGNIN_0_CON);
    s3c2410_gpio_cfgpin(WGNIN_1, WGNIN_1_CON);
    s3c2410_gpio_cfgpin(WGNOUT0, WGNOUT0_CON);
    s3c2410_gpio_cfgpin(WGNOUT1, WGNOUT1_CON);
#if  0
    
if  (request_irq(WGNIN_0_IRQ_NUM,  & wiegand_minus1_interrupt, 
        IORESOURCE_IRQ 
|  IRQF_TRIGGER_RISING, 
        WIEGAND_IRQ_MINUS, 
        
& wiegand_dev)         
        
||  request_irq(WGNIN_1_IRQ_NUM,  & wiegand_plus1_interrupt,  
        IORESOURCE_IRQ 
|  IRQF_TRIGGER_RISING, 
        WIEGAND_IRQ_PLUS, 
        
& wiegand_dev))
        
    {
        printk(
" WIEGAND request_irq Fail\n " );
    }
#endif
}

static   int  wiegand_open( struct  inode  *  inode,  struct  file  *  filp)
{
    config_wiegand_pins();
    
return   0 ;
}

static   int  wiegand_release( struct  inode  *  inode, struct  file  *  filp)
{
#if  0
    free_irq(WGNIN_0_IRQ_NUM, 
& wiegand_dev);
    free_irq(WGNIN_1_IRQ_NUM, 
& wiegand_dev);
#endif
    
return   0 ;
}

static  ssize_t wiegand_read( struct  file  * flip,  char   * buf, size_t len, loff_t  * pos)
{
    
int  result;
    spin_lock(
& wiegand_lock);
    
if  (wiegand_in  ==  WGNSTAT_NONE  ||  len  >   sizeof (wiegand_data)  ||  (wiegand_gettickcount()  -  wiegand_in_stime  >   1800 ))         // 500
    {
        wiegand_in 
=  WGNSTAT_NONE;
        spin_unlock(
& wiegand_lock);
        
return   0 ;
    }
    
if  (len  >  wiegand_in_cur)
        len 
=  wiegand_in_cur;
    result 
=  copy_to_user(buf, wiegand_data, len);
    wiegand_in 
=  WGNSTAT_NONE;
    wiegand_in_cur 
=   0 ;
    spin_unlock(
& wiegand_lock);
    
return  len;
}

static  ssize_t wiegand_write( struct  file  * flip,  const   char   * buf, size_t len, loff_t  * pos)
{
    
int  i;
    
char  data[ 40 ];

    
if  (len  >   sizeof (data))
        
return   0 ;

    i 
=  copy_from_user(data, buf, len);
    
for  (i = 0 ; i < len; i ++ )
    {
        
if  (data[i]  ==   0 )
        {
            WGNOUT0_1; wiegand_delay(wiegand_mode.dwTpw); WGNOUT0_0;
        }
        
else
        {
            WGNOUT1_1; wiegand_delay(wiegand_mode.dwTpw); WGNOUT1_0;
        }
        wiegand_delay(wiegand_mode.dwTpi);
    }

    
return  len;
}

static   long  wiegand_ioctl( struct  file  * file, unsigned  int  cmd, unsigned  long  arg)
{
    
int  result  =   0 ;
    spin_lock(
& wiegand_lock);
    
switch (cmd)
    {
    
case  WIEGAND_MODE_SET:
        result 
=  copy_from_user( & wiegand_mode, ( void * )arg,  sizeof (WIEGAND_TYPE));
        
break ;
    }
    spin_unlock(
& wiegand_lock);
    
return  (result  ==   sizeof (WIEGAND_TYPE)  ?   0  :  - 1 );
}



static   int  __init s3c2416_wiegand_init( void )
{
    
int  ret  =   0 ;
    
    ret 
=  misc_register( & wiegand_dev);
    
if  (ret)
    {
        printk(
" probuck s3c2416 WIEGAND Driver "  WIEGAND_DRIVER_VERSION  " Fail\n " );
        
goto  exit_sb3kt_wiegand_init;
    }
    spin_lock_init(
& wiegand_lock);

    printk(
" probuck s3c2416 WIEGAND Driver "  WIEGAND_DRIVER_VERSION  " \n " );
    
exit_sb3kt_wiegand_init:
    
return  ret;
}

static   void  __exit s3c2416_wiegand_cleanup( void )
{
    misc_deregister(
& wiegand_dev);
}

module_init(s3c2416_wiegand_init);
module_exit(s3c2416_wiegand_cleanup);
MODULE_LICENSE(
" GPL " );

MODULE_DESCRIPTION(
" s3c2416 WIEGAND Driver " );
MODULE_SUPPORTED_DEVICE(
" s3c2416 WIEGAND " );

你可能感兴趣的:(韦根驱动)