Example #1
0
/**
 * acpi_device_wakeup - Enable/disable wakeup functionality for device.
 * @adev: ACPI device to enable/disable wakeup functionality for.
 * @target_state: State the system is transitioning into.
 * @enable: Whether to enable or disable the wakeup functionality.
 *
 * Enable/disable the GPE associated with @adev so that it can generate
 * wakeup signals for the device in response to external (remote) events and
 * enable/disable device wakeup power.
 *
 * Callers must ensure that @adev is a valid ACPI device node before executing
 * this function.
 */
static int acpi_device_wakeup(struct acpi_device *adev, u32 target_state,
			      bool enable)
{
	struct acpi_device_wakeup *wakeup = &adev->wakeup;

	if (enable) {
		acpi_status res;
		int error;

		error = acpi_enable_wakeup_device_power(adev, target_state);
		if (error)
			return error;

		if (adev->wakeup.flags.enabled)
			return 0;

		res = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number);
		if (ACPI_SUCCESS(res)) {
			adev->wakeup.flags.enabled = 1;
		} else {
			acpi_disable_wakeup_device_power(adev);
			return -EIO;
		}
	} else {
		if (adev->wakeup.flags.enabled) {
			acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number);
			adev->wakeup.flags.enabled = 0;
		}
		acpi_disable_wakeup_device_power(adev);
	}
	return 0;
}
Example #2
0
static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
{
	int status;
	u32 glk;
	if (!ec || (!t) || (t->wlen && !t->wdata) || (t->rlen && !t->rdata))
		return -EINVAL;
	if (t->rdata)
		memset(t->rdata, 0, t->rlen);
	mutex_lock(&ec->lock);
	if (test_bit(EC_FLAGS_BLOCKED, &ec->flags)) {
		status = -EINVAL;
		goto unlock;
	}
	if (ec->global_lock) {
		status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
		if (ACPI_FAILURE(status)) {
			status = -ENODEV;
			goto unlock;
		}
	}
	if (ec_wait_ibf0(ec)) {
		pr_err(PREFIX "input buffer is not empty, "
				"aborting transaction\n");
		status = -ETIME;
		goto end;
	}
	pr_debug(PREFIX "transaction start\n");
	/* disable GPE during transaction if storm is detected */
	if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
		/* It has to be disabled, so that it doesn't trigger. */
		acpi_disable_gpe(NULL, ec->gpe);
	}

	status = acpi_ec_transaction_unlocked(ec, t);

	/* check if we received SCI during transaction */
	ec_check_sci_sync(ec, acpi_ec_read_status(ec));
	if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
		msleep(1);
		/* It is safe to enable the GPE outside of the transaction. */
		acpi_enable_gpe(NULL, ec->gpe);
	} else if (t->irq_count > ACPI_EC_STORM_THRESHOLD) {
		pr_info(PREFIX "GPE storm detected, "
			"transactions will use polling mode\n");
		set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
	}
	pr_debug(PREFIX "transaction end\n");
end:
	if (ec->global_lock)
		acpi_release_global_lock(glk);
unlock:
	mutex_unlock(&ec->lock);
	return status;
}
static int xo15_sci_add(struct acpi_device *device)
{
	unsigned long long tmp;
	acpi_status status;
	int r;

	if (!device)
		return -EINVAL;

	strcpy(acpi_device_name(device), XO15_SCI_DEVICE_NAME);
	strcpy(acpi_device_class(device), XO15_SCI_CLASS);

	/* Get GPE bit assignment (EC events). */
	status = acpi_evaluate_integer(device->handle, "_GPE", NULL, &tmp);
	if (ACPI_FAILURE(status))
		return -EINVAL;

	xo15_sci_gpe = tmp;
	status = acpi_install_gpe_handler(NULL, xo15_sci_gpe,
					  ACPI_GPE_EDGE_TRIGGERED,
					  xo15_sci_gpe_handler, device);
	if (ACPI_FAILURE(status))
		return -ENODEV;

	dev_info(&device->dev, "Initialized, GPE = 0x%lx\n", xo15_sci_gpe);

	r = sysfs_create_file(&device->dev.kobj, &lid_wake_on_close_attr.attr);
	if (r)
		goto err_sysfs;

	/* Flush queue, and enable all SCI events */
	process_sci_queue();
	olpc_ec_mask_write(EC_SCI_SRC_ALL);

	acpi_enable_gpe(NULL, xo15_sci_gpe);

	/* Enable wake-on-EC */
	if (device->wakeup.flags.valid)
		device_init_wakeup(&device->dev, true);

	return 0;

err_sysfs:
	acpi_remove_gpe_handler(NULL, xo15_sci_gpe, xo15_sci_gpe_handler);
	cancel_work_sync(&sci_work);
	return r;
}
Example #4
0
static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
			       const u8 * wdata, unsigned wdata_len,
			       u8 * rdata, unsigned rdata_len)
{
	int status;
	u32 glk;

	if (!ec || (wdata_len && !wdata) || (rdata_len && !rdata))
		return -EINVAL;

	if (rdata)
		memset(rdata, 0, rdata_len);

	mutex_lock(&ec->lock);
	if (ec->global_lock) {
		status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
		if (ACPI_FAILURE(status)) {
			mutex_unlock(&ec->lock);
			return -ENODEV;
		}
	}

	/* Make sure GPE is enabled before doing transaction */
	acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);

	status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0);
	if (status) {
		printk(KERN_DEBUG PREFIX
		       "input buffer is not empty, aborting transaction\n");
		goto end;
	}

	status = acpi_ec_transaction_unlocked(ec, command,
					      wdata, wdata_len,
					      rdata, rdata_len);

      end:

	if (ec->global_lock)
		acpi_release_global_lock(glk);
	mutex_unlock(&ec->lock);

	return status;
}
Example #5
0
/**
 * __acpi_device_run_wake - Enable/disable runtime remote wakeup for device.
 * @adev: ACPI device to enable/disable the remote wakeup for.
 * @enable: Whether to enable or disable the wakeup functionality.
 *
 * Enable/disable the GPE associated with @adev so that it can generate
 * wakeup signals for the device in response to external (remote) events and
 * enable/disable device wakeup power.
 *
 * Callers must ensure that @adev is a valid ACPI device node before executing
 * this function.
 */
int __acpi_device_run_wake(struct acpi_device *adev, bool enable)
{
	struct acpi_device_wakeup *wakeup = &adev->wakeup;

	if (enable) {
		acpi_status res;
		int error;

		error = acpi_enable_wakeup_device_power(adev, ACPI_STATE_S0);
		if (error)
			return error;

		res = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number);
		if (ACPI_FAILURE(res)) {
			acpi_disable_wakeup_device_power(adev);
			return -EIO;
		}
	} else {
		acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number);
		acpi_disable_wakeup_device_power(adev);
	}
	return 0;
}
Example #6
0
/**
 * acpi_device_wakeup - Enable/disable wakeup functionality for device.
 * @adev: ACPI device to enable/disable wakeup functionality for.
 * @target_state: State the system is transitioning into.
 * @enable: Whether to enable or disable the wakeup functionality.
 *
 * Enable/disable the GPE associated with @adev so that it can generate
 * wakeup signals for the device in response to external (remote) events and
 * enable/disable device wakeup power.
 *
 * Callers must ensure that @adev is a valid ACPI device node before executing
 * this function.
 */
static int acpi_device_wakeup(struct acpi_device *adev, u32 target_state,
			      bool enable)
{
	struct acpi_device_wakeup *wakeup = &adev->wakeup;

	if (enable) {
		acpi_status res;
		int error;

		error = acpi_enable_wakeup_device_power(adev, target_state);
		if (error)
			return error;

		res = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number);
		if (ACPI_FAILURE(res)) {
			acpi_disable_wakeup_device_power(adev);
			return -EIO;
		}
	} else {
		acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number);
		acpi_disable_wakeup_device_power(adev);
	}
	return 0;
}
acpi_status
acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
			     struct acpi_gpe_block_info *gpe_block)
{
	struct acpi_gpe_event_info *gpe_event_info;
	struct acpi_gpe_walk_info gpe_info;
	u32 wake_gpe_count;
	u32 gpe_enabled_count;
	u32 i;
	u32 j;

	ACPI_FUNCTION_TRACE(ev_initialize_gpe_block);

	/* Ignore a null GPE block (e.g., if no GPE block 1 exists) */

	if (!gpe_block) {
		return_ACPI_STATUS(AE_OK);
	}

	/*
	 * Runtime option: Should wake GPEs be enabled at runtime?  The default
	 * is no, they should only be enabled just as the machine goes to sleep.
	 */
	if (acpi_gbl_leave_wake_gpes_disabled) {
		/*
		 * Differentiate runtime vs wake GPEs, via the _PRW control methods.
		 * Each GPE that has one or more _PRWs that reference it is by
		 * definition a wake GPE and will not be enabled while the machine
		 * is running.
		 */
		gpe_info.gpe_block = gpe_block;
		gpe_info.gpe_device = gpe_device;

		acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
					   ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK,
					   acpi_ev_match_prw_and_gpe, NULL,
					   &gpe_info, NULL);
	}

	/*
	 * Enable all GPEs that have a corresponding method and aren't
	 * capable of generating wakeups. Any other GPEs within this block
	 * must be enabled via the acpi_enable_gpe() interface.
	 */
	wake_gpe_count = 0;
	gpe_enabled_count = 0;
	if (gpe_device == acpi_gbl_fadt_gpe_device)
		gpe_device = NULL;

	for (i = 0; i < gpe_block->register_count; i++) {
		for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
			acpi_status status;
			acpi_size gpe_index;
			int gpe_number;

			/* Get the info block for this particular GPE */
			gpe_index = (acpi_size)i * ACPI_GPE_REGISTER_WIDTH + j;
			gpe_event_info = &gpe_block->event_info[gpe_index];

			if (gpe_event_info->flags & ACPI_GPE_CAN_WAKE) {
				wake_gpe_count++;
				if (acpi_gbl_leave_wake_gpes_disabled)
					continue;
			}

			if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD))
				continue;

			gpe_number = gpe_index + gpe_block->block_base_number;
			status = acpi_enable_gpe(gpe_device, gpe_number,
						ACPI_GPE_TYPE_RUNTIME);
			if (ACPI_FAILURE(status))
				ACPI_ERROR((AE_INFO,
						"Failed to enable GPE %02X\n",
						gpe_number));
			else
				gpe_enabled_count++;
		}
	}

	ACPI_DEBUG_PRINT((ACPI_DB_INIT,
			  "Found %u Wake, Enabled %u Runtime GPEs in this block\n",
			  wake_gpe_count, gpe_enabled_count));

	return_ACPI_STATUS(AE_OK);
}