void acpi_rs_dump_resource_list(struct acpi_resource *resource_list) { u32 count = 0; u32 type; ACPI_FUNCTION_ENTRY(); /* Check if debug output enabled */ if (!ACPI_IS_DEBUG_ENABLED(ACPI_LV_RESOURCES, _COMPONENT)) { return; } /* Walk list and dump all resource descriptors (END_TAG terminates) */ do { acpi_os_printf("\n[%02X] ", count); count++; /* Validate Type before dispatch */ type = resource_list->type; if (type > ACPI_RESOURCE_TYPE_MAX) { acpi_os_printf ("Invalid descriptor type (%X) in resource list\n", resource_list->type); return; } /* Sanity check the length. It must not be zero, or we loop forever */ if (!resource_list->length) { acpi_os_printf ("Invalid zero length descriptor in resource list\n"); return; } /* Dump the resource descriptor */ if (type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { acpi_rs_dump_descriptor(&resource_list->data, acpi_gbl_dump_serial_bus_dispatch [resource_list->data. common_serial_bus.type]); } else { acpi_rs_dump_descriptor(&resource_list->data, acpi_gbl_dump_resource_dispatch [type]); } /* Point to the next resource structure */ resource_list = ACPI_NEXT_RESOURCE(resource_list); /* Exit when END_TAG descriptor is reached */ } while (type != ACPI_RESOURCE_TYPE_END_TAG); }
static void acpi_virtual_gpio_request_interrupts(struct virtual_gpio_data *gd) { struct device *dev = &gd->pdev->dev; struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; struct acpi_resource *res; acpi_handle handle, ev_handle; acpi_status status; unsigned int pin; int ret; char ev_name[5]; handle = ACPI_HANDLE(dev); if (!handle) return; status = acpi_get_event_resources(handle, &buf); if (ACPI_FAILURE(status)) return; /* * If a GPIO interrupt has an ACPI event handler method, set * up an interrupt handler that calls the ACPI event handler. */ for (res = buf.pointer; res && (res->type != ACPI_RESOURCE_TYPE_END_TAG); res = ACPI_NEXT_RESOURCE(res)) { if (res->type != ACPI_RESOURCE_TYPE_GPIO || res->data.gpio.connection_type != ACPI_RESOURCE_GPIO_TYPE_INT) continue; pin = res->data.gpio.pin_table[0]; dev_info(dev, "virtual gpio pin = %d\n", pin); if (pin > 255) continue; sprintf(ev_name, "_%c%02X", res->data.gpio.triggering ? 'E' : 'L', pin); status = acpi_get_handle(handle, ev_name, &ev_handle); if (ACPI_FAILURE(status)) continue; /* Assume BIOS sets the triggering, so no flags */ ret = devm_request_irq(dev, gd->irq, virtual_gpio_irq_handler_isr, 0, VIRTUAL_GPIO_DRIVER_NAME, ev_handle); if (ret) dev_err(dev, "Failed to request IRQ %d ACPI event handler\n", gd->irq); } }
static ACPI_STATUS acpi_pci_link_route_irqs(device_t dev) { struct acpi_pci_link_softc *sc; ACPI_RESOURCE *resource, *end; ACPI_BUFFER srsbuf; ACPI_STATUS status; struct link *link; int i; ACPI_SERIAL_ASSERT(pci_link); sc = device_get_softc(dev); if (sc->pl_crs_bad) status = acpi_pci_link_srs_from_links(sc, &srsbuf); else status = acpi_pci_link_srs_from_crs(sc, &srsbuf); /* Write out new resources via _SRS. */ status = AcpiSetCurrentResources(acpi_get_handle(dev), &srsbuf); if (ACPI_FAILURE(status)) { device_printf(dev, "Unable to route IRQs: %s\n", AcpiFormatException(status)); AcpiOsFree(srsbuf.Pointer); return (status); } /* * Perform acpi_config_intr() on each IRQ resource if it was just * routed for the first time. */ link = sc->pl_links; i = 0; resource = (ACPI_RESOURCE *)srsbuf.Pointer; end = (ACPI_RESOURCE *)((char *)srsbuf.Pointer + srsbuf.Length); for (;;) { if (resource->Type == ACPI_RESOURCE_TYPE_END_TAG) break; switch (resource->Type) { case ACPI_RESOURCE_TYPE_IRQ: case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: MPASS(i < sc->pl_num_links); /* * Only configure the interrupt and update the * weights if this link has a valid IRQ and was * previously unrouted. */ if (!link->l_routed && PCI_INTERRUPT_VALID(link->l_irq)) { link->l_routed = TRUE; acpi_config_intr(dev, resource); pci_link_interrupt_weights[link->l_irq] += link->l_references; } link++; i++; break; } resource = ACPI_NEXT_RESOURCE(resource); if (resource >= end) break; } AcpiOsFree(srsbuf.Pointer); return (AE_OK); }
static ACPI_STATUS acpi_pci_link_srs_from_crs(struct acpi_pci_link_softc *sc, ACPI_BUFFER *srsbuf) { ACPI_RESOURCE *end, *res; ACPI_STATUS status; struct link *link; int i, in_dpf; /* Fetch the _CRS. */ ACPI_SERIAL_ASSERT(pci_link); srsbuf->Pointer = NULL; srsbuf->Length = ACPI_ALLOCATE_BUFFER; status = AcpiGetCurrentResources(acpi_get_handle(sc->pl_dev), srsbuf); if (ACPI_SUCCESS(status) && srsbuf->Pointer == NULL) status = AE_NO_MEMORY; if (ACPI_FAILURE(status)) { if (bootverbose) device_printf(sc->pl_dev, "Unable to fetch current resources: %s\n", AcpiFormatException(status)); return (status); } /* Fill in IRQ resources via link structures. */ link = sc->pl_links; i = 0; in_dpf = DPF_OUTSIDE; res = (ACPI_RESOURCE *)srsbuf->Pointer; end = (ACPI_RESOURCE *)((char *)srsbuf->Pointer + srsbuf->Length); for (;;) { switch (res->Type) { case ACPI_RESOURCE_TYPE_START_DEPENDENT: switch (in_dpf) { case DPF_OUTSIDE: /* We've started the first DPF. */ in_dpf = DPF_FIRST; break; case DPF_FIRST: /* We've started the second DPF. */ panic( "%s: Multiple dependent functions within a current resource", __func__); break; } break; case ACPI_RESOURCE_TYPE_END_DEPENDENT: /* We are finished with DPF parsing. */ KASSERT(in_dpf != DPF_OUTSIDE, ("%s: end dpf when not parsing a dpf", __func__)); in_dpf = DPF_OUTSIDE; break; case ACPI_RESOURCE_TYPE_IRQ: MPASS(i < sc->pl_num_links); res->Data.Irq.InterruptCount = 1; if (PCI_INTERRUPT_VALID(link->l_irq)) { KASSERT(link->l_irq < NUM_ISA_INTERRUPTS, ("%s: can't put non-ISA IRQ %d in legacy IRQ resource type", __func__, link->l_irq)); res->Data.Irq.Interrupts[0] = link->l_irq; } else res->Data.Irq.Interrupts[0] = 0; link++; i++; break; case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: MPASS(i < sc->pl_num_links); res->Data.ExtendedIrq.InterruptCount = 1; if (PCI_INTERRUPT_VALID(link->l_irq)) res->Data.ExtendedIrq.Interrupts[0] = link->l_irq; else res->Data.ExtendedIrq.Interrupts[0] = 0; link++; i++; break; } if (res->Type == ACPI_RESOURCE_TYPE_END_TAG) break; res = ACPI_NEXT_RESOURCE(res); if (res >= end) break; } return (AE_OK); }
void AcpiRsDumpResourceList ( ACPI_RESOURCE *ResourceList) { UINT32 Count = 0; UINT32 Type; ACPI_FUNCTION_ENTRY (); /* Check if debug output enabled */ if (!ACPI_IS_DEBUG_ENABLED (ACPI_LV_RESOURCES, _COMPONENT)) { return; } /* Walk list and dump all resource descriptors (END_TAG terminates) */ do { AcpiOsPrintf ("\n[%02X] ", Count); Count++; /* Validate Type before dispatch */ Type = ResourceList->Type; if (Type > ACPI_RESOURCE_TYPE_MAX) { AcpiOsPrintf ( "Invalid descriptor type (%X) in resource list\n", ResourceList->Type); return; } /* Sanity check the length. It must not be zero, or we loop forever */ if (!ResourceList->Length) { AcpiOsPrintf ( "Invalid zero length descriptor in resource list\n"); return; } /* Dump the resource descriptor */ if (Type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { AcpiRsDumpDescriptor (&ResourceList->Data, AcpiGbl_DumpSerialBusDispatch[ ResourceList->Data.CommonSerialBus.Type]); } else { AcpiRsDumpDescriptor (&ResourceList->Data, AcpiGbl_DumpResourceDispatch[Type]); } /* Point to the next resource structure */ ResourceList = ACPI_NEXT_RESOURCE (ResourceList); /* Exit when END_TAG descriptor is reached */ } while (Type != ACPI_RESOURCE_TYPE_END_TAG); }
/******************************************************************************* * * FUNCTION: acpi_rs_convert_aml_to_resources * * PARAMETERS: acpi_walk_aml_callback * resource_ptr - Pointer to the buffer that will * contain the output structures * * RETURN: Status * * DESCRIPTION: Convert an AML resource to an internal representation of the * resource that is aligned and easier to access. * ******************************************************************************/ acpi_status acpi_rs_convert_aml_to_resources(u8 * aml, u32 length, u32 offset, u8 resource_index, void **context) { struct acpi_resource **resource_ptr = ACPI_CAST_INDIRECT_PTR(struct acpi_resource, context); struct acpi_resource *resource; union aml_resource *aml_resource; struct acpi_rsconvert_info *conversion_table; acpi_status status; ACPI_FUNCTION_TRACE(rs_convert_aml_to_resources); /* * Check that the input buffer and all subsequent pointers into it * are aligned on a native word boundary. Most important on IA64 */ resource = *resource_ptr; if (ACPI_IS_MISALIGNED(resource)) { ACPI_WARNING((AE_INFO, "Misaligned resource pointer %p", resource)); } /* Get the appropriate conversion info table */ aml_resource = ACPI_CAST_PTR(union aml_resource, aml); if (acpi_ut_get_resource_type(aml) == ACPI_RESOURCE_NAME_SERIAL_BUS) { if (aml_resource->common_serial_bus.type > AML_RESOURCE_MAX_SERIALBUSTYPE) { conversion_table = NULL; } else { /* This is an I2C, SPI, or UART serial_bus descriptor */ conversion_table = acpi_gbl_convert_resource_serial_bus_dispatch [aml_resource->common_serial_bus.type]; } } else { conversion_table = acpi_gbl_get_resource_dispatch[resource_index]; } if (!conversion_table) { ACPI_ERROR((AE_INFO, "Invalid/unsupported resource descriptor: Type 0x%2.2X", resource_index)); return_ACPI_STATUS(AE_AML_INVALID_RESOURCE_TYPE); } /* Convert the AML byte stream resource to a local resource struct */ status = acpi_rs_convert_aml_to_resource(resource, aml_resource, conversion_table); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Could not convert AML resource (Type 0x%X)", *aml)); return_ACPI_STATUS(status); } ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Type %.2X, AmlLength %.2X InternalLength %.2X\n", acpi_ut_get_resource_type(aml), length, resource->length)); /* Point to the next structure in the output buffer */ *resource_ptr = ACPI_NEXT_RESOURCE(resource); return_ACPI_STATUS(AE_OK); }
acpi_status acpi_rs_convert_resources_to_aml(struct acpi_resource *resource, acpi_size aml_size_needed, u8 * output_buffer) { u8 *aml = output_buffer; u8 *end_aml = output_buffer + aml_size_needed; struct acpi_rsconvert_info *conversion_table; acpi_status status; ACPI_FUNCTION_TRACE(rs_convert_resources_to_aml); /* Walk the resource descriptor list, convert each descriptor */ while (aml < end_aml) { /* Validate the (internal) Resource Type */ if (resource->type > ACPI_RESOURCE_TYPE_MAX) { ACPI_ERROR((AE_INFO, "Invalid descriptor type (0x%X) in resource list", resource->type)); return_ACPI_STATUS(AE_BAD_DATA); } /* Sanity check the length. It must not be zero, or we loop forever */ if (!resource->length) { ACPI_ERROR((AE_INFO, "Invalid zero length descriptor in resource list\n")); return_ACPI_STATUS(AE_AML_BAD_RESOURCE_LENGTH); } /* Perform the conversion */ if (resource->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { if (resource->data.common_serial_bus.type > AML_RESOURCE_MAX_SERIALBUSTYPE) { conversion_table = NULL; } else { /* This is an I2C, SPI, or UART serial_bus descriptor */ conversion_table = acpi_gbl_convert_resource_serial_bus_dispatch [resource->data.common_serial_bus.type]; } } else { conversion_table = acpi_gbl_set_resource_dispatch[resource->type]; } if (!conversion_table) { ACPI_ERROR((AE_INFO, "Invalid/unsupported resource descriptor: Type 0x%2.2X", resource->type)); return_ACPI_STATUS(AE_AML_INVALID_RESOURCE_TYPE); } status = acpi_rs_convert_resource_to_aml(resource, ACPI_CAST_PTR(union aml_resource, aml), conversion_table); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Could not convert resource (type 0x%X) to AML", resource->type)); return_ACPI_STATUS(status); } /* Perform final sanity check on the new AML resource descriptor */ status = acpi_ut_validate_resource(NULL, ACPI_CAST_PTR(union aml_resource, aml), NULL); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* Check for end-of-list, normal exit */ if (resource->type == ACPI_RESOURCE_TYPE_END_TAG) { /* An End Tag indicates the end of the input Resource Template */ return_ACPI_STATUS(AE_OK); } /* * Extract the total length of the new descriptor and set the * Aml to point to the next (output) resource descriptor */ aml += acpi_ut_get_descriptor_length(aml); /* Point to the next input resource descriptor */ resource = ACPI_NEXT_RESOURCE(resource); } /* Completed buffer, but did not find an end_tag resource descriptor */ return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); }
ACPI_STATUS AcpiRsConvertAmlToResources ( UINT8 *Aml, UINT32 Length, UINT32 Offset, UINT8 ResourceIndex, void **Context) { ACPI_RESOURCE **ResourcePtr = ACPI_CAST_INDIRECT_PTR ( ACPI_RESOURCE, Context); ACPI_RESOURCE *Resource; AML_RESOURCE *AmlResource; ACPI_RSCONVERT_INFO *ConversionTable; ACPI_STATUS Status; ACPI_FUNCTION_TRACE (RsConvertAmlToResources); /* * Check that the input buffer and all subsequent pointers into it * are aligned on a native word boundary. Most important on IA64 */ Resource = *ResourcePtr; if (ACPI_IS_MISALIGNED (Resource)) { ACPI_WARNING ((AE_INFO, "Misaligned resource pointer %p", Resource)); } /* Get the appropriate conversion info table */ AmlResource = ACPI_CAST_PTR (AML_RESOURCE, Aml); if (AcpiUtGetResourceType (Aml) == ACPI_RESOURCE_NAME_SERIAL_BUS) { if (AmlResource->CommonSerialBus.Type > AML_RESOURCE_MAX_SERIALBUSTYPE) { ConversionTable = NULL; } else { /* This is an I2C, SPI, or UART SerialBus descriptor */ ConversionTable = AcpiGbl_ConvertResourceSerialBusDispatch[ AmlResource->CommonSerialBus.Type]; } } else { ConversionTable = AcpiGbl_GetResourceDispatch[ResourceIndex]; } if (!ConversionTable) { ACPI_ERROR ((AE_INFO, "Invalid/unsupported resource descriptor: Type 0x%2.2X", ResourceIndex)); return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE); } /* Convert the AML byte stream resource to a local resource struct */ Status = AcpiRsConvertAmlToResource ( Resource, AmlResource, ConversionTable); if (ACPI_FAILURE (Status)) { ACPI_EXCEPTION ((AE_INFO, Status, "Could not convert AML resource (Type 0x%X)", *Aml)); return_ACPI_STATUS (Status); } ACPI_DEBUG_PRINT ((ACPI_DB_RESOURCES, "Type %.2X, AmlLength %.2X InternalLength %.2X\n", AcpiUtGetResourceType (Aml), Length, Resource->Length)); /* Point to the next structure in the output buffer */ *ResourcePtr = ACPI_NEXT_RESOURCE (Resource); return_ACPI_STATUS (AE_OK); }
ACPI_STATUS AcpiRsConvertResourcesToAml ( ACPI_RESOURCE *Resource, ACPI_SIZE AmlSizeNeeded, UINT8 *OutputBuffer) { UINT8 *Aml = OutputBuffer; UINT8 *EndAml = OutputBuffer + AmlSizeNeeded; ACPI_RSCONVERT_INFO *ConversionTable; ACPI_STATUS Status; ACPI_FUNCTION_TRACE (RsConvertResourcesToAml); /* Walk the resource descriptor list, convert each descriptor */ while (Aml < EndAml) { /* Validate the (internal) Resource Type */ if (Resource->Type > ACPI_RESOURCE_TYPE_MAX) { ACPI_ERROR ((AE_INFO, "Invalid descriptor type (0x%X) in resource list", Resource->Type)); return_ACPI_STATUS (AE_BAD_DATA); } /* Sanity check the length. It must not be zero, or we loop forever */ if (!Resource->Length) { ACPI_ERROR ((AE_INFO, "Invalid zero length descriptor in resource list\n")); return_ACPI_STATUS (AE_AML_BAD_RESOURCE_LENGTH); } /* Perform the conversion */ if (Resource->Type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { if (Resource->Data.CommonSerialBus.Type > AML_RESOURCE_MAX_SERIALBUSTYPE) { ConversionTable = NULL; } else { /* This is an I2C, SPI, or UART SerialBus descriptor */ ConversionTable = AcpiGbl_ConvertResourceSerialBusDispatch[ Resource->Data.CommonSerialBus.Type]; } } else { ConversionTable = AcpiGbl_SetResourceDispatch[Resource->Type]; } if (!ConversionTable) { ACPI_ERROR ((AE_INFO, "Invalid/unsupported resource descriptor: Type 0x%2.2X", Resource->Type)); return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE); } Status = AcpiRsConvertResourceToAml (Resource, ACPI_CAST_PTR (AML_RESOURCE, Aml), ConversionTable); if (ACPI_FAILURE (Status)) { ACPI_EXCEPTION ((AE_INFO, Status, "Could not convert resource (type 0x%X) to AML", Resource->Type)); return_ACPI_STATUS (Status); } /* Perform final sanity check on the new AML resource descriptor */ Status = AcpiUtValidateResource (NULL, ACPI_CAST_PTR (AML_RESOURCE, Aml), NULL); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } /* Check for end-of-list, normal exit */ if (Resource->Type == ACPI_RESOURCE_TYPE_END_TAG) { /* An End Tag indicates the end of the input Resource Template */ return_ACPI_STATUS (AE_OK); } /* * Extract the total length of the new descriptor and set the * Aml to point to the next (output) resource descriptor */ Aml += AcpiUtGetDescriptorLength (Aml); /* Point to the next input resource descriptor */ Resource = ACPI_NEXT_RESOURCE (Resource); } /* Completed buffer, but did not find an EndTag resource descriptor */ return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG); }
acpi_status acpi_walk_resources ( acpi_handle device_handle, char *path, ACPI_WALK_RESOURCE_CALLBACK user_function, void *context) { acpi_status status; struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; struct acpi_resource *resource; struct acpi_resource *buffer_end; ACPI_FUNCTION_TRACE ("acpi_walk_resources"); if (!device_handle || (ACPI_STRNCMP (path, METHOD_NAME__CRS, sizeof (METHOD_NAME__CRS)) && ACPI_STRNCMP (path, METHOD_NAME__PRS, sizeof (METHOD_NAME__PRS)))) { return_ACPI_STATUS (AE_BAD_PARAMETER); } status = acpi_rs_get_method_data (device_handle, path, &buffer); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* Setup pointers */ resource = (struct acpi_resource *) buffer.pointer; buffer_end = ACPI_CAST_PTR (struct acpi_resource, ((u8 *) buffer.pointer + buffer.length)); /* Walk the resource list */ for (;;) { if (!resource || resource->id == ACPI_RSTYPE_END_TAG) { break; } status = user_function (resource, context); switch (status) { case AE_OK: case AE_CTRL_DEPTH: /* Just keep going */ status = AE_OK; break; case AE_CTRL_TERMINATE: /* Exit now, with OK stats */ status = AE_OK; goto cleanup; default: /* All others are valid exceptions */ goto cleanup; } /* Get the next resource descriptor */ resource = ACPI_NEXT_RESOURCE (resource); /* Check for end-of-buffer */ if (resource >= buffer_end) { goto cleanup; } } cleanup: acpi_os_free (buffer.pointer); return_ACPI_STATUS (status); }
ACPI_STATUS AcpiWalkResourceBuffer ( ACPI_BUFFER *Buffer, ACPI_WALK_RESOURCE_CALLBACK UserFunction, void *Context) { ACPI_STATUS Status = AE_OK; ACPI_RESOURCE *Resource; ACPI_RESOURCE *ResourceEnd; ACPI_FUNCTION_TRACE (AcpiWalkResourceBuffer); /* Parameter validation */ if (!Buffer || !Buffer->Pointer || !UserFunction) { return_ACPI_STATUS (AE_BAD_PARAMETER); } /* Buffer contains the resource list and length */ Resource = ACPI_CAST_PTR (ACPI_RESOURCE, Buffer->Pointer); ResourceEnd = ACPI_ADD_PTR (ACPI_RESOURCE, Buffer->Pointer, Buffer->Length); /* Walk the resource list until the EndTag is found (or buffer end) */ while (Resource < ResourceEnd) { /* Sanity check the resource type */ if (Resource->Type > ACPI_RESOURCE_TYPE_MAX) { Status = AE_AML_INVALID_RESOURCE_TYPE; break; } /* Sanity check the length. It must not be zero, or we loop forever */ if (!Resource->Length) { return_ACPI_STATUS (AE_AML_BAD_RESOURCE_LENGTH); } /* Invoke the user function, abort on any error returned */ Status = UserFunction (Resource, Context); if (ACPI_FAILURE (Status)) { if (Status == AE_CTRL_TERMINATE) { /* This is an OK termination by the user function */ Status = AE_OK; } break; } /* EndTag indicates end-of-list */ if (Resource->Type == ACPI_RESOURCE_TYPE_END_TAG) { break; } /* Get the next resource descriptor */ Resource = ACPI_NEXT_RESOURCE (Resource); } return_ACPI_STATUS (Status); }
acpi_status acpi_walk_resource_buffer(struct acpi_buffer * buffer, acpi_walk_resource_callback user_function, void *context) { acpi_status status = AE_OK; struct acpi_resource *resource; struct acpi_resource *resource_end; ACPI_FUNCTION_TRACE(acpi_walk_resource_buffer); /* Parameter validation */ if (!buffer || !buffer->pointer || !user_function) { return_ACPI_STATUS(AE_BAD_PARAMETER); } /* Buffer contains the resource list and length */ resource = ACPI_CAST_PTR(struct acpi_resource, buffer->pointer); resource_end = ACPI_ADD_PTR(struct acpi_resource, buffer->pointer, buffer->length); /* Walk the resource list until the end_tag is found (or buffer end) */ while (resource < resource_end) { /* Sanity check the resource type */ if (resource->type > ACPI_RESOURCE_TYPE_MAX) { status = AE_AML_INVALID_RESOURCE_TYPE; break; } /* Sanity check the length. It must not be zero, or we loop forever */ if (!resource->length) { return_ACPI_STATUS(AE_AML_BAD_RESOURCE_LENGTH); } /* Invoke the user function, abort on any error returned */ status = user_function(resource, context); if (ACPI_FAILURE(status)) { if (status == AE_CTRL_TERMINATE) { /* This is an OK termination by the user function */ status = AE_OK; } break; } /* end_tag indicates end-of-list */ if (resource->type == ACPI_RESOURCE_TYPE_END_TAG) { break; } /* Get the next resource descriptor */ resource = ACPI_NEXT_RESOURCE(resource); } return_ACPI_STATUS(status); }
/** * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events * @chip: gpio chip * * ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are * handled by ACPI event methods which need to be called from the GPIO * chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which * gpio pins have acpi event methods and assigns interrupt handlers that calls * the acpi event methods for those pins. */ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; struct acpi_resource *res; acpi_handle handle, evt_handle; struct list_head *evt_pins = NULL; acpi_status status; unsigned int pin; int irq, ret; char ev_name[5]; if (!chip->dev || !chip->to_irq) return; handle = ACPI_HANDLE(chip->dev); if (!handle) return; status = acpi_get_event_resources(handle, &buf); if (ACPI_FAILURE(status)) return; status = acpi_get_handle(handle, "_EVT", &evt_handle); if (ACPI_SUCCESS(status)) { evt_pins = kzalloc(sizeof(*evt_pins), GFP_KERNEL); if (evt_pins) { INIT_LIST_HEAD(evt_pins); status = acpi_attach_data(handle, acpi_gpio_evt_dh, evt_pins); if (ACPI_FAILURE(status)) { kfree(evt_pins); evt_pins = NULL; } } } /* * If a GPIO interrupt has an ACPI event handler method, or _EVT is * present, set up an interrupt handler that calls the ACPI event * handler. */ for (res = buf.pointer; res && (res->type != ACPI_RESOURCE_TYPE_END_TAG); res = ACPI_NEXT_RESOURCE(res)) { irq_handler_t handler = NULL; void *data; if (res->type != ACPI_RESOURCE_TYPE_GPIO || res->data.gpio.connection_type != ACPI_RESOURCE_GPIO_TYPE_INT) continue; pin = res->data.gpio.pin_table[0]; if (pin > chip->ngpio) continue; irq = chip->to_irq(chip, pin); if (irq < 0) continue; if (pin <= 255) { acpi_handle ev_handle; sprintf(ev_name, "_%c%02X", res->data.gpio.triggering ? 'E' : 'L', pin); status = acpi_get_handle(handle, ev_name, &ev_handle); if (ACPI_SUCCESS(status)) { handler = acpi_gpio_irq_handler; data = ev_handle; } } if (!handler && evt_pins) { struct acpi_gpio_evt_pin *evt_pin; evt_pin = kzalloc(sizeof(*evt_pin), GFP_KERNEL); if (!evt_pin) continue; list_add_tail(&evt_pin->node, evt_pins); evt_pin->evt_handle = evt_handle; evt_pin->pin = pin; evt_pin->irq = irq; handler = acpi_gpio_irq_handler_evt; data = evt_pin; } if (!handler) continue; /* Assume BIOS sets the triggering, so no flags */ ret = devm_request_threaded_irq(chip->dev, irq, NULL, handler, 0, "GPIO-signaled-ACPI-event", data); if (ret) dev_err(chip->dev, "Failed to request IRQ %d ACPI event handler\n", irq); } }
/* * Retrieves a list of possible interrupt settings for the interrupt link * device. * * Stores polarity and sensitivity in the structure pointed to by intr_flagp. * Updates value pointed to by irqlistp with the address of a table it * allocates. where interrupt numbers are stored. Stores the number of entries * in this table in the value pointed to by num_entriesp; * * Each element in this table is of type int32_t. The table should be later * freed by caller via acpi_free_irq_list(). * * Returns ACPI_PSM_SUCCESS on success and ACPI_PSM_FAILURE upon failure */ int acpi_get_possible_irq_resources(acpi_psm_lnk_t *acpipsmlnkp, acpi_irqlist_t **irqlistp) { ACPI_HANDLE lnkobj; ACPI_BUFFER rsb; ACPI_RESOURCE *resp; int status; int i, el, po, irqlist_len; uint32_t *irqlist; void *tmplist; iflag_t intr_flags; ASSERT(acpipsmlnkp != NULL); lnkobj = acpipsmlnkp->lnkobj; rsb.Pointer = NULL; rsb.Length = ACPI_ALLOCATE_BUFFER; status = AcpiGetPossibleResources(lnkobj, &rsb); if (status != AE_OK) { cmn_err(CE_WARN, "!psm: get_irq: _PRS failed"); return (ACPI_PSM_FAILURE); } /* * Scan the resources looking for an interrupt resource */ *irqlistp = 0; for (resp = rsb.Pointer; resp->Type != ACPI_RESOURCE_TYPE_END_TAG; resp = ACPI_NEXT_RESOURCE(resp)) { switch (resp->Type) { case ACPI_RESOURCE_TYPE_IRQ: irqlist_len = resp->Data.Irq.InterruptCount; tmplist = resp->Data.Irq.Interrupts; el = resp->Data.Irq.Triggering; po = resp->Data.Irq.Polarity; break; case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: irqlist_len = resp->Data.ExtendedIrq.InterruptCount; tmplist = resp->Data.ExtendedIrq.Interrupts; el = resp->Data.ExtendedIrq.Triggering; po = resp->Data.ExtendedIrq.Polarity; break; default: continue; } if (resp->Type != ACPI_RESOURCE_TYPE_IRQ && resp->Type != ACPI_RESOURCE_TYPE_EXTENDED_IRQ) { cmn_err(CE_WARN, "!psm: get_irq: no IRQ resource"); return (ACPI_PSM_FAILURE); } /* NEEDSWORK: move this into add_irqlist_entry someday */ irqlist = kmem_zalloc(irqlist_len * sizeof (*irqlist), KM_SLEEP); for (i = 0; i < irqlist_len; i++) if (resp->Type == ACPI_RESOURCE_TYPE_IRQ) irqlist[i] = ((uint8_t *)tmplist)[i]; else irqlist[i] = ((uint32_t *)tmplist)[i]; intr_flags.intr_el = psm_acpi_edgelevel(el); intr_flags.intr_po = psm_acpi_po(po); acpi_add_irqlist_entry(irqlistp, irqlist, irqlist_len, &intr_flags); } AcpiOsFree(rsb.Pointer); return (irqlistp == NULL ? ACPI_PSM_FAILURE : ACPI_PSM_SUCCESS); }
/* * Retrieves the current irq setting for the interrrupt link device. * * Stores polarity and sensitivity in the structure pointed to by * intr_flagp, and irqno in the value pointed to by pci_irqp. * * Returns ACPI_PSM_SUCCESS on success, ACPI_PSM_FAILURE upon failure. */ int acpi_get_current_irq_resource(acpi_psm_lnk_t *acpipsmlnkp, int *pci_irqp, iflag_t *intr_flagp) { ACPI_HANDLE lnkobj; ACPI_BUFFER rb; ACPI_RESOURCE *rp; int irq; int status = ACPI_PSM_FAILURE; ASSERT(acpipsmlnkp != NULL); lnkobj = acpipsmlnkp->lnkobj; if (!(acpipsmlnkp->device_status & STA_PRESENT) || !(acpipsmlnkp->device_status & STA_ENABLE)) { PSM_VERBOSE_IRQ((CE_WARN, "!psm: crs device either not " "present or disabled, status 0x%x", acpipsmlnkp->device_status)); return (ACPI_PSM_FAILURE); } rb.Pointer = NULL; rb.Length = ACPI_ALLOCATE_BUFFER; if (AcpiGetCurrentResources(lnkobj, &rb) != AE_OK) { PSM_VERBOSE_IRQ((CE_WARN, "!psm: no crs object found or" " evaluation failed")); return (ACPI_PSM_FAILURE); } irq = -1; for (rp = rb.Pointer; rp->Type != ACPI_RESOURCE_TYPE_END_TAG; rp = ACPI_NEXT_RESOURCE(rp)) { if (rp->Type == ACPI_RESOURCE_TYPE_IRQ) { if (irq > 0) { PSM_VERBOSE_IRQ((CE_WARN, "!psm: multiple IRQ" " from _CRS ")); status = ACPI_PSM_FAILURE; break; } if (rp->Data.Irq.InterruptCount != 1) { PSM_VERBOSE_IRQ((CE_WARN, "!psm: <>1 interrupt" " from _CRS ")); status = ACPI_PSM_FAILURE; break; } intr_flagp->intr_el = psm_acpi_edgelevel( rp->Data.Irq.Triggering); intr_flagp->intr_po = psm_acpi_po( rp->Data.Irq.Polarity); irq = rp->Data.Irq.Interrupts[0]; status = ACPI_PSM_SUCCESS; } else if (rp->Type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) { if (irq > 0) { PSM_VERBOSE_IRQ((CE_WARN, "!psm: multiple IRQ" " from _CRS ")); status = ACPI_PSM_FAILURE; break; } if (rp->Data.ExtendedIrq.InterruptCount != 1) { PSM_VERBOSE_IRQ((CE_WARN, "!psm: <>1 interrupt" " from _CRS ")); status = ACPI_PSM_FAILURE; break; } intr_flagp->intr_el = psm_acpi_edgelevel( rp->Data.ExtendedIrq.Triggering); intr_flagp->intr_po = psm_acpi_po( rp->Data.ExtendedIrq.Polarity); irq = rp->Data.ExtendedIrq.Interrupts[0]; status = ACPI_PSM_SUCCESS; } } AcpiOsFree(rb.Pointer); if (status == ACPI_PSM_SUCCESS) { *pci_irqp = irq; } return (status); }
/* * Sets the irq resource of the lnk object to the requested irq value. * * Returns ACPI_PSM_SUCCESS on success, ACPI_PSM_FAILURE upon failure. */ int acpi_set_irq_resource(acpi_psm_lnk_t *acpipsmlnkp, int irq) { ACPI_BUFFER rsb; ACPI_RESOURCE *resp; ACPI_RESOURCE *srsp; ACPI_HANDLE lnkobj; int srs_len, status; ASSERT(acpipsmlnkp != NULL); lnkobj = acpipsmlnkp->lnkobj; /* * Fetch the possible resources for the link */ rsb.Pointer = NULL; rsb.Length = ACPI_ALLOCATE_BUFFER; status = AcpiGetPossibleResources(lnkobj, &rsb); if (status != AE_OK) { cmn_err(CE_WARN, "!psm: set_irq: _PRS failed"); return (ACPI_PSM_FAILURE); } /* * Find an IRQ resource descriptor to use as template */ srsp = NULL; for (resp = rsb.Pointer; resp->Type != ACPI_RESOURCE_TYPE_END_TAG; resp = ACPI_NEXT_RESOURCE(resp)) { if ((resp->Type == ACPI_RESOURCE_TYPE_IRQ) || (resp->Type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ)) { ACPI_RESOURCE *endtag; /* * Allocate enough room for this resource entry * and one end tag following it */ srs_len = resp->Length + sizeof (*endtag); srsp = kmem_zalloc(srs_len, KM_SLEEP); bcopy(resp, srsp, resp->Length); endtag = ACPI_NEXT_RESOURCE(srsp); endtag->Type = ACPI_RESOURCE_TYPE_END_TAG; endtag->Length = 0; break; /* drop out of the loop */ } } /* * We're done with the PRS values, toss 'em lest we forget */ AcpiOsFree(rsb.Pointer); if (srsp == NULL) return (ACPI_PSM_FAILURE); /* * The Interrupts[] array is always at least one entry * long; see the definition of ACPI_RESOURCE. */ switch (srsp->Type) { case ACPI_RESOURCE_TYPE_IRQ: srsp->Data.Irq.InterruptCount = 1; srsp->Data.Irq.Interrupts[0] = irq; break; case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: srsp->Data.ExtendedIrq.InterruptCount = 1; srsp->Data.ExtendedIrq.Interrupts[0] = irq; break; } rsb.Pointer = srsp; rsb.Length = srs_len; status = AcpiSetCurrentResources(lnkobj, &rsb); kmem_free(srsp, srs_len); if (status != AE_OK) { cmn_err(CE_WARN, "!psm: set_irq: _SRS failed"); return (ACPI_PSM_FAILURE); } if (acpica_eval_int(lnkobj, "_STA", &status) == AE_OK) { acpipsmlnkp->device_status = (uchar_t)status; return (ACPI_PSM_SUCCESS); } else return (ACPI_PSM_FAILURE); }