F1C200S 添加韦根驱动笔记(驱动编写)

1、如何把自己写的驱动添加到buildroot配置中可以参考这个文章:

https://bbs.csdn.net/topics/395088534/forums/forums/WindowsMobile

2、韦根驱动分析

1)

添加用于匹配设备树的结构体数组,跟我上一篇文章的设备树相匹配。

static const struct of_device_id gpio_wiegand_of_match[] = {
        { .compatible = "gpio-wiegand", },
        { },
};

2)

编写probe函数

//该代码进过简化方便了解流程,不能直接使用
static int gpio_wiegand_probe(struct platform_device *pdev){
    //通过传入的pdev获取设备指针
    struct device *dev = &pdev->dev;

    struct device_node *node,*pp;

    u32 gpio,ret;

    //通过设备指针获取节点
    node = dev->of_node;

    //dat0  从子节点中找到'gpios'对应的gpio 的标志位
    pp = of_get_next_child(node,NULL);//dat0

    gpio = of_get_named_gpio_flags(pp, "gpios", 0, &flags);
    if(!gpio_is_valid(gpio)){
        return  -EIO;
    }
    
    //申请占用这个管脚
    ret = gpio_request(gpio,"inwieganddata0");

    p_wiegand_data->gpio_dat0 = gpio;

    //由管脚的标志获取该管脚对应的中断号
    p_wiegand_data->irq_dat0 = gpio_to_irq(gpio);

    //output   dat2
    pp = of_get_next_child(node,pp);//dat2
    gpio =  of_get_named_gpio_flags(pp, "gpios", 0, &flags);

    ret = gpio_request(gpio,"inwieganddata2");

    p_wiegand_data->out_gpio_dat0 = gpio;

    //以下是申请设备结点,用于上层对设备的访问
    devno = MKDEV(WIEGAND_MAJOR, 0);
    if(WIEGAND_MAJOR)
        result = register_chrdev_region(devno,1,DEVICE_NAME);
    else
        result = alloc_chrdev_region(&devno,0,1,DEVICE_NAME);

    my_class = class_create(THIS_MODULE,"wiegand class");  //类名为hello_char_class

    device_create(my_class,NULL,devno,NULL,"wiegand");      //设备名为memdev

    rf_card = kmalloc(sizeof(struct wiegand_dev),GFP_KERNEL);

    memset(rf_card,0,sizeof(struct wiegand_dev));
    rf_card->count = 0;
    //传入ops函数
    cdev_init(&(rf_card->cdev), &rfcd_fops);

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

    init_completion(&(rf_card->receive_completion));
    sema_init(&rf_card->sem,0);
    sema_init(&rf_card->sem_output,0);
    sema_init(&rf_card->sem_read,1);
    rf_card->flag_wiegand_read = 0;
    //设定IO的方向是输入
    gpio_direction_input(DATA0);
    gpio_direction_input(DATA1);

    gpio_direction_output(OUTDATA0,1);
    gpio_direction_output(OUTDATA1,1);
    //设定IO的防抖时间
    //gpio_set_debounce(DATA0,1000);
    //gpio_set_debounce(DATA1,1000);
     
    //设定定时器函数
    timer_setup(&rf_card->wiegand_timer,wiegand_do_timer,0);//设定定时器函数
    timer_setup(&rf_card->wiegand_timer_over,wiegand_do_timer_over,0);

    hrtimer_init(&rf_card->out_wiegand_timer_td,CLOCK_MONOTONIC,HRTIMER_MODE_REL);
    rf_card->out_wiegand_timer_td.function = out_wiegand_do_timer_td;
    hrtimer_init(&rf_card->out_wiegand_timer_tw,CLOCK_MONOTONIC,HRTIMER_MODE_REL);
    rf_card->out_wiegand_timer_tw.function = out_wiegand_do_timer_tw;

    //申请相应的io中断,并设定中断触发方式
    result = request_irqs();

    return result;
}

3)fops结构体初始化

static struct file_operations rfcd_fops =
{
    .owner = THIS_MODULE,
    .read = rfcd_read,
    .write = rfcd_write,
    .open = rfcd_open,
    .release = rfcd_release,
    .unlocked_ioctl = rfcd_ioctl,
};

4)申请中断函数

在linux内核中用于申请中断的函数是request_irq(),函数原型在Kernel/irq/manage.c中定义:

int request_irq(unsigned int irq, irq_handler_t handler,
                         unsigned long irqflags, const char *devname, void *dev_id)

irq是要申请的硬件中断号。

handler是向系统注册的中断处理函数,是一个回调函数,中断发生时,系统调用这个函数,dev_id参数将被传递给它。

irqflags是中断处理的属性,若设置了IRQF_DISABLED (老版本中的SA_INTERRUPT,本版zhon已经不支持了),则表示中断处理程序是快速处理程序,快速处理程序被调用时屏蔽所有中断,慢速处理程序不屏蔽;若设置了IRQF_SHARED (老版本中的SA_SHIRQ),则表示多个设备共享中断,若设置了IRQF_SAMPLE_RANDOM(老版本中的SA_SAMPLE_RANDOM),表示对系统熵有贡献,对系统获取随机数有好处。(这几个flag是可以通过或的方式同时使用的)

devname设置中断名称 ,通常是设备驱动程序的名称  在cat /proc/interrupts中可以看到此名称。

dev_id在中断共享时会用到,一般设置为这个设备的设备结构体或者NULL。

request_irq()返回0表示成功,返回-INVAL表示中断号无效或处理函数指针为NULL,返回-EBUSY表示中断已经被占用且不能共享。

static int request_irqs(void)
{
    int ret;
    printk("%s:start request irqs\n",__func__);

    ret = request_irq(gpio_to_irq(DATA0),wiegand_irq0,IRQF_TRIGGER_RISING,"wiegand_data0",rf_card);
    if(ret)
    {
        printk("%s:request IRQ_EINT(17):%d,ret:%d failed!\n",__func__,gpio_to_irq(DATA0),ret);
        return -1;
    }
    ret = request_irq(gpio_to_irq(DATA1),wiegand_irq1,IRQF_TRIGGER_RISING,"wiegand_data1",rf_card);
    if(ret)
    {
        printk("%s:request IRQ_EINT(18):%d,ret:%d failed!\n",__func__,gpio_to_irq(DATA1),ret);
        return -1;
    }
    printk("%s:request irqs success!\n",__func__);

    return 0;
}

5)编写中断处理函数

static irqreturn_t wiegand_irq0(int irq, void *dev_id);

static irqreturn_t wiegand_irq1(int irq, void *dev_id);

在中断处理函数中完成韦根数据的接收。

未完待续

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值