经过摸索终于把它也弄出来了,话不多说上代码。
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