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
rk3568-Android11-韦根输入驱动相关推荐
- Linux按键输入实验(体验一下输入驱动,实际开发使用input子系统处理)
目录 Linux下按键驱动原理(使用原子操作) 硬件原理图分析 实验程序编写 修改设备树文件 按键驱动程序编写 编写测试APP(循环读取按键值) 运行测试 编译驱动程序和测试APP 运行测试(whil ...
- [RK3568 Android11] 开发之开发者选项中添加USB OTG模式切换(一)
目录 前言 一.创建全局变量 前言 上一篇已讲底层是怎么设置USB OTG模式<[RK3568 Android11] 教程之USB OTG模式切换>,此篇开始讲解怎么在设置应用->开 ...
- Android Things:用户驱动-输入驱动
一.驱动介绍 输入用户驱动程序为应用程序提供接口,向Android的输入管道注入事件.有了这个API,应用程序可以使用Peripheral I/O模拟一个人机界面的设备(HID)或者连接外部硬件到输入 ...
- [RK3568 Android11] 开发之内置默认中文输入法(谷歌输入法)
总目录链接:[RK3568 Android11] 本专栏说明和总目录 目录 前言 一.下载拼音输入法软件 二.内置谷歌输入法APP
- 光耦合器输入驱动电路
光耦合器输入驱动电路 光耦合器由一个光源和一个光敏检测器组成.在光耦合器或光子耦合对中,耦合依靠一个透明绝缘间隙一侧产生.另一侧检测到的光实现,两侧之间不存在电气连接(少量耦合电容除外).在飞兆半导体 ...
- [RK3568 Android11] 教程之硬件中断(实验一)
总目录链接:[RK3568 Android11] 本专栏说明和总目录 目录 前言 一.中断实验代码 1.实验说明 2.dts设备树配置
- [RK3568 Android11] 教程之升级固件方法二(电脑升级Update包)
目录 一.升级工具 二.升级update.img方法 总目录:[RK3568 Android11] 本专栏说明和总目录 一.升级工具 1.查找USB升级工具 在源码包中已经包含了win ...
- RK3568 Android11.0多屏配置
RK3568 Android11.0 LCD多屏配置 文章目录 RK3568 Android11.0 LCD多屏配置 LCD参数配置 LVDS显示配置 DSI0显示配置 DSI1显示配置 EDP显示配 ...
- [RK3568 Android11] 教程之watchdog看门狗应用
目录 一.watchdogd服务应用 二.开启watchdogd服务 一.watchdogd服务应用 1.rk3568 android11系统中自身带有个watchdogd服务,默认是没有开启,此wa ...
- Linux下的按键输入驱动开发
之前的文章中,介绍了各种各样的花式点灯方法,其本质都是通过操作GPIO输出高低电平,控制灯的亮灭.按键驱动也是要操作GPIO,只不过是要读取GPIO的高低电平.在驱动程序中使用一个整形变量来表示按键值 ...
最新文章
- js、jQuery、layer实现弹出层的打开、关闭
- java 反射代价_Java反射机制
- .exp文件_mini_httpd 任意文件读取漏洞(附EXP脚本)
- JVM异常之:方法区溢出OutOfMemoryError: PermGen space
- Bootstrap + Thymeleaf——预约维修前端页面设计(UI + JS数据校验 + JSON序列化 + AJAX提交)DEMO
- phpst安装memcache扩展_在 Ubuntu/Debian 下安装 PHP7.3 教程
- 将语音搜索集成到Google Now中
- Spring Boot AOP 实现日志持久化
- 文本编码与解码问题解决方案
- AS3连接MYSQL数据库
- 6.2GPT意境级讲解
- Educational Codeforces Round 45 (Rated for Div. 2) G - GCD Counting
- Android之断点续传下载(转)
- button html ios,iOS实现UIButton图标和文字上下布局
- CMMI认证适用的行业范围
- 史上最全linux内核配置详解
- 用键盘输入一位整数,当输入1~7时,显示对应的英语星期缩写。
- gdb调试c语言在poll函数卡住,poll()上的C编程分段错误
- 微软电话(中国)激活操作步骤
- 南加大计算机本科学费,南加州大学学费多少 本科研究生学费介绍