rk3568-Android11-韦根输入驱动

经过摸索终于把它也弄出来了,话不多说上代码。

wiegand-in.c

#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/device.h>
#include <linux/semaphore.h>
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/gpio.h> 
#include <linux/slab.h>

#include "wiegandin.h"
static unsigned long long dwWgReader = 0;
static int dwWgReaderCount = 0;
static int bWgDataReady = 0;
static unsigned int dwWgData = 0;
static struct  timeval last_time = {0};
static int bit_bgn = 0;
static int bit_end = 0;
static int g_irq_source = 0;

static int is_timediff_novalid(void)
{
    unsigned int diff = 0;

    struct  timeval curr_time = {0};

    do_gettimeofday(&curr_time);

    if(curr_time.tv_usec >= last_time.tv_usec)
    {
        diff = (curr_time.tv_sec - last_time.tv_sec) * 1000 + (curr_time.tv_usec - last_time.tv_usec) / 1000;
    }
    else
    {
        diff = (curr_time.tv_sec - last_time.tv_sec) * 1000 - (last_time.tv_usec - curr_time.tv_usec) / 1000;
    }

    last_time.tv_sec  = curr_time.tv_sec;
    last_time.tv_usec = curr_time.tv_usec;

    if(diff >= 240)
        return 1;

    return 0;
}

static int is_wgdata_valid(int mode)
{
    int i = 0;

    int one_num     = 0;

    unsigned int check_temp = 0;
    unsigned char  even       = 0;
    unsigned char  odd           = 0;
    int bit_num = 12;

    if(mode == 26)
    {
        bit_num = 12;
        check_temp  = dwWgReader >> 12;
    }
    else
    {
        check_temp  = dwWgReader >> 16;
        bit_num = 16;
    }

    //hid
    one_num = 0;

    for(i = 0; i < bit_num; i++)
    {
        if(check_temp & 0x01)
            one_num += 1;

        check_temp >>= 1;
    }

    if(one_num % 2 )    //奇校验位: 凑够奇数个1
        even = 0;
    else
        even = 1;


    if(even != (bit_bgn & (unsigned long long)0x01)){
        // printk("\033[1;32m<hq_gpio> 偶校验正确 init\033[0m\n");
    }else{
        printk("\033[1;31m<hq_gpio> 偶校验错误\033[0m\n");
        dwWgReader = 0;
        dwWgReaderCount = 0;
        bWgDataReady = 0;
        dwWgData = 0;
        return 0;
    }

    check_temp  = dwWgReader;
    //pid
    one_num = 0;

    for(i = 0; i < bit_num; i++)
    {
        if(check_temp & 0x01)
            one_num += 1;

        check_temp >>= 1;
    }

    if(one_num % 2 )    //偶校验位: 凑够偶数个1
        odd = 1;
    else
        odd = 0;

    return 1;
}


int flag_time = 0;
static void wiegand_handler(struct timer_list  *t)
{
    if(dwWgReaderCount == 26)
    {
        dwWgReader = dwWgReader >> 1;//bit26 在数据里: 去掉
        dwWgReader = dwWgReader & 0xffffff;

        if( is_wgdata_valid(26) )
        {
            dwWgData = ((dwWgReader&0xff0000)>>16)
             + (dwWgReader&0xff00)
             + ((dwWgReader&0xff)<<16);
            bWgDataReady = 1;
            dwWgReader = 0;
            dwWgReaderCount = 0;
            g_irq_source = 26;
           // printk("wiegand data:0x%x\033[0m\n", dwWgData);
        }
    } else {
        if (dwWgReaderCount != 0)
            printk("wg count:%d\n", dwWgReaderCount);
    }

    if(dwWgReaderCount == 34)
    {
        dwWgReader>>=1;
        if(is_wgdata_valid(34)) {
            dwWgData = ((dwWgReader&0xff000000)>>24)
             + ((dwWgReader&0xff0000)>>8)
             + ((dwWgReader&0xff00)<<8)
             + ((dwWgReader&0xff)<<24);
            bWgDataReady = 1;
            dwWgReader = 0;
            dwWgReaderCount = 0;
            //printk("wiegand data:0x%x(%d)\033[0m\n", dwWgData,dwWgData);
            g_irq_source = 34;
        }
    }
    if(dwWgReaderCount > 48){
        printk("不支持的dwWgReaderCount::%d\n", dwWgReaderCount);
        bWgDataReady = 0;
        dwWgReader = 0;
        dwWgReaderCount = 0;
    }
    flag_time = 0;
    up(&rf_card->sem);

}

static void irg_func_do(int val)
{
    if( is_timediff_novalid() )
    {
        dwWgReader = 0;
        dwWgReaderCount = 0;
    }

    dwWgReaderCount++;
    if(dwWgReaderCount !=1)
    {
        bit_end = val;
    }

    if (flag_time==0) {
        mod_timer(&rf_card->wiegand_timer, jiffies + HZ / 5); //200ms之后调用定时器处理函数
        flag_time=1;
    }


      //开始位或是结束位
    if(dwWgReaderCount == 1)
    {
        bit_bgn = val;
    }
    else if(dwWgReaderCount >= 48)
    {
        bit_end = val;
    }
    else
    {
        dwWgReader = dwWgReader << 1;

        if(val)
            dwWgReader |= 1;
    }
}

static irqreturn_t wiegand_irq0(int irq, void *dev_id)
{
    int one;
    one=gpio_get_value(rf_card->gpio_d0);
    if(one == 1)
    {
        return 0;
    }    
    irg_func_do(1);

    return IRQ_RETVAL(IRQ_HANDLED);
}

static irqreturn_t wiegand_irq1(int irq, void *dev_id)
{
    int one;
    one=gpio_get_value(rf_card->gpio_d1);
    if(one == 1)
    {
        return 0;
    }    
    irg_func_do(0);

    return IRQ_RETVAL(IRQ_HANDLED);
}

static ssize_t rfcd_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
    int max_count;
    char cardno[12];
    memset(cardno,0,sizeof(cardno));
    if(down_interruptible(&rf_card->sem)) {
        printk(" sem error\n");
        return -1 ;
    }
    max_count = sizeof(cardno);
    if(size >max_count)
    {
        //printk("size and max_count is :%d :%d",size,max_count);
        size = max_count;
        
    }
    sprintf(cardno,"%d",dwWgData);/*((dwWgReader&0xff000000)>>24)
             + ((dwWgReader&0xff0000)>>8)
             + ((dwWgReader&0xff00)<<8)
             + ((dwWgReader&0xff)<<24));*/
    //printk("cardno:(%d)\n",cardno);
    if(copy_to_user((char *)buf,cardno,size)){
            return -EFAULT;
    }
    return size;
}

static ssize_t rfcd_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
    return 0;
}

static int request_irqs(void)
{
    int ret;
    rf_card->d0_irq = gpio_to_irq(rf_card->gpio_d0);
    rf_card->d1_irq = gpio_to_irq(rf_card->gpio_d1);
    printk("%s:d0_irq=%d,d1_irq=%d\n",__func__, rf_card->d0_irq , rf_card->d1_irq );

    ret = request_irq(rf_card->d0_irq,wiegand_irq0,IRQF_SHARED | IRQF_TRIGGER_FALLING,"wiegand_data0",rf_card);

    if(ret)
    {
        printk("%s:request rf_card->d0_irq):%d,ret:%d failed!\n",__func__,rf_card->d0_irq,ret);
        return -1;
    }
    ret = request_irq(rf_card->d1_irq,wiegand_irq1,IRQF_SHARED | IRQF_TRIGGER_FALLING,"wiegand_data1",rf_card);

    if(ret)
    {
        printk("%s:request rf_card->d1_irq:%d,ret:%d failed!\n",__func__,rf_card->d1_irq,ret);
        return -1;
    }
    printk(KERN_INFO"%s:request irqs success!\n",__func__);
    return 0;
}

static int rfcd_open(struct inode *inode, struct file *filp)
{
    printk("start wiegand open \n");
    return 0;
}

static void free_irqs(void)
{
    free_irq(rf_card->d0_irq,rf_card);
    free_irq(rf_card->d1_irq,rf_card);
}

int rfcd_release(struct inode *inode, struct file *filp)
{
    //RF_OPEN_FLAG = false;
    return 0;
}

static struct file_operations rfcd_fops =
{
    .owner = THIS_MODULE,
    .open = rfcd_open,
    .read = rfcd_read,
    .write = rfcd_write,
    .release = rfcd_release,
};

static int __init wiegand_init(void)
{
    int err,result;
    dev_t devno = MKDEV(WIEGAND_MAJOR, 1);
    int ret;
    
    if(0)
        result = register_chrdev_region(devno,1,DEVICE_NAME);
    else
        result = alloc_chrdev_region(&devno,0,1,DEVICE_NAME);

    if(result < 0)
    {
        printk("hl %s:register_chrdev_region error\n",__func__);
        return result;
    }
    rf_card = kmalloc(sizeof(struct wiegand_dev),GFP_KERNEL);
    if (!rf_card)
    {
        result = -ENOMEM;
        goto fail_malloc;
    }

    memset(rf_card,0,sizeof(struct wiegand_dev));
    //rf_card->count = 0;
    cdev_init(&(rf_card->cdev), &rfcd_fops);
    rf_card->cdev.owner = THIS_MODULE;
    err = cdev_add(&rf_card->cdev, devno, 1);

    if(err)
    {
        printk("hl adding err\r\n");
        unregister_chrdev_region(devno,1);
        kfree(rf_card);
        free_irqs();
        return err;
    }

    cdev_class = class_create(THIS_MODULE, DEVICE_NAME);//动态创建设备结点
    if(IS_ERR(cdev_class))
    {
        printk("ERR:cannot create a cdev_class\n");
        unregister_chrdev_region(devno,1);
        return -1;
    }
    device_create(cdev_class,NULL, devno, 0, DEVICE_NAME);

    init_completion(&(rf_card->receive_completion));
    sema_init(&rf_card->sem,0);

    rf_card->gpio_d0 = D0_GPIO_NO;
    rf_card->gpio_d1 = D1_GPIO_NO;

    ret = gpio_request(rf_card->gpio_d0, "wiegand_d0");
    if(ret){
        printk("request gpio_d1 error\n");
        goto fail_malloc;
    }
    ret = gpio_request(rf_card->gpio_d1, "wiegand_d1");
    if(ret){
        printk("request gpio_d1 error\n");
        goto fail_malloc;
    }
    result = request_irqs();

    if(result < 0)
    {
        printk("%s:request_irqs error\n",__func__);
        return result;
    }
    timer_setup(&rf_card->wiegand_timer,wiegand_handler,0);
    //rf_card->wiegand_timer.expires  = jiffies + TIMER_DELAY;
    add_timer(&rf_card->wiegand_timer);

    printk (KERN_INFO "%s initialized\n",DEVICE_NAME);
    return 0;

fail_malloc:
    unregister_chrdev_region(devno,1);
    return result;
}

static void __exit wiegand_exit(void)
{
    cdev_del(&rf_card->cdev);
    free_irqs();
    kfree(rf_card);
    unregister_chrdev_region(MKDEV(WIEGAND_MAJOR,0),1);
    printk (KERN_INFO"%s removed\n",DEVICE_NAME);
}

module_init(wiegand_init);
module_exit(wiegand_exit);

MODULE_AUTHOR("bobo@itayga.com");
MODULE_LICENSE("GPL");
 

wiegand-in.h

#ifndef _WIEGANDIN_H_
#define _WIEGANDIN_H_

#include <linux/cdev.h>
#include <linux/delay.h>
#include <linux/time.h>
#include <linux/semaphore.h>
#include <linux/unistd.h>
#include <linux/of_gpio.h>
#include <dt-bindings/gpio/gpio.h>
#include <linux/gpio.h>


#define WIEGAND_MAJOR 243
//delay 33ms to convert data
#define TIMER_DELAY     HZ/8
#define DEVICE_NAME     "wiegandin"

bool TIMEER_FLAG = false;
bool RF_OPEN_FLAG = false;
static struct class *cdev_class;
//dev_t dev = 0;

#define D0_GPIO_NO      95       
#define D1_GPIO_NO      94       

struct wiegand_dev
{
    struct cdev cdev;
    struct semaphore sem;
    struct completion receive_completion;
    struct timer_list wiegand_timer;
    struct work_struct    pen_event_work;
    struct workqueue_struct *ts_workqueue;

    int gpio_d0;
    int gpio_d1;
    int d0_irq;
    int d1_irq;

};

static struct wiegand_dev *rf_card;

#endif

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值