Skip to content
ec.c 27.2 KiB
Newer Older
	ec_ecdt = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
Linus Torvalds's avatar
Linus Torvalds committed
	if (!ec_ecdt) {
		ret = -ENOMEM;
		goto error;
	}
	memset(ec_ecdt, 0, sizeof(struct acpi_ec));
Linus Torvalds's avatar
Linus Torvalds committed

	status = acpi_get_devices(ACPI_EC_HID,
				  acpi_fake_ecdt_callback, NULL, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
	if (ACPI_FAILURE(status)) {
		kfree(ec_ecdt);
		ec_ecdt = NULL;
		ret = -ENODEV;
		ACPI_EXCEPTION((AE_INFO, status, "Can't make an fake ECDT"));
Linus Torvalds's avatar
Linus Torvalds committed
		goto error;
	}
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
	return ret;
}

static int __init acpi_ec_get_real_ecdt(void)
	acpi_status status;
	struct acpi_table_ecdt *ecdt_ptr;
	status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING,
					 (struct acpi_table_header **)
					 &ecdt_ptr);
	if (ACPI_FAILURE(status))
		return -ENODEV;

	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT"));

	/*
	 * Generate a temporary ec context to use until the namespace is scanned
	 */
	ec_ecdt = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
	if (!ec_ecdt)
		return -ENOMEM;
	memset(ec_ecdt, 0, sizeof(struct acpi_ec));
	init_MUTEX(&ec_ecdt->sem);
	if (acpi_ec_mode == EC_INTR) {
		init_waitqueue_head(&ec_ecdt->wait);
	ec_ecdt->command_addr = ecdt_ptr->ec_control;
	ec_ecdt->status_addr = ecdt_ptr->ec_control;
	ec_ecdt->data_addr = ecdt_ptr->ec_data;
	ec_ecdt->gpe_bit = ecdt_ptr->gpe_bit;
Linus Torvalds's avatar
Linus Torvalds committed
	/* use the GL just to be safe */
	ec_ecdt->global_lock = TRUE;
	ec_ecdt->uid = ecdt_ptr->uid;
Linus Torvalds's avatar
Linus Torvalds committed

	status =
	    acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->handle);
Linus Torvalds's avatar
Linus Torvalds committed
	if (ACPI_FAILURE(status)) {
		goto error;
	}

	return 0;
  error:
	ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT"));
Linus Torvalds's avatar
Linus Torvalds committed
	kfree(ec_ecdt);
	ec_ecdt = NULL;

	return -ENODEV;
}

static int __initdata acpi_fake_ecdt_enabled;
int __init acpi_ec_ecdt_probe(void)
Linus Torvalds's avatar
Linus Torvalds committed
{
	acpi_status status;
	int ret;
Linus Torvalds's avatar
Linus Torvalds committed

	ret = acpi_ec_get_real_ecdt();
	/* Try to make a fake ECDT */
	if (ret && acpi_fake_ecdt_enabled) {
		ret = acpi_ec_fake_ecdt();
	}

	if (ret)
		return 0;

	/*
	 * Install GPE handler
	 */
	status = acpi_install_gpe_handler(NULL, ec_ecdt->gpe_bit,
					  ACPI_GPE_EDGE_TRIGGERED,
					  &acpi_ec_gpe_handler, ec_ecdt);
Linus Torvalds's avatar
Linus Torvalds committed
	if (ACPI_FAILURE(status)) {
		goto error;
	}
	acpi_set_gpe_type(NULL, ec_ecdt->gpe_bit, ACPI_GPE_TYPE_RUNTIME);
	acpi_enable_gpe(NULL, ec_ecdt->gpe_bit, ACPI_NOT_ISR);

	status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT,
						    ACPI_ADR_SPACE_EC,
						    &acpi_ec_space_handler,
						    &acpi_ec_space_setup,
						    ec_ecdt);
Linus Torvalds's avatar
Linus Torvalds committed
	if (ACPI_FAILURE(status)) {
		acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit,
					&acpi_ec_gpe_handler);
Linus Torvalds's avatar
Linus Torvalds committed
		goto error;
	}

	return 0;

      error:
	ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT"));
Linus Torvalds's avatar
Linus Torvalds committed
	kfree(ec_ecdt);
	ec_ecdt = NULL;

	return -ENODEV;
}

static int __init acpi_ec_init(void)
Linus Torvalds's avatar
Linus Torvalds committed
{
	int result = 0;
Linus Torvalds's avatar
Linus Torvalds committed


	if (acpi_disabled)
Linus Torvalds's avatar
Linus Torvalds committed

	acpi_ec_dir = proc_mkdir(ACPI_EC_CLASS, acpi_root_dir);
	if (!acpi_ec_dir)
Linus Torvalds's avatar
Linus Torvalds committed

	/* Now register the driver for the EC */
	result = acpi_bus_register_driver(&acpi_ec_driver);
	if (result < 0) {
		remove_proc_entry(ACPI_EC_CLASS, acpi_root_dir);
Linus Torvalds's avatar
Linus Torvalds committed
}

subsys_initcall(acpi_ec_init);

/* EC driver currently not unloadable */
#if 0
static void __exit acpi_ec_exit(void)
Linus Torvalds's avatar
Linus Torvalds committed
{

	acpi_bus_unregister_driver(&acpi_ec_driver);

	remove_proc_entry(ACPI_EC_CLASS, acpi_root_dir);

Linus Torvalds's avatar
Linus Torvalds committed
}
#endif				/* 0 */
Linus Torvalds's avatar
Linus Torvalds committed

static int __init acpi_fake_ecdt_setup(char *str)
{
	acpi_fake_ecdt_enabled = 1;
Linus Torvalds's avatar
Linus Torvalds committed
}
Linus Torvalds's avatar
Linus Torvalds committed
__setup("acpi_fake_ecdt", acpi_fake_ecdt_setup);
static int __init acpi_ec_set_intr_mode(char *str)
	if (!get_option(&str, &intr))
	acpi_ec_driver.ops.add = acpi_ec_add;
	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "EC %s mode.\n", intr ? "interrupt" : "polling"));

__setup("ec_intr=", acpi_ec_set_intr_mode);