drivers/platform/x86/lenovo/think-lmi.c

Source file repositories/reference/linux-study-clean/drivers/platform/x86/lenovo/think-lmi.c

File Facts

System
Linux kernel
Corpus path
drivers/platform/x86/lenovo/think-lmi.c
Extension
.c
Size
53551 bytes
Lines
1860
Domain
Driver Families
Bucket
drivers/platform
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (ACPI_FAILURE(status)) {
			kfree(output.pointer);
			return -EIO;
		}
		err = tlmi_extract_error(&output);
		kfree(output.pointer);
		if (err)
			return err;
	}
	return 0;
}

/* Extract output string from WMI return value */
static int tlmi_extract_output_string(union acpi_object *obj, char **string)
{
	char *s;

	if (obj->type != ACPI_TYPE_STRING || !obj->string.pointer)
		return -EIO;

	s = kstrdup(obj->string.pointer, GFP_KERNEL);
	if (!s)
		return -ENOMEM;
	*string = s;
	return 0;
}

/* ------ Core interface functions ------------*/

/* Get password settings from BIOS */
static int tlmi_get_pwd_settings(struct tlmi_pwdcfg *pwdcfg)
{
	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
	const union acpi_object *obj;
	acpi_status status;
	int copy_size;

	if (!tlmi_priv.can_get_password_settings)
		return -EOPNOTSUPP;

	status = wmi_query_block(LENOVO_BIOS_PASSWORD_SETTINGS_GUID, 0,
				 &output);
	if (ACPI_FAILURE(status))
		return -EIO;

	obj = output.pointer;
	if (!obj)
		return -ENOMEM;
	if (obj->type != ACPI_TYPE_BUFFER || !obj->buffer.pointer) {
		kfree(obj);
		return -EIO;
	}
	/*
	 * The size of thinkpad_wmi_pcfg on ThinkStation is larger than ThinkPad.
	 * To make the driver compatible on different brands, we permit it to get
	 * the data in below case.
	 * Settings must have at minimum the core fields available
	 */
	if (obj->buffer.length < sizeof(struct tlmi_pwdcfg_core)) {
		pr_warn("Unknown pwdcfg buffer length %d\n", obj->buffer.length);
		kfree(obj);
		return -EIO;
	}

	copy_size = min_t(size_t, obj->buffer.length, sizeof(struct tlmi_pwdcfg));

	memcpy(pwdcfg, obj->buffer.pointer, copy_size);
	kfree(obj);

	if (WARN_ON(pwdcfg->core.max_length >= TLMI_PWD_BUFSIZE))
		pwdcfg->core.max_length = TLMI_PWD_BUFSIZE - 1;
	return 0;
}

static int tlmi_save_bios_settings(const char *password)
{
	return tlmi_simple_call(LENOVO_SAVE_BIOS_SETTINGS_GUID,
				password);
}

static int tlmi_opcode_setting(char *setting, const char *value)
{
	char *opcode_str;
	int ret;

	opcode_str = kasprintf(GFP_KERNEL, "%s:%s;", setting, value);
	if (!opcode_str)
		return -ENOMEM;

	ret = tlmi_simple_call(LENOVO_OPCODE_IF_GUID, opcode_str);

Annotation

Implementation Notes