Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2f9f26bd authored by Michał Kępień's avatar Michał Kępień Committed by Darren Hart
Browse files

dell-laptop: extract SMBIOS-related code to a separate module



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: default avatarMichał Kępień <kernel@kempniu.pl>
Reviewed-by: default avatarPali Rohár <pali.rohar@gmail.com>
[dvhart: Include linux/io.h in dell-smbios.c as caught by lkp]
Signed-off-by: default avatarDarren Hart <dvhart@linux.intel.com>
parent 7faa6a37
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
@@ -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
+1 −0
Original line number Diff line number Diff line
@@ -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
+1 −162
Original line number Diff line number Diff line
@@ -28,12 +28,11 @@
#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
@@ -44,33 +43,6 @@
#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
+194 −0
Original line number Diff line number Diff line
/*
 *  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");
+50 −0
Original line number Diff line number Diff line
/*
 *  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