0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/acpi.h>
0014 #include <linux/device.h>
0015 #include <linux/export.h>
0016 #include <linux/ioport.h>
0017 #include <linux/slab.h>
0018 #include <linux/irq.h>
0019 #include <linux/dmi.h>
0020
0021 #ifdef CONFIG_X86
0022 #define valid_IRQ(i) (((i) != 0) && ((i) != 2))
0023 static inline bool acpi_iospace_resource_valid(struct resource *res)
0024 {
0025
0026 return res->end < 0x10003;
0027 }
0028 #else
0029 #define valid_IRQ(i) (true)
0030
0031
0032
0033
0034
0035 static inline bool
0036 acpi_iospace_resource_valid(struct resource *res) { return true; }
0037 #endif
0038
0039 #if IS_ENABLED(CONFIG_ACPI_GENERIC_GSI)
0040 static inline bool is_gsi(struct acpi_resource_extended_irq *ext_irq)
0041 {
0042 return ext_irq->resource_source.string_length == 0 &&
0043 ext_irq->producer_consumer == ACPI_CONSUMER;
0044 }
0045 #else
0046 static inline bool is_gsi(struct acpi_resource_extended_irq *ext_irq)
0047 {
0048 return true;
0049 }
0050 #endif
0051
0052 static bool acpi_dev_resource_len_valid(u64 start, u64 end, u64 len, bool io)
0053 {
0054 u64 reslen = end - start + 1;
0055
0056
0057
0058
0059
0060
0061
0062
0063 if (len && reslen && start <= end)
0064 return true;
0065
0066 pr_debug("ACPI: invalid or unassigned resource %s [%016llx - %016llx] length [%016llx]\n",
0067 io ? "io" : "mem", start, end, len);
0068
0069 return false;
0070 }
0071
0072 static void acpi_dev_memresource_flags(struct resource *res, u64 len,
0073 u8 write_protect)
0074 {
0075 res->flags = IORESOURCE_MEM;
0076
0077 if (!acpi_dev_resource_len_valid(res->start, res->end, len, false))
0078 res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET;
0079
0080 if (write_protect == ACPI_READ_WRITE_MEMORY)
0081 res->flags |= IORESOURCE_MEM_WRITEABLE;
0082 }
0083
0084 static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len,
0085 u8 write_protect)
0086 {
0087 res->start = start;
0088 res->end = start + len - 1;
0089 acpi_dev_memresource_flags(res, len, write_protect);
0090 }
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106 bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res)
0107 {
0108 struct acpi_resource_memory24 *memory24;
0109 struct acpi_resource_memory32 *memory32;
0110 struct acpi_resource_fixed_memory32 *fixed_memory32;
0111
0112 switch (ares->type) {
0113 case ACPI_RESOURCE_TYPE_MEMORY24:
0114 memory24 = &ares->data.memory24;
0115 acpi_dev_get_memresource(res, memory24->minimum << 8,
0116 memory24->address_length << 8,
0117 memory24->write_protect);
0118 break;
0119 case ACPI_RESOURCE_TYPE_MEMORY32:
0120 memory32 = &ares->data.memory32;
0121 acpi_dev_get_memresource(res, memory32->minimum,
0122 memory32->address_length,
0123 memory32->write_protect);
0124 break;
0125 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
0126 fixed_memory32 = &ares->data.fixed_memory32;
0127 acpi_dev_get_memresource(res, fixed_memory32->address,
0128 fixed_memory32->address_length,
0129 fixed_memory32->write_protect);
0130 break;
0131 default:
0132 res->flags = 0;
0133 return false;
0134 }
0135
0136 return !(res->flags & IORESOURCE_DISABLED);
0137 }
0138 EXPORT_SYMBOL_GPL(acpi_dev_resource_memory);
0139
0140 static void acpi_dev_ioresource_flags(struct resource *res, u64 len,
0141 u8 io_decode, u8 translation_type)
0142 {
0143 res->flags = IORESOURCE_IO;
0144
0145 if (!acpi_dev_resource_len_valid(res->start, res->end, len, true))
0146 res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET;
0147
0148 if (!acpi_iospace_resource_valid(res))
0149 res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET;
0150
0151 if (io_decode == ACPI_DECODE_16)
0152 res->flags |= IORESOURCE_IO_16BIT_ADDR;
0153 if (translation_type == ACPI_SPARSE_TRANSLATION)
0154 res->flags |= IORESOURCE_IO_SPARSE;
0155 }
0156
0157 static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len,
0158 u8 io_decode)
0159 {
0160 res->start = start;
0161 res->end = start + len - 1;
0162 acpi_dev_ioresource_flags(res, len, io_decode, 0);
0163 }
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179 bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res)
0180 {
0181 struct acpi_resource_io *io;
0182 struct acpi_resource_fixed_io *fixed_io;
0183
0184 switch (ares->type) {
0185 case ACPI_RESOURCE_TYPE_IO:
0186 io = &ares->data.io;
0187 acpi_dev_get_ioresource(res, io->minimum,
0188 io->address_length,
0189 io->io_decode);
0190 break;
0191 case ACPI_RESOURCE_TYPE_FIXED_IO:
0192 fixed_io = &ares->data.fixed_io;
0193 acpi_dev_get_ioresource(res, fixed_io->address,
0194 fixed_io->address_length,
0195 ACPI_DECODE_10);
0196 break;
0197 default:
0198 res->flags = 0;
0199 return false;
0200 }
0201
0202 return !(res->flags & IORESOURCE_DISABLED);
0203 }
0204 EXPORT_SYMBOL_GPL(acpi_dev_resource_io);
0205
0206 static bool acpi_decode_space(struct resource_win *win,
0207 struct acpi_resource_address *addr,
0208 struct acpi_address64_attribute *attr)
0209 {
0210 u8 iodec = attr->granularity == 0xfff ? ACPI_DECODE_10 : ACPI_DECODE_16;
0211 bool wp = addr->info.mem.write_protect;
0212 u64 len = attr->address_length;
0213 u64 start, end, offset = 0;
0214 struct resource *res = &win->res;
0215
0216
0217
0218
0219
0220 if ((addr->min_address_fixed != addr->max_address_fixed && len) ||
0221 (addr->min_address_fixed && addr->max_address_fixed && !len))
0222 pr_debug("ACPI: Invalid address space min_addr_fix %d, max_addr_fix %d, len %llx\n",
0223 addr->min_address_fixed, addr->max_address_fixed, len);
0224
0225
0226
0227
0228
0229
0230
0231
0232 if (addr->producer_consumer == ACPI_PRODUCER)
0233 offset = attr->translation_offset;
0234 else if (attr->translation_offset)
0235 pr_debug("ACPI: translation_offset(%lld) is invalid for non-bridge device.\n",
0236 attr->translation_offset);
0237 start = attr->minimum + offset;
0238 end = attr->maximum + offset;
0239
0240 win->offset = offset;
0241 res->start = start;
0242 res->end = end;
0243 if (sizeof(resource_size_t) < sizeof(u64) &&
0244 (offset != win->offset || start != res->start || end != res->end)) {
0245 pr_warn("acpi resource window ([%#llx-%#llx] ignored, not CPU addressable)\n",
0246 attr->minimum, attr->maximum);
0247 return false;
0248 }
0249
0250 switch (addr->resource_type) {
0251 case ACPI_MEMORY_RANGE:
0252 acpi_dev_memresource_flags(res, len, wp);
0253 break;
0254 case ACPI_IO_RANGE:
0255 acpi_dev_ioresource_flags(res, len, iodec,
0256 addr->info.io.translation_type);
0257 break;
0258 case ACPI_BUS_NUMBER_RANGE:
0259 res->flags = IORESOURCE_BUS;
0260 break;
0261 default:
0262 return false;
0263 }
0264
0265 if (addr->producer_consumer == ACPI_PRODUCER)
0266 res->flags |= IORESOURCE_WINDOW;
0267
0268 if (addr->info.mem.caching == ACPI_PREFETCHABLE_MEMORY)
0269 res->flags |= IORESOURCE_PREFETCH;
0270
0271 return !(res->flags & IORESOURCE_DISABLED);
0272 }
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289 bool acpi_dev_resource_address_space(struct acpi_resource *ares,
0290 struct resource_win *win)
0291 {
0292 struct acpi_resource_address64 addr;
0293
0294 win->res.flags = 0;
0295 if (ACPI_FAILURE(acpi_resource_to_address64(ares, &addr)))
0296 return false;
0297
0298 return acpi_decode_space(win, (struct acpi_resource_address *)&addr,
0299 &addr.address);
0300 }
0301 EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space);
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318 bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares,
0319 struct resource_win *win)
0320 {
0321 struct acpi_resource_extended_address64 *ext_addr;
0322
0323 win->res.flags = 0;
0324 if (ares->type != ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64)
0325 return false;
0326
0327 ext_addr = &ares->data.ext_address64;
0328
0329 return acpi_decode_space(win, (struct acpi_resource_address *)ext_addr,
0330 &ext_addr->address);
0331 }
0332 EXPORT_SYMBOL_GPL(acpi_dev_resource_ext_address_space);
0333
0334
0335
0336
0337
0338
0339
0340 unsigned long acpi_dev_irq_flags(u8 triggering, u8 polarity, u8 shareable)
0341 {
0342 unsigned long flags;
0343
0344 if (triggering == ACPI_LEVEL_SENSITIVE)
0345 flags = polarity == ACPI_ACTIVE_LOW ?
0346 IORESOURCE_IRQ_LOWLEVEL : IORESOURCE_IRQ_HIGHLEVEL;
0347 else
0348 flags = polarity == ACPI_ACTIVE_LOW ?
0349 IORESOURCE_IRQ_LOWEDGE : IORESOURCE_IRQ_HIGHEDGE;
0350
0351 if (shareable == ACPI_SHARED)
0352 flags |= IORESOURCE_IRQ_SHAREABLE;
0353
0354 return flags | IORESOURCE_IRQ;
0355 }
0356 EXPORT_SYMBOL_GPL(acpi_dev_irq_flags);
0357
0358
0359
0360
0361
0362
0363 unsigned int acpi_dev_get_irq_type(int triggering, int polarity)
0364 {
0365 switch (polarity) {
0366 case ACPI_ACTIVE_LOW:
0367 return triggering == ACPI_EDGE_SENSITIVE ?
0368 IRQ_TYPE_EDGE_FALLING :
0369 IRQ_TYPE_LEVEL_LOW;
0370 case ACPI_ACTIVE_HIGH:
0371 return triggering == ACPI_EDGE_SENSITIVE ?
0372 IRQ_TYPE_EDGE_RISING :
0373 IRQ_TYPE_LEVEL_HIGH;
0374 case ACPI_ACTIVE_BOTH:
0375 if (triggering == ACPI_EDGE_SENSITIVE)
0376 return IRQ_TYPE_EDGE_BOTH;
0377 fallthrough;
0378 default:
0379 return IRQ_TYPE_NONE;
0380 }
0381 }
0382 EXPORT_SYMBOL_GPL(acpi_dev_get_irq_type);
0383
0384 static const struct dmi_system_id medion_laptop[] = {
0385 {
0386 .ident = "MEDION P15651",
0387 .matches = {
0388 DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
0389 DMI_MATCH(DMI_BOARD_NAME, "M15T"),
0390 },
0391 },
0392 {
0393 .ident = "MEDION S17405",
0394 .matches = {
0395 DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
0396 DMI_MATCH(DMI_BOARD_NAME, "M17T"),
0397 },
0398 },
0399 { }
0400 };
0401
0402 struct irq_override_cmp {
0403 const struct dmi_system_id *system;
0404 unsigned char irq;
0405 unsigned char triggering;
0406 unsigned char polarity;
0407 unsigned char shareable;
0408 };
0409
0410 static const struct irq_override_cmp skip_override_table[] = {
0411 { medion_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0 },
0412 };
0413
0414 static bool acpi_dev_irq_override(u32 gsi, u8 triggering, u8 polarity,
0415 u8 shareable)
0416 {
0417 int i;
0418
0419 #ifdef CONFIG_X86
0420
0421
0422
0423
0424
0425 if (boot_cpu_has(X86_FEATURE_ZEN))
0426 return false;
0427 #endif
0428
0429 for (i = 0; i < ARRAY_SIZE(skip_override_table); i++) {
0430 const struct irq_override_cmp *entry = &skip_override_table[i];
0431
0432 if (dmi_check_system(entry->system) &&
0433 entry->irq == gsi &&
0434 entry->triggering == triggering &&
0435 entry->polarity == polarity &&
0436 entry->shareable == shareable)
0437 return false;
0438 }
0439
0440 return true;
0441 }
0442
0443 static void acpi_dev_get_irqresource(struct resource *res, u32 gsi,
0444 u8 triggering, u8 polarity, u8 shareable,
0445 bool check_override)
0446 {
0447 int irq, p, t;
0448
0449 if (!valid_IRQ(gsi)) {
0450 irqresource_disabled(res, gsi);
0451 return;
0452 }
0453
0454
0455
0456
0457
0458
0459
0460
0461
0462
0463
0464 if (check_override &&
0465 acpi_dev_irq_override(gsi, triggering, polarity, shareable) &&
0466 !acpi_get_override_irq(gsi, &t, &p)) {
0467 u8 trig = t ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE;
0468 u8 pol = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
0469
0470 if (triggering != trig || polarity != pol) {
0471 pr_warn("ACPI: IRQ %d override to %s, %s\n", gsi,
0472 t ? "level" : "edge", p ? "low" : "high");
0473 triggering = trig;
0474 polarity = pol;
0475 }
0476 }
0477
0478 res->flags = acpi_dev_irq_flags(triggering, polarity, shareable);
0479 irq = acpi_register_gsi(NULL, gsi, triggering, polarity);
0480 if (irq >= 0) {
0481 res->start = irq;
0482 res->end = irq;
0483 } else {
0484 irqresource_disabled(res, gsi);
0485 }
0486 }
0487
0488
0489
0490
0491
0492
0493
0494
0495
0496
0497
0498
0499
0500
0501
0502
0503
0504
0505
0506
0507 bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index,
0508 struct resource *res)
0509 {
0510 struct acpi_resource_irq *irq;
0511 struct acpi_resource_extended_irq *ext_irq;
0512
0513 switch (ares->type) {
0514 case ACPI_RESOURCE_TYPE_IRQ:
0515
0516
0517
0518
0519 irq = &ares->data.irq;
0520 if (index >= irq->interrupt_count) {
0521 irqresource_disabled(res, 0);
0522 return false;
0523 }
0524 acpi_dev_get_irqresource(res, irq->interrupts[index],
0525 irq->triggering, irq->polarity,
0526 irq->shareable, true);
0527 break;
0528 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
0529 ext_irq = &ares->data.extended_irq;
0530 if (index >= ext_irq->interrupt_count) {
0531 irqresource_disabled(res, 0);
0532 return false;
0533 }
0534 if (is_gsi(ext_irq))
0535 acpi_dev_get_irqresource(res, ext_irq->interrupts[index],
0536 ext_irq->triggering, ext_irq->polarity,
0537 ext_irq->shareable, false);
0538 else
0539 irqresource_disabled(res, 0);
0540 break;
0541 default:
0542 res->flags = 0;
0543 return false;
0544 }
0545
0546 return true;
0547 }
0548 EXPORT_SYMBOL_GPL(acpi_dev_resource_interrupt);
0549
0550
0551
0552
0553
0554 void acpi_dev_free_resource_list(struct list_head *list)
0555 {
0556 resource_list_free(list);
0557 }
0558 EXPORT_SYMBOL_GPL(acpi_dev_free_resource_list);
0559
0560 struct res_proc_context {
0561 struct list_head *list;
0562 int (*preproc)(struct acpi_resource *, void *);
0563 void *preproc_data;
0564 int count;
0565 int error;
0566 };
0567
0568 static acpi_status acpi_dev_new_resource_entry(struct resource_win *win,
0569 struct res_proc_context *c)
0570 {
0571 struct resource_entry *rentry;
0572
0573 rentry = resource_list_create_entry(NULL, 0);
0574 if (!rentry) {
0575 c->error = -ENOMEM;
0576 return AE_NO_MEMORY;
0577 }
0578 *rentry->res = win->res;
0579 rentry->offset = win->offset;
0580 resource_list_add_tail(rentry, c->list);
0581 c->count++;
0582 return AE_OK;
0583 }
0584
0585 static acpi_status acpi_dev_process_resource(struct acpi_resource *ares,
0586 void *context)
0587 {
0588 struct res_proc_context *c = context;
0589 struct resource_win win;
0590 struct resource *res = &win.res;
0591 int i;
0592
0593 if (c->preproc) {
0594 int ret;
0595
0596 ret = c->preproc(ares, c->preproc_data);
0597 if (ret < 0) {
0598 c->error = ret;
0599 return AE_ABORT_METHOD;
0600 } else if (ret > 0) {
0601 return AE_OK;
0602 }
0603 }
0604
0605 memset(&win, 0, sizeof(win));
0606
0607 if (acpi_dev_resource_memory(ares, res)
0608 || acpi_dev_resource_io(ares, res)
0609 || acpi_dev_resource_address_space(ares, &win)
0610 || acpi_dev_resource_ext_address_space(ares, &win))
0611 return acpi_dev_new_resource_entry(&win, c);
0612
0613 for (i = 0; acpi_dev_resource_interrupt(ares, i, res); i++) {
0614 acpi_status status;
0615
0616 status = acpi_dev_new_resource_entry(&win, c);
0617 if (ACPI_FAILURE(status))
0618 return status;
0619 }
0620
0621 return AE_OK;
0622 }
0623
0624 static int __acpi_dev_get_resources(struct acpi_device *adev,
0625 struct list_head *list,
0626 int (*preproc)(struct acpi_resource *, void *),
0627 void *preproc_data, char *method)
0628 {
0629 struct res_proc_context c;
0630 acpi_status status;
0631
0632 if (!adev || !adev->handle || !list_empty(list))
0633 return -EINVAL;
0634
0635 if (!acpi_has_method(adev->handle, method))
0636 return 0;
0637
0638 c.list = list;
0639 c.preproc = preproc;
0640 c.preproc_data = preproc_data;
0641 c.count = 0;
0642 c.error = 0;
0643 status = acpi_walk_resources(adev->handle, method,
0644 acpi_dev_process_resource, &c);
0645 if (ACPI_FAILURE(status)) {
0646 acpi_dev_free_resource_list(list);
0647 return c.error ? c.error : -EIO;
0648 }
0649
0650 return c.count;
0651 }
0652
0653
0654
0655
0656
0657
0658
0659
0660
0661
0662
0663
0664
0665
0666
0667
0668
0669
0670
0671
0672
0673
0674
0675
0676
0677 int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list,
0678 int (*preproc)(struct acpi_resource *, void *),
0679 void *preproc_data)
0680 {
0681 return __acpi_dev_get_resources(adev, list, preproc, preproc_data,
0682 METHOD_NAME__CRS);
0683 }
0684 EXPORT_SYMBOL_GPL(acpi_dev_get_resources);
0685
0686 static int is_memory(struct acpi_resource *ares, void *not_used)
0687 {
0688 struct resource_win win;
0689 struct resource *res = &win.res;
0690
0691 memset(&win, 0, sizeof(win));
0692
0693 return !(acpi_dev_resource_memory(ares, res)
0694 || acpi_dev_resource_address_space(ares, &win)
0695 || acpi_dev_resource_ext_address_space(ares, &win));
0696 }
0697
0698
0699
0700
0701
0702
0703
0704
0705
0706
0707
0708
0709
0710
0711
0712
0713
0714 int acpi_dev_get_dma_resources(struct acpi_device *adev, struct list_head *list)
0715 {
0716 return __acpi_dev_get_resources(adev, list, is_memory, NULL,
0717 METHOD_NAME__DMA);
0718 }
0719 EXPORT_SYMBOL_GPL(acpi_dev_get_dma_resources);
0720
0721
0722
0723
0724
0725
0726
0727
0728
0729
0730 int acpi_dev_filter_resource_type(struct acpi_resource *ares,
0731 unsigned long types)
0732 {
0733 unsigned long type = 0;
0734
0735 switch (ares->type) {
0736 case ACPI_RESOURCE_TYPE_MEMORY24:
0737 case ACPI_RESOURCE_TYPE_MEMORY32:
0738 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
0739 type = IORESOURCE_MEM;
0740 break;
0741 case ACPI_RESOURCE_TYPE_IO:
0742 case ACPI_RESOURCE_TYPE_FIXED_IO:
0743 type = IORESOURCE_IO;
0744 break;
0745 case ACPI_RESOURCE_TYPE_IRQ:
0746 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
0747 type = IORESOURCE_IRQ;
0748 break;
0749 case ACPI_RESOURCE_TYPE_DMA:
0750 case ACPI_RESOURCE_TYPE_FIXED_DMA:
0751 type = IORESOURCE_DMA;
0752 break;
0753 case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
0754 type = IORESOURCE_REG;
0755 break;
0756 case ACPI_RESOURCE_TYPE_ADDRESS16:
0757 case ACPI_RESOURCE_TYPE_ADDRESS32:
0758 case ACPI_RESOURCE_TYPE_ADDRESS64:
0759 case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
0760 if (ares->data.address.resource_type == ACPI_MEMORY_RANGE)
0761 type = IORESOURCE_MEM;
0762 else if (ares->data.address.resource_type == ACPI_IO_RANGE)
0763 type = IORESOURCE_IO;
0764 else if (ares->data.address.resource_type ==
0765 ACPI_BUS_NUMBER_RANGE)
0766 type = IORESOURCE_BUS;
0767 break;
0768 default:
0769 break;
0770 }
0771
0772 return (type & types) ? 0 : 1;
0773 }
0774 EXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type);
0775
0776 static int acpi_dev_consumes_res(struct acpi_device *adev, struct resource *res)
0777 {
0778 struct list_head resource_list;
0779 struct resource_entry *rentry;
0780 int ret, found = 0;
0781
0782 INIT_LIST_HEAD(&resource_list);
0783 ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
0784 if (ret < 0)
0785 return 0;
0786
0787 list_for_each_entry(rentry, &resource_list, node) {
0788 if (resource_contains(rentry->res, res)) {
0789 found = 1;
0790 break;
0791 }
0792
0793 }
0794
0795 acpi_dev_free_resource_list(&resource_list);
0796 return found;
0797 }
0798
0799 static acpi_status acpi_res_consumer_cb(acpi_handle handle, u32 depth,
0800 void *context, void **ret)
0801 {
0802 struct resource *res = context;
0803 struct acpi_device **consumer = (struct acpi_device **) ret;
0804 struct acpi_device *adev = acpi_fetch_acpi_dev(handle);
0805
0806 if (!adev)
0807 return AE_OK;
0808
0809 if (acpi_dev_consumes_res(adev, res)) {
0810 *consumer = adev;
0811 return AE_CTRL_TERMINATE;
0812 }
0813
0814 return AE_OK;
0815 }
0816
0817
0818
0819
0820
0821
0822
0823
0824
0825 struct acpi_device *acpi_resource_consumer(struct resource *res)
0826 {
0827 struct acpi_device *consumer = NULL;
0828
0829 acpi_get_devices(NULL, acpi_res_consumer_cb, res, (void **) &consumer);
0830 return consumer;
0831 }