gpio 产生Generic Event Device中断

如果在bios中传递ACPI0013的话,就会在kernel中使能Generic Event Device。
static struct platform_driver ged_driver = {
    .probe = ged_probe,
    .driver = {
        .name = MODULE_NAME,
        .acpi_match_table = ACPI_PTR(ged_acpi_ids),
    },
};
builtin_platform_driver(ged_driver);
而builtin_platform_driver 的定义如下:
#define builtin_platform_driver(__platform_driver) \
    builtin_driver(__platform_driver, platform_driver_register)

#define builtin_driver(__driver, __register, ...) \
static int __init __driver##_init(void) \
{ \
    return __register(&(__driver) , ##__VA_ARGS__); \
} \
device_initcall(__driver##_init);

可见最终还是通过device_initcall 来调用platform_driver_register。因为系统已经帮忙调用platform_device_register了.
如果bios中传递ACPI0013的话,就调用ged_probe
static int ged_probe(struct platform_device *pdev)
{
    acpi_status acpi_ret;

    acpi_ret = acpi_walk_resources(ACPI_HANDLE(&pdev->dev), "_CRS",
                       acpi_ged_request_interrupt, &pdev->dev);
    if (ACPI_FAILURE(acpi_ret)) {
        dev_err(&pdev->dev, "unable to parse the _CRS record\n");
        return -EINVAL;
    }

    return 0;
}
在ged_probe中通过acpi_walk_resources 遍历pdev->dev 中的_CRS 资源,然后为每个_CRS 调用acpi_ged_request_interrupt

bios中这个设备对_CRS定义如下:
 * Device (GED0)
 * {
 *
 *     Name (_HID, "ACPI0013")
 *     Name (_UID, 0)
 *     Method (_CRS, 0x0, Serialized)
 *     {
 *        Name (RBUF, ResourceTemplate ()
 *        {
 *        Interrupt(ResourceConsumer, Edge, ActiveHigh, Shared, , , )
 *        {123}
 *        }
 *     })
 *
 *     Method (_EVT, 1) {
 *             if (Lequal(123, Arg0))
 *             {
 *             }
 *     }
 * }

static acpi_status acpi_ged_request_interrupt(struct acpi_resource *ares,
                          void *context)
{
    struct acpi_ged_event *event;
    unsigned int irq;
    unsigned int gsi;
    unsigned int irqflags = IRQF_ONESHOT;
    struct device *dev = context;
    acpi_handle handle = ACPI_HANDLE(dev);
    acpi_handle evt_handle;
    struct resource r;
    struct acpi_resource_irq *p = &ares->data.irq;
    struct acpi_resource_extended_irq *pext = &ares->data.extended_irq;

    if (ares->type == ACPI_RESOURCE_TYPE_END_TAG)
        return AE_OK;
//得到中断
    if (!acpi_dev_resource_interrupt(ares, 0, &r)) {
        dev_err(dev, "unable to parse IRQ resource\n");
        return AE_ERROR;
    }
    if (ares->type == ACPI_RESOURCE_TYPE_IRQ)
        gsi = p->interrupts[0];
    else
        gsi = pext->interrupts[0];
//得到具体的中断号
    irq = r.start;
//通过acpi_get_handle 得到_EVT,这个表示一个函数
    if (ACPI_FAILURE(acpi_get_handle(handle, "_EVT", &evt_handle))) {
        dev_err(dev, "cannot locate _EVT method\n");
        return AE_ERROR;
    }

    dev_info(dev, "GED listening GSI %u @ IRQ %u\n", gsi, irq);
//申请一个acpi_ged_event *event
    event = devm_kzalloc(dev, sizeof(*event), GFP_KERNEL);
    if (!event)
        return AE_ERROR;
//初始化成员
    event->gsi = gsi;
    event->dev = dev;
    event->irq = irq;
    event->handle = evt_handle;

    if (r.flags & IORESOURCE_IRQ_SHAREABLE)
        irqflags |= IRQF_SHARED;
//为irq注册中断,其中断出来函数是acpi_ged_irq_handler
    if (devm_request_threaded_irq(dev, irq, NULL, acpi_ged_irq_handler,
                      irqflags, "ACPI:Ged", event)) {
        dev_err(dev, "failed to setup event handler for irq %u\n", irq);
        return AE_ERROR;
    }

    return AE_OK;
}

static irqreturn_t acpi_ged_irq_handler(int irq, void *data)
{
    struct acpi_ged_event *event = data;
    acpi_status acpi_ret;

    acpi_ret = acpi_execute_simple_method(event->handle, NULL, event->gsi);
    if (ACPI_FAILURE(acpi_ret))
        dev_err_once(event->dev, "IRQ method execution failed\n");

    return IRQ_HANDLED;
}
在acpi_ged_irq_handler中调用acpi_execute_simple_method
acpi_status acpi_execute_simple_method(acpi_handle handle, char *method,
                       u64 arg)
{
    union acpi_object obj = { .type = ACPI_TYPE_INTEGER };
    struct acpi_object_list arg_list = { .count = 1, .pointer = &obj, };

    obj.integer.value = arg;

    return acpi_evaluate_object(handle, method, &arg_list, NULL);
}
最终通过acpi_evaluate_object 来执行handle,这个handle就是_EVT
 Method (_EVT, 1) {
 *             if (Lequal(123, Arg0))
 *             {
 *             }
 *     }
调用这个函数就会产生一个scl的电平中断.

你可能感兴趣的:(Linux,源码分析)