嵌入式Linux设备驱动开发(二)

本文深入探讨Linux设备驱动中的probe函数,讲解如何验证硬件存在,使用资源,包括时钟和platform_data。probe函数在设备注册的最后阶段工作,负责资源分配、中断处理和其他初始化操作。内容涵盖资源管理、中断申请、设备文件注册以及sysfs文件系统与设备属性的交互。
摘要由CSDN通过智能技术生成

上一篇中介绍到设备驱动如何匹配设备以及绑定设备的,在Linux系统下进行注册,这里将继续介绍probe函数的功能。
5、probe函数
Probe()函数必须验证指定设备的硬件是否真的存在,probe()可以使用设备的资源,包括时钟,platform_data等。一般来说设备是不能被热插拔的,所以可以将probe()函数放在init段里面来节省driver运行时候的内存开销。

probe函数在设备驱动注册最后收尾工作,当设备的device 和其对应的driver 在总线上完成配对之后,系统就调用platform设备的probe函数完成驱动注册最后工作。资源、中断调用函数以及其他相关工作。

probe函数接收到plarform_device这个参数后,就需要从中提取出需要的信息。它一般会通过调用内核提供的platform_get_resource和platform_get_irq等函数来获得相关信息。如通过platform_get_resource获得设备的起始地址后,可以对其进行request_mem_region和ioremap等操作,以便应用程序对其进行操作。通过platform_get_irq得到设备的中断号以后,就可以调用request_irq函数来向系统申请中断。这些操作在设备驱动程序中一般都要完成。
在完成了上面这些工作和一些其他必须的初始化操作后,就可以向系统注册我们在/dev目录下能看在的设备文件了。

/**
 * irfpa_drv_probe -  Probe call for the device.
 //*针对设备探测驱动
 * @pdev:   handle to the platform device structure.
 //*参数是平台设备的结构体。分配存储区,注册设备
 * It does all the memory allocation and registration for the device.//0成功,其他负数
 * Returns 0 on success, negative error otherwise.
 **/
 static int __devinit irfpa_drv_probe(struct platform_device *pdev)
{
    struct resource *irfpa_regs_res;
    struct resource *vdma_regs_res;
    struct resource *vbuf_mem_res;
    struct resource *xinfo_mem_res;
    struct irfpa_drvdata *drvdata;
    dev_t devt;
    int retval;
    //参考设备树文件中对设备包括的几个地址区间
    irfpa_regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    vdma_regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
    vbuf_mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
    xinfo_mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 3);

    if ((!irfpa_regs_res) || (!vdma_regs_res) || (!vbuf_mem_res) || (!xinfo_mem_res)) {
        dev_err(&pdev->dev, "Invalid address.\n");
        return -ENODEV;
    }

/*组合设备号符合dev_t类型
    devt = MKDEV(IRFPA_MAJOR, IRFPA_MINOR);
    retval = register_chrdev_region(devt, IRFPA_DEVICES, DRIVER_NAME);
    if (retval < 0)
        return retval;
*/
    retval = alloc_chrdev_region(&devt, IRFPA_MINOR, IRFPA_DEVICES, DRIVER_NAME);//动态分配设备编号,该函数需要传递给它指定的第一个次设备号firstminor(一般为0)和要分配的设备数count,以及设备名,调用该函数后自动分配得到的设备号保存在dev中。
    if (retval < 0) {
        dev_err(&pdev->dev, "alloc_chrdev_region fail.\n");
        return retval;
    }

    drvdata = kzalloc(sizeof(struct irfpa_drvdata), GFP_KERNEL);//用kzalloc申请内存的时候, 效果等同于先是用 kmalloc() 申请空间 , 然后用 memset() 来初始化 ,所有申请的元素都被初始化为 0.GFP_KERNEL 内核内存的正常分配. 可能睡眠.
    if (!drvdata) {
        dev_err(&pdev->dev, "Couldn't allocate device private record.\n");
        retval = -ENOMEM;
        goto failed0;
    }

    dev_set_drvdata(&pdev->dev, (void *)drvdata);

    drvdata->devt = devt;
    drvdata->is_open = 0;

    mutex_init(&drvdata->sem);

    // == request_mem_region
    if (!request_mem_region(irfpa_regs_res->start, irfpa_regs_res->end - irfpa_regs_res->start + 1, DRIVER_NAME)) {
        dev_err(&pdev->dev, "Couldn't lock memory region at %Lx\n", (unsigned long long) irfpa_regs_res->start);
        retval = -EBUSY;
        goto failed1_1;
    }

    if (!request_mem_region(vdma_regs_res->start, vdma_regs_res->end - vdma_regs_res->start + 1, DRIVER_NAME)) {
        dev_err(&pdev->dev, "Couldn't lock memory region at %Lx\n", (unsigned long long) vdma_regs_res->start);
        retval = -EBUSY;
        goto failed1_2;
    }

    if (!request_mem_region(vbuf_mem_res->start, vbuf_mem_res->end - vbuf_mem_res->start + 1, DRIVER_NAME)) {
        dev_err(&
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值