/*
* File Name: rockchip-wiegand.c
* Author: HuKe
* E-Mail: ke_hu@bozztek.com
* Created Time: Sat 11 Aug 2018 01:42:13 PM CST
* Description: 韦根驱动
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/poll.h>
/* Debug */
#if 1
#define DBG(x...) printk(x)
#else
#define DBG(x...) do { } while (0)
#endif
#define WG_CMD_MAX_NR 7
#define WG_CMD_MAGIC 'x'
#define WG_26_MODE _IO(WG_CMD_MAGIC, 0x01)
#define WG_34_MODE _IO(WG_CMD_MAGIC, 0x02)
#define WG_66_MODE _IO(WG_CMD_MAGIC, 0x03)
#define WG_PERIOD_MODE _IO(WG_CMD_MAGIC, 0x04)
#define WG_PULSE_MODE _IO(WG_CMD_MAGIC, 0x05)
#define WG_UNKNOWN_MODE _IO(WG_CMD_MAGIC, 0x07)
#define WG_26_MODE_CMD 0x01
#define WG_34_MODE_CMD 0x02
#define WG_66_MODE_CMD 0x03
#define SET_PERIOD_CMD 0x04
#define SET_PULSE_CMD 0x05
static void recive_data_convert(void);
static int major;
static dev_t devid;
static struct cdev wiegand_cdev;
static struct class *cls;
static unsigned char wiegand[66];
static int bit_count; //Global Bit Counter
static unsigned long gl_barcode;
static unsigned long long barcode_66;
static DECLARE_WAIT_QUEUE_HEAD(read_waitq);//定义读等待队列头
static int convert_finish_flag = 0;
static struct timer_list refresh_timer;
static int flag_timeout = 0;
static int flag_recive_mode;
static int period_time = 250; //unit us
static int pulse_time = 100; //unit us
struct wiegand_io {
int pin_num;
char *name;
int flag_input; // if input mode, flag set to 1
};
static struct wiegand_io wiegand_set[] = {
{69, "WGN_IN_D0", 1}, //GPIO2_A5_U
{70, "WGN_IN_D1", 1}, //GPIO2_A6_U
{71, "WGN_OUT_D0", 0}, //GPIO2_A7_D
{72, "WGN_OUT_D1", 0}, //GPIO2_B0_D
};
/* 定时器中断服务程序
* 主要功能:处理数据,完成韦根数据转换
* 并清空计数值。
*/
static void refresh_timer_function(unsigned long data)
{
flag_timeout = 1;
if (bit_count== 26) {
flag_recive_mode = WG_26_MODE;
} else if (bit_count== 34) {
flag_recive_mode = WG_34_MODE;
} else if (bit_count== 66) {
flag_recive_mode = WG_66_MODE;
} else {
flag_recive_mode = WG_UNKNOWN_MODE;
}
recive_data_convert();
bit_count = 0;
}
static unsigned char even_parity_26_byte(unsigned char* wg_data)
{
unsigned char i, even_val;
unsigned char ret;
even_val = 0;
for(i=12;i<24;i++) {
if((wg_data[i] & 0x01) == 0x01) {
even_val++;
}
}
DBG("%s 1's num = %d\n",__func__, even_val);
if((even_val % 2) == 0) {
ret = 1;
} else {
ret = 0;
}
return ret;
}
static unsigned char odd_parity_26_byte(unsigned char* wg_data)
{
unsigned char i, odd_val;
unsigned char ret;
odd_val = 0;
for(i = 0; i < 12; i++){
if((wg_data[i] & 0x01) == 0x01){
odd_val++;
}
}
DBG("%s 1's num = %d\n",__func__, odd_val);
if((odd_val % 2) == 0)
ret = 0;
else
ret = 1;
return ret;
}
static unsigned char even_parity_34_byte(unsigned char* wg_data)
{
unsigned char i, even_val;
unsigned char ret;
even_val = 0;
for(i = 16; i < 32; i++){
if((wg_data[i] & 0x01) == 0x01){
even_val++;
}
}
DBG("%s 1's num = %d\n",__func__, even_val);
if((even_val % 2) == 0)
ret = 1;
else
ret = 0;
return ret;
}
static unsigned char odd_parity_34_byte(unsigned char* wg_data)
{
unsigned char i, odd_val;
unsigned char ret;
odd_val = 0;
for(i = 0; i < 16; i++){
if((wg_data[i] & 0x01) == 0x01){
odd_val++;
}
}
DBG("%s 1's num = %d\n",__func__, odd_val);
if((odd_val % 2) == 0)
ret = 0;
else
ret = 1;
return ret;
}
static unsigned char even_parity_26(unsigned long wg_data)
{
unsigned char i, even_val;
unsigned char ret;
even_val = 0;
for(i=12;i<24;i++) {
if(((wg_data >> i) & 0x01) == 0x01) {
even_val++;
}
}
DBG("%s 1's num = %d\n",__func__, even_val);
if((even_val % 2) == 0)
ret = 1;
else
ret = 0;
return ret;
}
static unsigned char odd_parity_26(unsigned long wg_data)
{
unsigned char i, odd_val;
unsigned char ret;
odd_val = 0;
for(i = 0; i < 12; i++){
if(((wg_data >> i) & 0x01) == 0x01){
odd_val++;
}
}
DBG("%s 1's num = %d\n",__func__, odd_val);
if((odd_val % 2) == 0)
ret = 0;
else
ret = 1;
return ret;
}
static unsigned char even_parity_34(unsigned long long wg_data)
{
unsigned char i, even_val;
unsigned char ret;
even_val = 0;
for(i = 16; i < 32; i++){
if(((wg_data >> i) & 0x01) == 0x01){
even_val++;
}
}
DBG("%s 1's num = %d\n",__func__, even_val);
if((even_val % 2) == 0)
ret = 1;
else
ret = 0;
return ret;
}
static unsigned char odd_parity_34(unsigned long long wg_data)
{
unsigned char i, odd_val;
unsigned char ret;
odd_val = 0;
for(i = 0; i < 16; i++){
if(((wg_data >> i) & 0x01) == 0x01){
odd_val++;
}
}
DBG("%s 1's num = %d\n",__func__, odd_val);
if((odd_val % 2) == 0)
ret = 0;
else
ret = 1;
return ret;
}
static unsigned char even_parity_66(unsigned long long wg_data)
{
unsigned char i, even_val;
even_val = 0;
for(i = 32; i < 64; i++){
if(((wg_data >> i) & 0x01) == 0x01){
even_val++;
}
}
if((even_val & 0x01) == 0x01)
even_val = 1;
else
even_val = 0;
return even_val;
}
static unsigned char odd_parity_66(unsigned long long wg_data)
{
unsigned char i, odd_val;
odd_val = 0;
for(i = 0; i < 32; i++){
if(((wg_data >> i) & 0x01) == 0x01){
odd_val++;
}
}
if((odd_val & 0x01 ) == 0x01)
odd_val = 0;
else
odd_val = 1;
return odd_val;
}
static unsigned char wiegand_26_to_barcode(unsigned long *data)
{
int i,even,odd,hid,pid;
//偶校验
even = 0;
for(i = 1; i < 13;i++) {
if(wiegand[i] == 1)
even = (~even) & 0x01;
}
if(even != wiegand[0]){
bit_count = 0;
goto error;
}
//奇校验
odd = 1;
for(i = 13; i< 25;i++) {
if(wiegand[i] == 1)
odd = (~odd)& 0x01;
}
if(odd != wiegand[25]) {
bit_count = 0;
goto error;
}
//奇偶校验通过
//hid转换
hid = 0;
for(i = 1 ;i<=8;i++){
hid |= (0x01 & wiegand[i]) << (8-i);
}
//pid转换
pid = 0;
for(i = 9 ;i<25;i++){
pid |= (0x01 & wiegand[i]) << (25-i-1);
}
bit_count = 0;
*data = (hid << 16) | (pid);
return 0;
error:
printk("wiegand_26 Parity Efficacy Error!\n");
return -1;
}
static unsigned char wiegand_34_to_barcode(unsigned long *data)
{
int i,even,odd,hid,pid;
for(i = 0; i < 34;i++) {
printk("%x", wiegand[i]);
}
printk("\n");
//偶校验
even = 0;
for(i = 1; i < 17;i++) {
if(wiegand[i] == 1)
even = (~even) & 0x01;
}
if(even != wiegand[0]){
bit_count = 0;
printk("even bit error\n");
goto error;
}
//寄校验
odd = 1;
for(i = 17; i< 33;i++) {
if(wiegand[i] == 1)
odd = (~odd)& 0x01;
}
if(odd != wiegand[33]) {
bit_count = 0;
printk("odd bit error\n");
goto error;
}
//奇偶校验通过
//hid转换
hid = 0;
for(i = 1 ;i<=16;i++){
hid |= (0x01 & wiegand[i]) << (16-i);
}
//pid转换
pid = 0;
for(i = 17 ;i<33; i++){
pid |= (0x01 & wiegand[i]) << (33-i-1);
}
bit_count = 0;
*data = (hid << 16) | (pid);
return 0;
error:
printk("wiegand_34 Parity Efficacy Error!\n");
return -1;
}
static unsigned char wiegand_66_to_barcode(unsigned long long *data)
{
int i;
unsigned long long hid,pid,even,odd;
//奇校验
even = 0;
for(i = 1; i < 33;i++) {
if(wiegand[i] == 1)
even = (~even) & 0x01;
}
if(even != wiegand[0]){
bit_count = 0;
goto error;
}
//偶校验
odd = 1;
for(i = 33; i< 65;i++) {
if(wiegand[i] == 1)
odd = (~odd)& 0x01;
}
if(odd != wiegand[65]) {
bit_count = 0;
goto error;
}
//奇偶校验通过
//hid转换
hid = 0;
for(i = 1 ;i<=32;i++){
hid |= (unsigned long long )(0x01 & wiegand[i]) << (32-i);
}
//pid转换
pid = 0;
for(i = 33 ;i<=65;i++){
pid |= (unsigned long long )(0x01 & wiegand[i]) << (65-i-1