diff options
| -rw-r--r-- | drivers/acpi/evged.c | 47 |
1 files changed, 41 insertions, 6 deletions
diff --git a/drivers/acpi/evged.c b/drivers/acpi/evged.c index 46f060356a22..f13ba2c07667 100644 --- a/drivers/acpi/evged.c +++ b/drivers/acpi/evged.c | |||
| @@ -49,6 +49,11 @@ | |||
| 49 | 49 | ||
| 50 | #define MODULE_NAME "acpi-ged" | 50 | #define MODULE_NAME "acpi-ged" |
| 51 | 51 | ||
| 52 | struct acpi_ged_device { | ||
| 53 | struct device *dev; | ||
| 54 | struct list_head event_list; | ||
| 55 | }; | ||
| 56 | |||
| 52 | struct acpi_ged_event { | 57 | struct acpi_ged_event { |
| 53 | struct list_head node; | 58 | struct list_head node; |
| 54 | struct device *dev; | 59 | struct device *dev; |
| @@ -76,7 +81,8 @@ static acpi_status acpi_ged_request_interrupt(struct acpi_resource *ares, | |||
| 76 | unsigned int irq; | 81 | unsigned int irq; |
| 77 | unsigned int gsi; | 82 | unsigned int gsi; |
| 78 | unsigned int irqflags = IRQF_ONESHOT; | 83 | unsigned int irqflags = IRQF_ONESHOT; |
| 79 | struct device *dev = context; | 84 | struct acpi_ged_device *geddev = context; |
| 85 | struct device *dev = geddev->dev; | ||
| 80 | acpi_handle handle = ACPI_HANDLE(dev); | 86 | acpi_handle handle = ACPI_HANDLE(dev); |
| 81 | acpi_handle evt_handle; | 87 | acpi_handle evt_handle; |
| 82 | struct resource r; | 88 | struct resource r; |
| @@ -102,8 +108,6 @@ static acpi_status acpi_ged_request_interrupt(struct acpi_resource *ares, | |||
| 102 | return AE_ERROR; | 108 | return AE_ERROR; |
| 103 | } | 109 | } |
| 104 | 110 | ||
| 105 | dev_info(dev, "GED listening GSI %u @ IRQ %u\n", gsi, irq); | ||
| 106 | |||
| 107 | event = devm_kzalloc(dev, sizeof(*event), GFP_KERNEL); | 111 | event = devm_kzalloc(dev, sizeof(*event), GFP_KERNEL); |
| 108 | if (!event) | 112 | if (!event) |
| 109 | return AE_ERROR; | 113 | return AE_ERROR; |
| @@ -116,29 +120,58 @@ static acpi_status acpi_ged_request_interrupt(struct acpi_resource *ares, | |||
| 116 | if (r.flags & IORESOURCE_IRQ_SHAREABLE) | 120 | if (r.flags & IORESOURCE_IRQ_SHAREABLE) |
| 117 | irqflags |= IRQF_SHARED; | 121 | irqflags |= IRQF_SHARED; |
| 118 | 122 | ||
| 119 | if (devm_request_threaded_irq(dev, irq, NULL, acpi_ged_irq_handler, | 123 | if (request_threaded_irq(irq, NULL, acpi_ged_irq_handler, |
| 120 | irqflags, "ACPI:Ged", event)) { | 124 | irqflags, "ACPI:Ged", event)) { |
| 121 | dev_err(dev, "failed to setup event handler for irq %u\n", irq); | 125 | dev_err(dev, "failed to setup event handler for irq %u\n", irq); |
| 122 | return AE_ERROR; | 126 | return AE_ERROR; |
| 123 | } | 127 | } |
| 124 | 128 | ||
| 129 | dev_dbg(dev, "GED listening GSI %u @ IRQ %u\n", gsi, irq); | ||
| 130 | list_add_tail(&event->node, &geddev->event_list); | ||
| 125 | return AE_OK; | 131 | return AE_OK; |
| 126 | } | 132 | } |
| 127 | 133 | ||
| 128 | static int ged_probe(struct platform_device *pdev) | 134 | static int ged_probe(struct platform_device *pdev) |
| 129 | { | 135 | { |
| 136 | struct acpi_ged_device *geddev; | ||
| 130 | acpi_status acpi_ret; | 137 | acpi_status acpi_ret; |
| 131 | 138 | ||
| 139 | geddev = devm_kzalloc(&pdev->dev, sizeof(*geddev), GFP_KERNEL); | ||
| 140 | if (!geddev) | ||
| 141 | return -ENOMEM; | ||
| 142 | |||
| 143 | geddev->dev = &pdev->dev; | ||
| 144 | INIT_LIST_HEAD(&geddev->event_list); | ||
| 132 | acpi_ret = acpi_walk_resources(ACPI_HANDLE(&pdev->dev), "_CRS", | 145 | acpi_ret = acpi_walk_resources(ACPI_HANDLE(&pdev->dev), "_CRS", |
| 133 | acpi_ged_request_interrupt, &pdev->dev); | 146 | acpi_ged_request_interrupt, geddev); |
| 134 | if (ACPI_FAILURE(acpi_ret)) { | 147 | if (ACPI_FAILURE(acpi_ret)) { |
| 135 | dev_err(&pdev->dev, "unable to parse the _CRS record\n"); | 148 | dev_err(&pdev->dev, "unable to parse the _CRS record\n"); |
| 136 | return -EINVAL; | 149 | return -EINVAL; |
| 137 | } | 150 | } |
| 151 | platform_set_drvdata(pdev, geddev); | ||
| 138 | 152 | ||
| 139 | return 0; | 153 | return 0; |
| 140 | } | 154 | } |
| 141 | 155 | ||
| 156 | static void ged_shutdown(struct platform_device *pdev) | ||
| 157 | { | ||
| 158 | struct acpi_ged_device *geddev = platform_get_drvdata(pdev); | ||
| 159 | struct acpi_ged_event *event, *next; | ||
| 160 | |||
| 161 | list_for_each_entry_safe(event, next, &geddev->event_list, node) { | ||
| 162 | free_irq(event->irq, event); | ||
| 163 | list_del(&event->node); | ||
| 164 | dev_dbg(geddev->dev, "GED releasing GSI %u @ IRQ %u\n", | ||
| 165 | event->gsi, event->irq); | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | static int ged_remove(struct platform_device *pdev) | ||
| 170 | { | ||
| 171 | ged_shutdown(pdev); | ||
| 172 | return 0; | ||
| 173 | } | ||
| 174 | |||
| 142 | static const struct acpi_device_id ged_acpi_ids[] = { | 175 | static const struct acpi_device_id ged_acpi_ids[] = { |
| 143 | {"ACPI0013"}, | 176 | {"ACPI0013"}, |
| 144 | {}, | 177 | {}, |
| @@ -146,6 +179,8 @@ static const struct acpi_device_id ged_acpi_ids[] = { | |||
| 146 | 179 | ||
| 147 | static struct platform_driver ged_driver = { | 180 | static struct platform_driver ged_driver = { |
| 148 | .probe = ged_probe, | 181 | .probe = ged_probe, |
| 182 | .remove = ged_remove, | ||
| 183 | .shutdown = ged_shutdown, | ||
| 149 | .driver = { | 184 | .driver = { |
| 150 | .name = MODULE_NAME, | 185 | .name = MODULE_NAME, |
| 151 | .acpi_match_table = ACPI_PTR(ged_acpi_ids), | 186 | .acpi_match_table = ACPI_PTR(ged_acpi_ids), |
