概述
如果在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 recordn");
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 resourcen");
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 methodn");
return AE_ERROR;
}
dev_info(dev, "GED listening GSI %u @ IRQ %un", 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 %un", 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 failedn");
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的电平中断.
最后
以上就是忧心红牛为你收集整理的gpio 产生Generic Event Device中断的全部内容,希望文章能够帮你解决gpio 产生Generic Event Device中断所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复