drivers/platform/x86/dell/dell-smbios-wmi.c

Source file repositories/reference/linux-study-clean/drivers/platform/x86/dell/dell-smbios-wmi.c

File Facts

System
Linux kernel
Corpus path
drivers/platform/x86/dell/dell-smbios-wmi.c
Extension
.c
Size
8449 bytes
Lines
344
Domain
Driver Families
Bucket
drivers/platform
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern 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

static const struct file_operations dell_smbios_wmi_fops = {
	.owner		= THIS_MODULE,
	.open		= dell_smbios_wmi_open,
	.read		= dell_smbios_wmi_read,
	.unlocked_ioctl	= dell_smbios_wmi_ioctl,
	.compat_ioctl	= compat_ptr_ioctl,
};

static void dell_smbios_wmi_unregister_chardev(void *data)
{
	struct miscdevice *char_dev = data;

	misc_deregister(char_dev);
}

static int dell_smbios_wmi_register_chardev(struct wmi_smbios_priv *priv)
{
	int ret;

	priv->char_dev.minor = MISC_DYNAMIC_MINOR;
	priv->char_dev.name = "wmi/dell-smbios";
	priv->char_dev.fops = &dell_smbios_wmi_fops;
	priv->char_dev.mode = 0444;

	ret = misc_register(&priv->char_dev);
	if (ret < 0)
		return ret;

	return devm_add_action_or_reset(&priv->wdev->dev, dell_smbios_wmi_unregister_chardev,
					&priv->char_dev);
}

static int dell_smbios_wmi_probe(struct wmi_device *wdev, const void *context)
{
	struct wmi_smbios_priv *priv;
	u32 buffer_size, hotfix;
	int count;
	int ret;

	ret = dell_wmi_get_descriptor_valid();
	if (ret)
		return ret;

	priv = devm_kzalloc(&wdev->dev, sizeof(struct wmi_smbios_priv),
			    GFP_KERNEL);
	if (!priv)
		return -ENOMEM;

	priv->wdev = wdev;
	dev_set_drvdata(&wdev->dev, priv);

	/* WMI buffer size will be either 4k or 32k depending on machine */
	if (!dell_wmi_get_size(&buffer_size))
		return -EPROBE_DEFER;

	priv->req_buf_size = buffer_size;

	/* some SMBIOS calls fail unless BIOS contains hotfix */
	if (!dell_wmi_get_hotfix(&hotfix))
		return -EPROBE_DEFER;

	if (!hotfix)
		dev_warn(&wdev->dev,
			"WMI SMBIOS userspace interface not supported(%u), try upgrading to a newer BIOS\n",
			hotfix);

	/* add in the length object we will use internally with ioctl */
	priv->req_buf_size += sizeof(u64);

	count = get_order(priv->req_buf_size);
	priv->buf = (void *)devm_get_free_pages(&wdev->dev, GFP_KERNEL, count);
	if (!priv->buf)
		return -ENOMEM;

	ret = dell_smbios_wmi_register_chardev(priv);
	if (ret)
		return ret;

	ret = dell_smbios_register_device(&wdev->dev, 1, &dell_smbios_wmi_call);
	if (ret)
		return ret;

	mutex_lock(&list_mutex);
	list_add_tail(&priv->list, &wmi_list);
	mutex_unlock(&list_mutex);

	return 0;
}

static void dell_smbios_wmi_remove(struct wmi_device *wdev)

Annotation

Implementation Notes