Exemple #1
0
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);
}
Exemple #5
0
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);
}
Exemple #6
0
/*******************************************************************************
 *
 * 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);
}
Exemple #7
0
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);
}
Exemple #8
0
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);
}
Exemple #9
0
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);
}
Exemple #10
0
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);
}
Exemple #11
0
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);
}
Exemple #12
0
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);
}
Exemple #13
0
/**
 * 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);
}