1、韦根输入管脚
D0-> GPIO0_PC1
D1-> GPIO0_PC0
uart0 管脚
2、设备树配置
wiegand_input:wiegand-input{
compatible= "wiegand-input";
status="okay";
pinctrl-names="default";
pinctrl-0 = <&wiegand_int>;
input0-gpio = <&gpio0 RK_PC1 IRQ_TYPE_EDGE_RISING>;
input1-gpio = <&gpio0 RK_PC0 IRQ_TYPE_EDGE_RISING>;
};
&pinctrl {
wiegand_gpio{
wiegand_int:wiegand-int{
rockchip,pins=
<0 RK_PC0 RK_FUNC_GPIO &pcfg_pull_none>,
<0 RK_PC1 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
3、驱动代码
#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/of_gpio.h>
#include <linux/semaphore.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/gpio.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <asm/param.h>
#define DEVICE_NAME "wiegand"
//delay 33ms to convert data
#define TIMER_DELAY (HZ/30*8)
struct wiegand_dev{
int hid;
int pid;
int rx_index;
char wiegand[34];
dev_t devno;
struct cdev cdev;
struct device *device;
struct class *cls;
struct device_node *nd;
struct timer_list wiegand_timer;
int timer_flag;
int open_flag;
struct semaphore sema;
int irq_d0;
int irq_d1;
int gpio_d0;
int gpio_d1;
enum of_gpio_flags irq_d0_flags;
enum of_gpio_flags irq_d1_flags;
};
static struct wiegand_dev *pdev_wiegand;
static int convert_data(void)
{
int i,even;//,odd;
// printk("%s:wait wieg_data completed\n",__func__);
//偶校验
even=0;
for(i=0;i<17;i++)
{
even+=pdev_wiegand->wiegand[i];
}
if(even%2==0)
{
}
else
{
goto error;
//printk("Parity even Error!\n");
}
even=0;
for(i=0;i<17;i++)
{
even+=pdev_wiegand->wiegand[17+i];
}
if(even%2==0)
{
goto error;
//printk("Parity odd Error!\n");
}
pdev_wiegand->hid = 0;
for(i = 1 ;i<=16;i++)
pdev_wiegand->hid = pdev_wiegand->hid << 1 |pdev_wiegand->wiegand[i];
pdev_wiegand->pid = 0;
for(i = 17 ;i<=32;i++)
pdev_wiegand->pid = pdev_wiegand->pid << 1 |pdev_wiegand->wiegand[i];
return 0;
error:
printk("Parity Efficacy Error!\n");
return -1;
}
static void func_timer(struct timer_list *t)
{
unsigned int tmp;
disable_irq(pdev_wiegand->irq_d0);
disable_irq(pdev_wiegand->irq_d1);
if(pdev_wiegand->rx_index!=34)
{
memset(pdev_wiegand->wiegand,0,34);
pdev_wiegand->hid=0;
pdev_wiegand->pid=0;
}
else
{
convert_data();
}
tmp=pdev_wiegand->hid<<16|pdev_wiegand->pid;
printk("count:%d :complete convert wieg_data,hid = %x,pid = %x =>%u \n",pdev_wiegand->rx_index,pdev_wiegand->hid,pdev_wiegand->pid,tmp);
pdev_wiegand->timer_flag=false;
pdev_wiegand->rx_index=0;
up(&pdev_wiegand->sema);
enable_irq(pdev_wiegand->irq_d0);
enable_irq(pdev_wiegand->irq_d1);
}
static irqreturn_t func_irq0(int irq,void *dev_id)
{
disable_irq_nosync(pdev_wiegand->irq_d0);
//printk("irq0 read %d\n",pdev_wiegand->rx_index);
udelay(5);
if(gpio_get_value(pdev_wiegand->gpio_d0)==0 && pdev_wiegand->rx_index<34)
{
pdev_wiegand->wiegand[pdev_wiegand->rx_index]=0;
pdev_wiegand->rx_index++;
}
else
{
printk("irq0 read high %d\n",pdev_wiegand->rx_index);
goto end;
}
if(pdev_wiegand->timer_flag==false)
{
pdev_wiegand->wiegand_timer.expires=jiffies+TIMER_DELAY;
add_timer(&pdev_wiegand->wiegand_timer);
pdev_wiegand->timer_flag=true;
}
enable_irq(pdev_wiegand->irq_d0);
return IRQ_HANDLED;
end:
enable_irq(pdev_wiegand->irq_d0);
return IRQ_HANDLED;
}
static irqreturn_t func_irq1(int irq,void *dev_id)
{
disable_irq_nosync(pdev_wiegand->irq_d1);
//printk("irq1 read %d\n",pdev_wiegand->rx_index);
udelay(5);
if(gpio_get_value(pdev_wiegand->gpio_d1)==0 && pdev_wiegand->rx_index<34)
{
pdev_wiegand->wiegand[pdev_wiegand->rx_index]=1;
pdev_wiegand->rx_index++;
}
else
{
printk("irq1 read high %d\n",pdev_wiegand->rx_index);
goto end;
}
if(pdev_wiegand->timer_flag==false)
{
pdev_wiegand->wiegand_timer.expires=jiffies+TIMER_DELAY;
add_timer(&pdev_wiegand->wiegand_timer);
pdev_wiegand->timer_flag=true;
}
enable_irq(pdev_wiegand->irq_d1);
return IRQ_HANDLED;
end:
enable_irq(pdev_wiegand->irq_d1);
return IRQ_HANDLED;
}
static ssize_t wiegand_read(struct file *filp,char __user *buf,size_t size,loff_t *ppos)
{
int ret=down_interruptible(&pdev_wiegand->sema);
ret++;
if(size <= pdev_wiegand->rx_index)
size=pdev_wiegand->rx_index;
return copy_to_user(buf,pdev_wiegand->wiegand,size);
}
static ssize_t wiegand_write(struct file *filp,const char __user *buf,size_t size,loff_t *ppos)
{
return 0;
}
static int wiegand_release(struct inode *node,struct file *filp)
{
disable_irq(pdev_wiegand->irq_d0);
disable_irq(pdev_wiegand->irq_d1);
pdev_wiegand->open_flag=false;
del_timer_sync(&pdev_wiegand->wiegand_timer);
return 0;
}
static int wiegand_open(struct inode *node,struct file *filp)
{
if(pdev_wiegand->open_flag)
{
return -EBUSY;
}
pdev_wiegand->open_flag=true;
pdev_wiegand->timer_flag=false;
timer_setup(&pdev_wiegand->wiegand_timer,func_timer,0);
memset(pdev_wiegand->wiegand,0,34);
pdev_wiegand->rx_index=0;
enable_irq(pdev_wiegand->irq_d0);
enable_irq(pdev_wiegand->irq_d1);
printk("%s:%d failed\n",__func__,__LINE__);
return 0;
}
static struct file_operations wiegand_fops={
.owner = THIS_MODULE,
.read = wiegand_read,
.write = wiegand_write,
.open = wiegand_open,
.release = wiegand_release,
} ;
static int __init wiegand_init(void )
{
int result;
dev_t devno;
result=alloc_chrdev_region(&devno,0,1,DEVICE_NAME);
if(result < 0 )
{
printk("%s:%d failed\n",__func__,__LINE__);
return result;
}
pdev_wiegand=kmalloc(sizeof(struct wiegand_dev),GFP_KERNEL);
if(!pdev_wiegand)
{
result=-ENOMEM;
goto fail_malloc;
}
memset(pdev_wiegand,0,sizeof(struct wiegand_dev));
pdev_wiegand->devno=devno;
pdev_wiegand->rx_index=0;
cdev_init(&(pdev_wiegand->cdev),&wiegand_fops);
pdev_wiegand->cdev.owner=THIS_MODULE;
result=cdev_add(&pdev_wiegand->cdev,devno,1);
if(result)
{
printk("%s:%d failed\n",__func__,__LINE__);
kfree(pdev_wiegand);
goto fail_malloc;
}
pdev_wiegand->cls=class_create(THIS_MODULE,DEVICE_NAME);
if(IS_ERR(pdev_wiegand->cls))
{
printk("%s:%d failed\n",__func__,__LINE__);
kfree(pdev_wiegand);
goto fail_class;
}
pdev_wiegand->device=device_create(pdev_wiegand->cls,NULL,devno,NULL,DEVICE_NAME);
if(IS_ERR(pdev_wiegand->device))
{
printk("%s:%d failed\n",__func__,__LINE__);
goto fail_device;
}
pdev_wiegand->nd=of_find_node_by_path("/wiegand-input");
if(pdev_wiegand->nd==NULL)
{
printk("%s:%d failed\n",__func__,__LINE__);
goto fail_last;
}
pdev_wiegand->gpio_d0=of_get_named_gpio_flags(pdev_wiegand->nd,"input0-gpio",0,(enum of_gpio_flags*)&pdev_wiegand->irq_d0_flags);
pdev_wiegand->gpio_d1=of_get_named_gpio_flags(pdev_wiegand->nd,"input1-gpio",0,(enum of_gpio_flags*)&pdev_wiegand->irq_d1_flags);
#if 0
if(pdev_wiegand->gpio_d0==NULL || pdev_wiegand->gpio_d0==NULL)
{
printk("%s:%d failed\n",__func__,__LINE__);
goto fail_last;
}
#endif
pdev_wiegand->irq_d0=gpio_to_irq(pdev_wiegand->gpio_d0);
pdev_wiegand->irq_d1=gpio_to_irq(pdev_wiegand->gpio_d1);
sema_init(&pdev_wiegand->sema,0);
result=request_threaded_irq(pdev_wiegand->irq_d0,NULL,func_irq0,IRQF_TRIGGER_FALLING|IRQF_ONESHOT,"wiegand-d0",pdev_wiegand);
if(result !=0)
{
printk("%s:%d failed\n",__func__,__LINE__);
goto fail_last;
}
result=request_threaded_irq(pdev_wiegand->irq_d1,NULL,func_irq1,IRQF_TRIGGER_FALLING|IRQF_ONESHOT,"wiegand-d1",pdev_wiegand);
if(result !=0)
{
printk("%s:%d failed\n",__func__,__LINE__);
goto fail_last;
}
disable_irq(pdev_wiegand->irq_d0);
disable_irq(pdev_wiegand->irq_d1);
printk("%s:%d \n",__func__,__LINE__);
return 0;
fail_last:
device_destroy(pdev_wiegand->cls,pdev_wiegand->devno);
fail_device:
class_destroy(pdev_wiegand->cls);
fail_class:
cdev_del(&pdev_wiegand->cdev);
kfree(pdev_wiegand);
fail_malloc:
unregister_chrdev_region(devno,1);
return result;
}
static __exit void wiegand_exit(void )
{
if(pdev_wiegand)
{
free_irq(pdev_wiegand->irq_d0,pdev_wiegand);
free_irq(pdev_wiegand->irq_d1,pdev_wiegand);
device_destroy(pdev_wiegand->cls,pdev_wiegand->devno);
class_destroy(pdev_wiegand->cls);
cdev_del(&pdev_wiegand->cdev);
kfree(pdev_wiegand);
unregister_chrdev_region(pdev_wiegand->devno,1);
}
printk("%s:%d \n",__func__,__LINE__);
}
module_init(wiegand_init);
module_exit(wiegand_exit);
MODULE_AUTHOR("R@BTIOT.cn");
MODULE_LICENSE("GPL");
4、测试程序
static int convert_data(unsigned char wiegand[34],int &hid,int &pid)
{
int i,even;//,odd;
// printk("%s:wait wieg_data completed\n",__func__);
//偶校验
even=0;
for(i=0;i<17;i++)
{
even+=wiegand[i];
}
if(even%2==0)
{
}
else
{
// printk("even err\n");
goto error;
}
even=0;
for(i=0;i<17;i++)
{
even+=wiegand[17+i];
}
if(even%2==0)
{
// printk("odd err\n");
goto error;
}
hid = 0;
for(i = 1 ;i<=16;i++)
hid = hid << 1 |wiegand[i];
pid = 0;
for(i = 17 ;i<=32;i++)
pid = pid << 1 |wiegand[i];
return 0;
error:
printf("Parity Efficacy Error!\n");
return -1;
}
int test_wiegand()
{
int fd = open("/dev/wiegand", O_RDWR | O_NOCTTY | O_NONBLOCK);
if(fd < 0)
{
printf("open wiegand failed\n");
return -1;
}
fd_set fs_set;
struct timeval tv_timeout;
int retval = 0;
FD_ZERO(&fs_set);
FD_SET(fd, &fs_set);
tv_timeout.tv_sec = 0;
tv_timeout.tv_usec = 100000;
unsigned char rbuf[34]={0};
while(1)
{
retval = select(fd + 1, &fs_set, NULL, NULL, &tv_timeout);
if (retval < 0) {
return -1;
} else if (retval == 0) //time out
{
printf("timeout \n");
} else {
retval = FD_ISSET(fd, &fs_set);
if (retval > 0) {
memset(rbuf,0,34);
if(read(fd,rbuf,34)<0)
{
printf("read error \n");
}
else
{
int hid,pid;
convert_data(rbuf,hid,pid);
printf("done hid:%4x pid:%x %lld \n",hid,pid,hid<<16|pid);
}
}
}
}
return 0;
}