Android系统韦根调试从驱动到应用(一)

Android系统韦根调试从驱动到应用

软件开发平台:android P 源码。
硬件开发平台:nxp imx8m mini开发板。

本文记录在nxp 8m mini 硬件平台, androidP 源码的软件平台上调试韦根驱动,增加韦根的framework 层,并能在APP 应用层 获取韦根数据的流程。

一.韦根驱动调试
韦根Wiegand,即韦根传感器是一种当交变磁场经过时产生输出电压脉冲的传感器。
Wiegand协议是国际上统一的标准,是由摩托罗拉公司制定的一种通讯协议。它适用于涉及门禁控制系统的读卡器和卡片的许多特性。 它有很多格式,标准的26-bit 应该是最常用的格式。此外,还有34-bit 、37-bit 等格式。 而标准26-bit 格式是一个开放式的格式,这就意味着任何人都可以购买某一特定格式的IC卡,并且这些特定格式的种类是公开可选的。26-Bit格式就是一个广泛使用的工业标准,并且对所有IC卡的用户开放。几乎所有的门禁控制系统都接受标准的26-Bit格式。

硬件设计
可以将Wiegand接口的Data0和Data1两个输出接到MCU的两个IO脚上,采用查询的方式接收数据,但这样接收并不可靠。比较好的方法是将Data0和Data1接到MCU的两个中断引脚上,采用中断的方式接收数据。
韦根信号是两根数据线传输二进制数据,在空闲时段,两线的对0V的电源都为TTL电平的水平,也就是5V,一般通过5K电阻上拉,当有数据传输时,两根线交替地发送100uS低脉冲,当Data0线发脉冲时,数据是0;当Data1发脉冲时,发送的数据是1,不能两根线同时发脉冲。脉冲的间隔时间是1ms.

我们硬件设计VEGEN 用的 SAI5_MCLK , SAI5_RXFS 两个管脚。

在这里插入图片描述
对驱动来说就需要查看GPIO引脚功能。
在这里插入图片描述
文档MUX_MODE 指明 SAI5_MCLK 有三种复用功能.在pins 定义中查得如下。

在这里插入图片描述
这里MX8MM_IOMUXC_SAI5_MCLK_SAI5_MCLK 在DTS 中查得被复用,所以实际 我们选用了
MX8MM_IOMUXC_ECSPI2_SCLK_GPIO5_IO10
在DTS中增加如下代码:
在这里插入图片描述
GPIO5_IO10, GPIO5_IO12 没有被复用,默认是用作GPIO功能. 所以这里不用配置 pinctrl 。否则要配置pinctrl,配置方法参考文档
在这里插入图片描述确认完硬件就可以开始编码了。

#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/slab.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/device.h>
#include <linux/semaphore.h>
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/of_gpio.h>


#define WIEGAND_MAJOR 243
#define TIMER_DELAY HZ/4
#define DEVICE_NAME "wiegand"

bool TIMEER_FLAG = false;

bool READ_FLAG = false;
static struct class *cdev_class;

static DECLARE_WAIT_QUEUE_HEAD( wiegand_wait);// 定义等待队列

struct wiegand_dev
{
    char wiegand[34];  //Wiegand26-34
    int hid;
    int pid;
    int count;  //Global Counter
    struct cdev cdev;
    struct timer_list   wiegand_timer;
    struct work_struct  pen_event_work;
    struct workqueue_struct *ts_workqueue;
    int gpio_d0;//gpio no
    int gpio_d1;
    int d0_irq;// irq no
    int d1_irq;
};

static struct wiegand_dev *rf_card;

static char convert_data26(void)
{
    int i,even,odd;
    int cardno ;

   printk("%s: begin\n", __func__);

   //偶校验
    even = 0;
    for(i = 1; i < 13; i++)
    {
        if(rf_card->wiegand[i] == 1)
        {
            even = (~even) & 0x01;
        }
    }
    if(even != rf_card->wiegand[0])
    {
        rf_card->count = 0;
        printk("%s %d\n", __func__, __LINE__);
        goto error;
    }
   //奇校验
    odd = 1;
    for(i = 13; i< 25; i++)
    {
        if(rf_card->wiegand[i] == 1)
        {
            odd = (~odd)& 0x01;
        }
    }
    if(odd != rf_card->wiegand[25])
    {
        rf_card->count = 0;
        printk("%s %d\n", __func__, __LINE__);
        goto error;
    }

   //奇偶校验通过
    rf_card->hid = 0;
    for(i = 1 ; i<=8; i++) //hid转换
    {
        rf_card->hid = rf_card->hid << 1 | rf_card->wiegand[i];
    }

    rf_card->pid = 0;
    for(i = 9 ; i<=24; i++) //pid转换
    {
        rf_card->pid = rf_card->pid << 1 | rf_card->wiegand[i];
    }

    cardno = rf_card->hid << 16 | rf_card->pid;
    rf_card->count = 0;

    printk("%s cardno=(0x%x, %d) end\n", __func__, cardno, cardno);
    return 0;

error:
    printk("Parity Efficacy Error!\n");
    return -1;
}

static char convert_data34(void)
{
    int i,even,odd;
    int cardno;

   printk("%s: begin\n", __func__);


   //偶校验
    even = 0;
    for(i = 1; i < 17; i++)
    {
        if(rf_card->wiegand[i] == 1)
        {
            even = (~even) & 0x01;
        }
    }
    if(even != rf_card->wiegand[0])
    {
        rf_card->count = 0;
        printk("%s %d\n", __func__, __LINE__);
        goto error;
    }
   //奇校验
    odd = 1;
    for(i = 17; i < 34; i++)
    {
        if(rf_card->wiegand[i] == 1)
        {
            odd = (~odd)& 0x01;
        }
    }
    if(odd != rf_card->wiegand[33])
    {
        rf_card->count = 0;
        printk("%s %d\n", __func__, __LINE__);
        goto error;
    }

   //奇偶校验通过
    rf_card->hid = 0;
    for(i = 1 ; i<=16; i++) //hid转换
    {
        rf_card->hid = rf_card->hid << 1 | rf_card->wiegand[i];
    }

    rf_card->pid = 0;
    for(i = 17 ; i<=32; i++) //pid转换
    {
        rf_card->pid = rf_card->pid << 1 | rf_card->wiegand[i];
    }

    cardno = rf_card->hid << 16 | rf_card->pid;
    rf_card->count = 0;

    printk("wiegandr cardno=(0x%x, %d)\n", cardno, cardno);
    return 0;

error:
    printk("Parity Efficacy Error!\n");
    return -1;
}

//static void wiegand_pen_irq_work(struct work_struct *work)

static void wiegand_do_timer(unsigned long arg)
{

    //printk("rf_card->count=%d arg=%lu\n",rf_card->count, arg);
    printk("%s  card count: %d\n", __func__, rf_card->count );
    disable_irq(rf_card->d0_irq);
    disable_irq(rf_card->d1_irq);//防止wieg_data在转换期间发生变化

   if(rf_card->count == 26)
       convert_data26();
   else if(rf_card->count == 34)
      convert_data34();


    READ_FLAG = true;
   wake_up_interruptible(&wiegand_wait);//唤醒等待队列中的所有的进程

    rf_card->count =0 ;


    enable_irq(rf_card->d0_irq);
    enable_irq(rf_card->d1_irq);
    TIMEER_FLAG = false;

    printk("%s end\n", __func__);

}



static irqreturn_t wiegand_handle_irq0(int irq, void *dev_id)
{
    disable_irq_nosync(rf_card->d0_irq);
    {
        rf_card->wiegand[rf_card->count] = 0;
        rf_card->count++;
    }

    enable_irq(rf_card->d0_irq);

    if(TIMEER_FLAG == false)
    {
        rf_card->wiegand_timer.expires = jiffies + TIMER_DELAY;
        add_timer(&rf_card->wiegand_timer);
        TIMEER_FLAG = true;
    }
    return IRQ_HANDLED;

}

static irqreturn_t wiegand_handle_irq1(int irq, void *dev_id)
{
    disable_irq_nosync(rf_card->d1_irq);
    {
        rf_card->wiegand[rf_card->count] = 1;
        rf_card->count ++;
    }

    enable_irq(rf_card->d1_irq);


    if(TIMEER_FLAG== false)
    {
        rf_card->wiegand_timer.expires = jiffies + TIMER_DELAY;
        add_timer(&rf_card->wiegand_timer);
        TIMEER_FLAG = true;
    }
    return IRQ_HANDLED;
}

static ssize_t wiegand_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
    printk("%s \n", __func__);
    int max_count;
    char cardno[12];
    memset( cardno , 0, sizeof(cardno));

    max_count = sizeof(cardno);

    if(size > max_count)
    {
        size = max_count;
    }
    //等待 队列头部的队列被唤醒,如果READ_FLAG 不为true 则继续等待。
    wait_event_interruptible( wiegand_wait, READ_FLAG);

    sprintf(cardno,"%d",rf_card->hid << 16 | rf_card->pid);
    printk("%s  cardno : %s\n", __func__, cardno );

    copy_to_user(buf, cardno, size);
    READ_FLAG = false;//重置等待队列的条件

    return size;
}

static ssize_t wiegand_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
    printk("%s \n", __func__);
    return 0;
}

static int wiegand_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_handle_irq0,IRQF_SHARED | IRQF_TRIGGER_FALLING,"wiegandr_data0",rf_card);

    if(ret)
    {
        printk("wiegandr %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_handle_irq1,IRQF_SHARED | IRQF_TRIGGER_FALLING,"wiegandr_data1",rf_card);

    if(ret)
    {
        printk("wiegandr %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 wiegand_open(struct inode *inode, struct file *filp)
{
    printk("%s \n", __func__);

    TIMEER_FLAG = false;

   //setup_timer(&rf_card->wiegand_timer,wiegand_do_timer,0);

    memset(rf_card->wiegand, 0x00, 26);
    rf_card->count = 0;

   //enable_irqs();
    printk("%s has been opened \n", __func__);
    return 0;
}

static void free_irqs(void)
{
    free_irq(rf_card->d0_irq,rf_card);
    free_irq(rf_card->d1_irq,rf_card);
}

int wiegand_release(struct inode *inode, struct file *filp)
{
    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 wiegand_probe(struct platform_device *pdev)
{
    dump_stack();
    printk("%s begin \n", __func__);
    const char *str = NULL;
    of_property_read_string(pdev->dev.of_node, "wiegand_name", &str);
    printk("%s wiegand_name %s \n", __func__, str);


    int err,result;
    dev_t devno = MKDEV(WIEGAND_MAJOR, 1);


   //if(WIEGAND_MAJOR)
    if(0)
    {
        result = register_chrdev_region(devno, 1, DEVICE_NAME);
    }
    else
    {
        result = alloc_chrdev_region(&devno, 0, 1, DEVICE_NAME);
    }

    if(result < 0)
    {
        printk("%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), &wiegand_fops);

    rf_card->cdev.owner = THIS_MODULE;

    err = cdev_add(&rf_card->cdev, devno, 1);

    if(err)
    {
        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);

 


    rf_card->gpio_d0 = of_get_named_gpio(pdev->dev.of_node, "wiegn0-gpios", 0);
    rf_card->gpio_d1 = of_get_named_gpio(pdev->dev.of_node, "wiegn1-gpios", 0);
    if (!gpio_is_valid(rf_card->gpio_d0)  || !gpio_is_valid(rf_card->gpio_d1) ) {
        printk("%s -gpio: %d is invalid  -gpio %d is invalid\n",__func__, rf_card->gpio_d0, rf_card->gpio_d1);
    }


    printk("%s gpio_d0 %d, gpio_d1 %d\n", __func__, rf_card->gpio_d0, rf_card->gpio_d1);
    result = devm_gpio_request_one(&pdev->dev,
                        rf_card->gpio_d0,
                        GPIOF_IN,
                        "INTR0");
   if (result) {
       printk("%s request gpio  error  %d\n", __func__, rf_card->gpio_d0);

   }
    result = devm_gpio_request_one(&pdev->dev,
                        rf_card->gpio_d1,
                        GPIOF_IN,
                        "INTR1");
   if (result) {
       printk("%s request gpio  error  %d\n", __func__, rf_card->gpio_d1);

   }

    result = wiegand_request_irqs();

    if(result < 0)
    {
        printk("%s: error\n",__func__);
        return result;
    }

    setup_timer(&rf_card->wiegand_timer, wiegand_do_timer, 0);


    printk("%s  end!\n",__func__);
    return 0;

fail_malloc:
    unregister_chrdev_region(devno,1);

    return result;
   return 0;
}

static void wiegand_shutdown(struct platform_device *pdev)
{
    printk("%s \n", __func__);
}

/* match dts */
static const struct of_device_id of_wiegand_match[] = {
   { .compatible = "wiegand", },
   {},
};

static struct platform_driver  wiegand_driver = {
   .probe    =  wiegand_probe,
   .shutdown  =  wiegand_shutdown,
   .driver       = {
      .name  = "wiegand",
      .of_match_table = of_wiegand_match,
   },
};

static int __init wiegand_init(void)
{
    dump_stack();
    printk("%s\n",__func__);
    int ret = 0;
    ret =platform_driver_register(&wiegand_driver);
    if (ret) {
            printk( " %s failed!\n", __func__);
            return ret;
    }
    printk("%s ok!\n", __func__);
    return ret;
 }

static void __exit wiegand_exit(void)
{
    printk("%s\n",__func__);
    platform_driver_unregister(&wiegand_driver);

    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("xiangshaoxiong");
MODULE_DESCRIPTION(" wiegand driver");
MODULE_LICENSE("GPL");

代码流程从 wiegand_init -> wiegand_probe 完成韦根初始化,当有韦根读卡器来信号触发中断wiegand_handle_irq0,wiegand_handle_irq1,定时器回调函数wiegand_do_timer读出卡号,并将等待队列的条件置为 true并唤醒等待队列的所有进程。此时如果有进程阻塞在 韦根驱动的wiegand_read函数,则可以将卡号拷贝到应用进程空间copy_to_user(buf, cardno, size) 。
我们可以写一个简单的bin文件来验证.

int main(int argc, char **argv)
{
    char val[12]={0};
    char* filename="dev/wiegand";


    fd = open(filename, O_RDWR);//打开dev/wiegand设备文件
    if (fd < 0)//小于0说明没有成功
    {
        printf("error, can't open %s\n", filename);
        return 0;
    }

    if(argc !=1)
    {
        printf("Usage : %s ",argv[0]);
        return 0;
    }
    while(1)
    {
        sleep(1000);
        /* 3. 读文件 */
        printf("read : %s\n", val);
        //阻塞在这里,当有贴卡时 将卡号读出来
        read(fd, val, sizeof(val) );
        printf("read value : %s\n", val);
    }
    return 0;
}

至此完成韦根驱动部分。
参考资料:
《Linux 设备驱动开发详解:基于最新的 Linux4.0 内核》宋宝华 著 等
https://e.coding.net/weidongshan/01_all_series_quickstart.git 韦东山

  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值