summaryrefslogtreecommitdiff
path: root/drivers/platform/x86/dell-smbios.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-03-24 00:20:59 (GMT)
committerLinus Torvalds <torvalds@linux-foundation.org>2016-03-24 00:20:59 (GMT)
commit5a010c73cdb760c9bdf37b28824b6566789cc005 (patch)
treea12508a6d3b20807eaa822bedd95973df47d6307 /drivers/platform/x86/dell-smbios.c
parentb615d3d406ead1157c6b846c417b71a3b6600776 (diff)
parentfffcad87d4e7c5f6f6f6e5fc9d337bd6f197f80f (diff)
downloadlinux-5a010c73cdb760c9bdf37b28824b6566789cc005.tar.xz
Merge tag 'platform-drivers-x86-v4.6-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86
Pull x86 platform driver updates from Darren Hart: "Significant refactoring of Dell laptop drivers, modularizing the smbios code. Multiple new platforms added for ideapad, asus, dell, and alienware using existing quirks. A few fixes and cleanups. hp-wmi: - Remove GPS rfkill support via pre-2009 interface - fix unregister order in hp_wmi_rfkill_setup() once again ideapad-laptop: - Add ideapad Y700 (15) to the no_hw_rfkill DMI list fujitsu-laptop: - Support radio toggle button intel-hid: - allocate correct amount of memory for private struct platform/x86: - Make intel_scu_ipc explicitly non-modular intel_pmc_ipc: - Avoid pending IPC1 command during legacy suspend - Fix GCR register base address and length asus-nb-wmi: - add wapf=4 quirk for ASUS X75VD intel_telemetry_pltdrv: - Change verbosity control bits dell-rbtn: - Add a comment about the XPS 13 9350 dell-wmi, dell-laptop: - depends DMI dell-wmi: - support Dell Inspiron M5110 - properly process Dell Instant Launch hotkey - enable receiving WMI events on Dell Vostro V131 - Support new hotkeys on the XPS 13 9350 (Skylake) - Clean up hotkey table size check - Stop storing pointers to DMI tables dell-laptop: - move dell_smi_error() to dell-smbios - use dell_smbios_find_token() instead of find_token_location() - use dell_smbios_find_token() instead of find_token_id() - extract SMBIOS-related code to a separate module dell-smbios: - rename dell_smi_error() to dell_smbios_error() - make da_tokens static - remove find_token_{id,location}() - implement new function for finding DMI table 0xDA tokens - make the SMBIOS buffer static - return the SMBIOS buffer from dell_smbios_get_buffer() - don't return an SMBIOS buffer from dell_smbios_send_request() - don't pass an SMBIOS buffer to dell_smbios_send_request() - rename dell_send_request() to dell_smbios_send_request() - rename release_buffer() to dell_smbios_release_buffer() - rename clear_buffer() to dell_smbios_clear_buffer() - rename get_buffer() to dell_smbios_get_buffer() dell-led: - use dell_smbios_send_request() for performing SMBIOS calls - use dell_smbios_find_token() for finding mic DMI tokens toshiba_acpi: - Add a module parameter to disable hotkeys registration - Add sysfs entries for the Cooling Method feature - Add support for cooling method feature Documentation/ABI: - Update sysfs-driver-toshiba_acpi file thinkpad_acpi: - Remove ambiguous logging for "Unsupported brightness interface" alienware-wmi: - whitespace improvements - Add support for two new systems: ASM200 and ASM201. - Add support for deep sleep control. - Add initial support for alienware graphics amplifier. - Add support for new platform: X51-R3 - Clean up whitespace for ASM100 platform" * tag 'platform-drivers-x86-v4.6-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86: (47 commits) hp-wmi: Remove GPS rfkill support via pre-2009 interface hp-wmi: fix unregister order in hp_wmi_rfkill_setup() once again dell-wmi: support Dell Inspiron M5110 dell-wmi: properly process Dell Instant Launch hotkey dell-wmi: enable receiving WMI events on Dell Vostro V131 dell-smbios: rename dell_smi_error() to dell_smbios_error() dell-laptop: move dell_smi_error() to dell-smbios ideapad-laptop: Add ideapad Y700 (15) to the no_hw_rfkill DMI list fujitsu-laptop: Support radio toggle button intel-hid: allocate correct amount of memory for private struct platform/x86: Make intel_scu_ipc explicitly non-modular intel_pmc_ipc: Avoid pending IPC1 command during legacy suspend intel_pmc_ipc: Fix GCR register base address and length asus-nb-wmi: add wapf=4 quirk for ASUS X75VD intel_telemetry_pltdrv: Change verbosity control bits dell-rbtn: Add a comment about the XPS 13 9350 dell-wmi: Support new hotkeys on the XPS 13 9350 (Skylake) dell-wmi: Clean up hotkey table size check dell-wmi, dell-laptop: depends DMI dell-wmi: Stop storing pointers to DMI tables ...
Diffstat (limited to 'drivers/platform/x86/dell-smbios.c')
-rw-r--r--drivers/platform/x86/dell-smbios.c193
1 files changed, 193 insertions, 0 deletions
diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c
new file mode 100644
index 0000000..d2412ab
--- /dev/null
+++ b/drivers/platform/x86/dell-smbios.c
@@ -0,0 +1,193 @@
+/*
+ * Common functions for kernel modules using Dell SMBIOS
+ *
+ * Copyright (c) Red Hat <mjg@redhat.com>
+ * Copyright (c) 2014 Gabriele Mazzotta <gabriele.mzt@gmail.com>
+ * Copyright (c) 2014 Pali Rohár <pali.rohar@gmail.com>
+ *
+ * Based on documentation in the libsmbios package:
+ * Copyright (C) 2005-2014 Dell Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/dmi.h>
+#include <linux/err.h>
+#include <linux/gfp.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include "../../firmware/dcdbas.h"
+#include "dell-smbios.h"
+
+struct calling_interface_structure {
+ struct dmi_header header;
+ u16 cmdIOAddress;
+ u8 cmdIOCode;
+ u32 supportedCmds;
+ struct calling_interface_token tokens[];
+} __packed;
+
+static struct calling_interface_buffer *buffer;
+static DEFINE_MUTEX(buffer_mutex);
+
+static int da_command_address;
+static int da_command_code;
+static int da_num_tokens;
+static struct calling_interface_token *da_tokens;
+
+int dell_smbios_error(int value)
+{
+ switch (value) {
+ case 0: /* Completed successfully */
+ return 0;
+ case -1: /* Completed with error */
+ return -EIO;
+ case -2: /* Function not supported */
+ return -ENXIO;
+ default: /* Unknown error */
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL_GPL(dell_smbios_error);
+
+struct calling_interface_buffer *dell_smbios_get_buffer(void)
+{
+ mutex_lock(&buffer_mutex);
+ dell_smbios_clear_buffer();
+ return buffer;
+}
+EXPORT_SYMBOL_GPL(dell_smbios_get_buffer);
+
+void dell_smbios_clear_buffer(void)
+{
+ memset(buffer, 0, sizeof(struct calling_interface_buffer));
+}
+EXPORT_SYMBOL_GPL(dell_smbios_clear_buffer);
+
+void dell_smbios_release_buffer(void)
+{
+ mutex_unlock(&buffer_mutex);
+}
+EXPORT_SYMBOL_GPL(dell_smbios_release_buffer);
+
+void dell_smbios_send_request(int class, int select)
+{
+ struct smi_cmd command;
+
+ command.magic = SMI_CMD_MAGIC;
+ command.command_address = da_command_address;
+ command.command_code = da_command_code;
+ command.ebx = virt_to_phys(buffer);
+ command.ecx = 0x42534931;
+
+ buffer->class = class;
+ buffer->select = select;
+
+ dcdbas_smi_request(&command);
+}
+EXPORT_SYMBOL_GPL(dell_smbios_send_request);
+
+struct calling_interface_token *dell_smbios_find_token(int tokenid)
+{
+ int i;
+
+ for (i = 0; i < da_num_tokens; i++) {
+ if (da_tokens[i].tokenID == tokenid)
+ return &da_tokens[i];
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(dell_smbios_find_token);
+
+static void __init parse_da_table(const struct dmi_header *dm)
+{
+ /* Final token is a terminator, so we don't want to copy it */
+ int tokens = (dm->length-11)/sizeof(struct calling_interface_token)-1;
+ struct calling_interface_token *new_da_tokens;
+ struct calling_interface_structure *table =
+ container_of(dm, struct calling_interface_structure, header);
+
+ /* 4 bytes of table header, plus 7 bytes of Dell header, plus at least
+ 6 bytes of entry */
+
+ if (dm->length < 17)
+ return;
+
+ da_command_address = table->cmdIOAddress;
+ da_command_code = table->cmdIOCode;
+
+ new_da_tokens = krealloc(da_tokens, (da_num_tokens + tokens) *
+ sizeof(struct calling_interface_token),
+ GFP_KERNEL);
+
+ if (!new_da_tokens)
+ return;
+ da_tokens = new_da_tokens;
+
+ memcpy(da_tokens+da_num_tokens, table->tokens,
+ sizeof(struct calling_interface_token) * tokens);
+
+ da_num_tokens += tokens;
+}
+
+static void __init find_tokens(const struct dmi_header *dm, void *dummy)
+{
+ switch (dm->type) {
+ case 0xd4: /* Indexed IO */
+ case 0xd5: /* Protected Area Type 1 */
+ case 0xd6: /* Protected Area Type 2 */
+ break;
+ case 0xda: /* Calling interface */
+ parse_da_table(dm);
+ break;
+ }
+}
+
+static int __init dell_smbios_init(void)
+{
+ int ret;
+
+ dmi_walk(find_tokens, NULL);
+
+ if (!da_tokens) {
+ pr_info("Unable to find dmi tokens\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Allocate buffer below 4GB for SMI data--only 32-bit physical addr
+ * is passed to SMI handler.
+ */
+ buffer = (void *)__get_free_page(GFP_KERNEL | GFP_DMA32);
+ if (!buffer) {
+ ret = -ENOMEM;
+ goto fail_buffer;
+ }
+
+ return 0;
+
+fail_buffer:
+ kfree(da_tokens);
+ return ret;
+}
+
+static void __exit dell_smbios_exit(void)
+{
+ kfree(da_tokens);
+ free_page((unsigned long)buffer);
+}
+
+subsys_initcall(dell_smbios_init);
+module_exit(dell_smbios_exit);
+
+MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
+MODULE_AUTHOR("Gabriele Mazzotta <gabriele.mzt@gmail.com>");
+MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
+MODULE_DESCRIPTION("Common functions for kernel modules using Dell SMBIOS");
+MODULE_LICENSE("GPL");