dell-laptop: extract SMBIOS-related code to a separate module
authorMichał Kępień <kernel@kempniu.pl>
Fri, 22 Jan 2016 14:27:13 +0000 (15:27 +0100)
committerDarren Hart <dvhart@linux.intel.com>
Wed, 23 Mar 2016 17:05:38 +0000 (10:05 -0700)
Extract SMBIOS-related code from dell-laptop to a new kernel module,
dell-smbios.  The static specifier is removed from exported symbols,
otherwise code is just moved around.

Signed-off-by: Michał Kępień <kernel@kempniu.pl>
Reviewed-by: Pali Rohár <pali.rohar@gmail.com>
[dvhart: Include linux/io.h in dell-smbios.c as caught by lkp]
Signed-off-by: Darren Hart <dvhart@linux.intel.com>
drivers/platform/x86/Kconfig
drivers/platform/x86/Makefile
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/dell-smbios.c [new file with mode: 0644]
drivers/platform/x86/dell-smbios.h [new file with mode: 0644]

index 69f93a576e4583a945746f92e14d06f0ad3a70ea..3e4d9c3e83fdb6f7bbe20fa70636debaeb7e4c55 100644 (file)
@@ -91,10 +91,20 @@ config ASUS_LAPTOP
 
          If you have an ACPI-compatible ASUS laptop, say Y or M here.
 
+config DELL_SMBIOS
+       tristate "Dell SMBIOS Support"
+       depends on DCDBAS
+       default n
+       ---help---
+       This module provides common functions for kernel modules using
+       Dell SMBIOS.
+
+       If you have a Dell laptop, say Y or M here.
+
 config DELL_LAPTOP
        tristate "Dell Laptop Extras"
        depends on X86
-       depends on DCDBAS
+       depends on DELL_SMBIOS
        depends on BACKLIGHT_CLASS_DEVICE
        depends on ACPI_VIDEO || ACPI_VIDEO = n
        depends on RFKILL || RFKILL = n
index 40574e7390f3d69702e76ae62517b70a669c91ef..448443c3baba9652e4c0edaa2d8295b8a1c3e0f1 100644 (file)
@@ -11,6 +11,7 @@ obj-$(CONFIG_EEEPC_WMI)               += eeepc-wmi.o
 obj-$(CONFIG_MSI_LAPTOP)       += msi-laptop.o
 obj-$(CONFIG_ACPI_CMPC)                += classmate-laptop.o
 obj-$(CONFIG_COMPAL_LAPTOP)    += compal-laptop.o
+obj-$(CONFIG_DELL_SMBIOS)      += dell-smbios.o
 obj-$(CONFIG_DELL_LAPTOP)      += dell-laptop.o
 obj-$(CONFIG_DELL_WMI)         += dell-wmi.o
 obj-$(CONFIG_DELL_WMI_AIO)     += dell-wmi-aio.o
index aaeeae81e3a9798de43aaa80fb4aba2f247ad3ab..d45d356b6e693274d075bd52599117d6f3b0152e 100644 (file)
 #include <linux/acpi.h>
 #include <linux/mm.h>
 #include <linux/i8042.h>
-#include <linux/slab.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <acpi/video.h>
-#include "../../firmware/dcdbas.h"
 #include "dell-rbtn.h"
+#include "dell-smbios.h"
 
 #define BRIGHTNESS_TOKEN 0x7d
 #define KBD_LED_OFF_TOKEN 0x01E1
 #define KBD_LED_AUTO_75_TOKEN 0x02EC
 #define KBD_LED_AUTO_100_TOKEN 0x02F6
 
-/* This structure will be modified by the firmware when we enter
- * system management mode, hence the volatiles */
-
-struct calling_interface_buffer {
-       u16 class;
-       u16 select;
-       volatile u32 input[4];
-       volatile u32 output[4];
-} __packed;
-
-struct calling_interface_token {
-       u16 tokenID;
-       u16 location;
-       union {
-               u16 value;
-               u16 stringlength;
-       };
-};
-
-struct calling_interface_structure {
-       struct dmi_header header;
-       u16 cmdIOAddress;
-       u8 cmdIOCode;
-       u32 supportedCmds;
-       struct calling_interface_token tokens[];
-} __packed;
-
 struct quirk_entry {
        u8 touchpad_led;
 
@@ -103,11 +75,6 @@ static struct quirk_entry quirk_dell_xps13_9333 = {
        .kbd_timeouts = { 0, 5, 15, 60, 5 * 60, 15 * 60, -1 },
 };
 
-static int da_command_address;
-static int da_command_code;
-static int da_num_tokens;
-static struct calling_interface_token *da_tokens;
-
 static struct platform_driver platform_driver = {
        .driver = {
                .name = "dell-laptop",
@@ -306,112 +273,6 @@ static const struct dmi_system_id dell_quirks[] __initconst = {
        { }
 };
 
-static struct calling_interface_buffer *buffer;
-static DEFINE_MUTEX(buffer_mutex);
-
-static void clear_buffer(void)
-{
-       memset(buffer, 0, sizeof(struct calling_interface_buffer));
-}
-
-static void get_buffer(void)
-{
-       mutex_lock(&buffer_mutex);
-       clear_buffer();
-}
-
-static void release_buffer(void)
-{
-       mutex_unlock(&buffer_mutex);
-}
-
-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 find_token_id(int tokenid)
-{
-       int i;
-
-       for (i = 0; i < da_num_tokens; i++) {
-               if (da_tokens[i].tokenID == tokenid)
-                       return i;
-       }
-
-       return -1;
-}
-
-static int find_token_location(int tokenid)
-{
-       int id;
-
-       id = find_token_id(tokenid);
-       if (id == -1)
-               return -1;
-
-       return da_tokens[id].location;
-}
-
-static struct calling_interface_buffer *
-dell_send_request(struct calling_interface_buffer *buffer, 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);
-
-       return buffer;
-}
-
 static inline int dell_smi_error(int value)
 {
        switch (value) {
@@ -2122,13 +1983,6 @@ static int __init dell_init(void)
        /* find if this machine support other functions */
        dmi_check_system(dell_quirks);
 
-       dmi_walk(find_tokens, NULL);
-
-       if (!da_tokens)  {
-               pr_info("Unable to find dmi tokens\n");
-               return -ENODEV;
-       }
-
        ret = platform_driver_register(&platform_driver);
        if (ret)
                goto fail_platform_driver;
@@ -2141,16 +1995,6 @@ static int __init dell_init(void)
        if (ret)
                goto fail_platform_device2;
 
-       /*
-        * 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;
-       }
-
        ret = dell_setup_rfkill();
 
        if (ret) {
@@ -2208,15 +2052,12 @@ static int __init dell_init(void)
 fail_backlight:
        dell_cleanup_rfkill();
 fail_rfkill:
-       free_page((unsigned long)buffer);
-fail_buffer:
        platform_device_del(platform_device);
 fail_platform_device2:
        platform_device_put(platform_device);
 fail_platform_device1:
        platform_driver_unregister(&platform_driver);
 fail_platform_driver:
-       kfree(da_tokens);
        return ret;
 }
 
@@ -2232,8 +2073,6 @@ static void __exit dell_exit(void)
                platform_device_unregister(platform_device);
                platform_driver_unregister(&platform_driver);
        }
-       kfree(da_tokens);
-       free_page((unsigned long)buffer);
 }
 
 /* dell-rbtn.c driver export functions which will not work correctly (and could
diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c
new file mode 100644 (file)
index 0000000..d1aae53
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ *  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/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;
+
+struct calling_interface_buffer *buffer;
+EXPORT_SYMBOL_GPL(buffer);
+static DEFINE_MUTEX(buffer_mutex);
+
+static int da_command_address;
+static int da_command_code;
+static int da_num_tokens;
+struct calling_interface_token *da_tokens;
+EXPORT_SYMBOL_GPL(da_tokens);
+
+void get_buffer(void)
+{
+       mutex_lock(&buffer_mutex);
+       clear_buffer();
+}
+EXPORT_SYMBOL_GPL(get_buffer);
+
+void clear_buffer(void)
+{
+       memset(buffer, 0, sizeof(struct calling_interface_buffer));
+}
+EXPORT_SYMBOL_GPL(clear_buffer);
+
+void release_buffer(void)
+{
+       mutex_unlock(&buffer_mutex);
+}
+EXPORT_SYMBOL_GPL(release_buffer);
+
+struct calling_interface_buffer *
+dell_send_request(struct calling_interface_buffer *buffer,
+                 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);
+
+       return buffer;
+}
+EXPORT_SYMBOL_GPL(dell_send_request);
+
+int find_token_id(int tokenid)
+{
+       int i;
+
+       for (i = 0; i < da_num_tokens; i++) {
+               if (da_tokens[i].tokenID == tokenid)
+                       return i;
+       }
+
+       return -1;
+}
+EXPORT_SYMBOL_GPL(find_token_id);
+
+int find_token_location(int tokenid)
+{
+       int id;
+
+       id = find_token_id(tokenid);
+       if (id == -1)
+               return -1;
+
+       return da_tokens[id].location;
+}
+EXPORT_SYMBOL_GPL(find_token_location);
+
+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");
diff --git a/drivers/platform/x86/dell-smbios.h b/drivers/platform/x86/dell-smbios.h
new file mode 100644 (file)
index 0000000..3bc9080
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ *  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.
+ */
+
+#ifndef _DELL_SMBIOS_H_
+#define _DELL_SMBIOS_H_
+
+/* This structure will be modified by the firmware when we enter
+ * system management mode, hence the volatiles */
+
+struct calling_interface_buffer {
+       u16 class;
+       u16 select;
+       volatile u32 input[4];
+       volatile u32 output[4];
+} __packed;
+
+struct calling_interface_token {
+       u16 tokenID;
+       u16 location;
+       union {
+               u16 value;
+               u16 stringlength;
+       };
+};
+
+extern struct calling_interface_buffer *buffer;
+extern struct calling_interface_token *da_tokens;
+
+void get_buffer(void);
+void clear_buffer(void);
+void release_buffer(void);
+struct calling_interface_buffer *
+dell_send_request(struct calling_interface_buffer *buffer,
+                 int class, int select);
+
+int find_token_id(int tokenid);
+int find_token_location(int tokenid);
+#endif