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

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

rk3568-Android11-韦根输入驱动相关推荐

  1. Linux按键输入实验(体验一下输入驱动,实际开发使用input子系统处理)

    目录 Linux下按键驱动原理(使用原子操作) 硬件原理图分析 实验程序编写 修改设备树文件 按键驱动程序编写 编写测试APP(循环读取按键值) 运行测试 编译驱动程序和测试APP 运行测试(whil ...

  2. [RK3568 Android11] 开发之开发者选项中添加USB OTG模式切换(一)

    目录 前言 一.创建全局变量 前言 上一篇已讲底层是怎么设置USB OTG模式<[RK3568 Android11] 教程之USB OTG模式切换>,此篇开始讲解怎么在设置应用->开 ...

  3. Android Things:用户驱动-输入驱动

    一.驱动介绍 输入用户驱动程序为应用程序提供接口,向Android的输入管道注入事件.有了这个API,应用程序可以使用Peripheral I/O模拟一个人机界面的设备(HID)或者连接外部硬件到输入 ...

  4. [RK3568 Android11] 开发之内置默认中文输入法(谷歌输入法)

    总目录链接:[RK3568 Android11] 本专栏说明和总目录 目录 前言 一.下载拼音输入法软件 二.内置谷歌输入法APP

  5. 光耦合器输入驱动电路

    光耦合器输入驱动电路 光耦合器由一个光源和一个光敏检测器组成.在光耦合器或光子耦合对中,耦合依靠一个透明绝缘间隙一侧产生.另一侧检测到的光实现,两侧之间不存在电气连接(少量耦合电容除外).在飞兆半导体 ...

  6. [RK3568 Android11] 教程之硬件中断(实验一)

    总目录链接:[RK3568 Android11] 本专栏说明和总目录 目录 前言 一.中断实验代码 1.实验说明 2.dts设备树配置

  7. [RK3568 Android11] 教程之升级固件方法二(电脑升级Update包)

    目录 一.升级工具 二.升级update.img方法 总目录:[RK3568 Android11] 本专栏说明和总目录 一.升级工具 1.查找USB升级工具         在源码包中已经包含了win ...

  8. RK3568 Android11.0多屏配置

    RK3568 Android11.0 LCD多屏配置 文章目录 RK3568 Android11.0 LCD多屏配置 LCD参数配置 LVDS显示配置 DSI0显示配置 DSI1显示配置 EDP显示配 ...

  9. [RK3568 Android11] 教程之watchdog看门狗应用

    目录 一.watchdogd服务应用 二.开启watchdogd服务 一.watchdogd服务应用 1.rk3568 android11系统中自身带有个watchdogd服务,默认是没有开启,此wa ...

  10. Linux下的按键输入驱动开发

    之前的文章中,介绍了各种各样的花式点灯方法,其本质都是通过操作GPIO输出高低电平,控制灯的亮灭.按键驱动也是要操作GPIO,只不过是要读取GPIO的高低电平.在驱动程序中使用一个整形变量来表示按键值 ...

最新文章

  1. js、jQuery、layer实现弹出层的打开、关闭
  2. java 反射代价_Java反射机制
  3. .exp文件_mini_httpd 任意文件读取漏洞(附EXP脚本)
  4. JVM异常之:方法区溢出OutOfMemoryError: PermGen space
  5. Bootstrap + Thymeleaf——预约维修前端页面设计(UI + JS数据校验 + JSON序列化 + AJAX提交)DEMO
  6. phpst安装memcache扩展_在 Ubuntu/Debian 下安装 PHP7.3 教程
  7. 将语音搜索集成到Google Now中
  8. Spring Boot AOP 实现日志持久化
  9. 文本编码与解码问题解决方案
  10. AS3连接MYSQL数据库
  11. 6.2GPT意境级讲解
  12. Educational Codeforces Round 45 (Rated for Div. 2) G - GCD Counting
  13. Android之断点续传下载(转)
  14. button html ios,iOS实现UIButton图标和文字上下布局
  15. CMMI认证适用的行业范围
  16. 史上最全linux内核配置详解
  17. 用键盘输入一位整数,当输入1~7时,显示对应的英语星期缩写。
  18. gdb调试c语言在poll函数卡住,poll()上的C编程分段错误
  19. 微软电话(中国)激活操作步骤
  20. 南加大计算机本科学费,南加州大学学费多少 本科研究生学费介绍

热门文章

  1. Linux----cut命令详细使用方法
  2. 不限速!免登录!百度网盘下载工具(Yixun)亲测好用
  3. 模块说和神经网络学说_为什么都说神经网络是个黑箱?
  4. CodeMix使用教程:Emmet
  5. 【转】雅典娜与宙斯的对话.(kerberos原理)
  6. java网络高级_Java高级-增高
  7. SRT互联网传输设备技术分享
  8. 关于.bin格式的文件
  9. i7 8750h支持linux,为游戏而生,i7-8750H游戏本推荐
  10. contentprovider数据获取