LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH] Platform: add Samsung Laptop platform driver
@ 2011-02-09 22:40 Greg KH
  2011-02-09 22:44 ` Randy Dunlap
                   ` (4 more replies)
  0 siblings, 5 replies; 53+ messages in thread
From: Greg KH @ 2011-02-09 22:40 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: Randy Dunlap, linux-kernel, platform-driver-x86

From: Greg Kroah-Hartman <gregkh@suse.de>

This adds the samsung-laptop driver to the kernel.  It now supports
all known Samsung laptops.

Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 Documentation/ABI/testing/sysfs-driver-samsung-laptop |   19 
 drivers/platform/x86/Kconfig                          |   13 
 drivers/platform/x86/Makefile                         |    1 
 drivers/platform/x86/samsung-laptop.c                 |  768 ++++++++++++++++++
 4 files changed, 801 insertions(+)

Matthew, this is a copy of the latest version in the linux-next tree of the
driver.  Once it has been accepted into your tree, I'll delete the
staging driver.  Or, if you want to give your ACK, I can just move the
driver from staging into this directory in my tree, which will properly
preserve the history of the code.


diff --git a/Documentation/ABI/testing/sysfs-driver-samsung-laptop b/Documentation/ABI/testing/sysfs-driver-samsung-laptop
new file mode 100644
index 0000000..0a81023
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-samsung-laptop
@@ -0,0 +1,19 @@
+What:		/sys/devices/platform/samsung/performance_level
+Date:		January 1, 2010
+KernelVersion:	2.6.33
+Contact:	Greg Kroah-Hartman <gregkh@suse.de>
+Description:	Some Samsung laptops have different "performance levels"
+		that are can be modified by a function key, and by this
+		sysfs file.  These values don't always make a whole lot
+		of sense, but some users like to modify them to keep
+		their fans quiet at all costs.  Reading from this file
+		will show the current performance level.  Writing to the
+		file can change this value.
+			Valid options:
+				"silent"
+				"normal"
+				"overclock"
+		Note that not all laptops support all of these options.
+		Specifically, not all support the "overclock" option,
+		and it's still unknown if this value even changes
+		anything, other than making the user feel a bit better.
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index d163bc2..da9aed1 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -654,4 +654,17 @@ config XO1_RFKILL
 	  Support for enabling/disabling the WLAN interface on the OLPC XO-1
 	  laptop.
 
+config SAMSUNG_LAPTOP
+	tristate "Samsung Laptop driver"
+	depends on RFKILL && BACKLIGHT_CLASS_DEVICE && X86
+	---help---
+	  This module implements a driver for a wide range of different
+	  Samsung laptops.  It offers control over the different
+	  function keys, wireless LED, LCD backlight level, and
+	  sometimes provides a "performance_control" sysfs file to allow
+	  the performance level of the laptop to be changed.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called samsung-laptop.
+
 endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 4ec4ff8..ad2fb97 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -34,3 +34,4 @@ obj-$(CONFIG_INTEL_IPS)		+= intel_ips.o
 obj-$(CONFIG_GPIO_INTEL_PMIC)	+= intel_pmic_gpio.o
 obj-$(CONFIG_XO1_RFKILL)	+= xo1-rfkill.o
 obj-$(CONFIG_IBM_RTL)		+= ibm_rtl.o
+obj-$(CONFIG_SAMSUNG_LAPTOP)	+= samsung-laptop.o
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c
new file mode 100644
index 0000000..51ec621
--- /dev/null
+++ b/drivers/platform/x86/samsung-laptop.c
@@ -0,0 +1,768 @@
+/*
+ * Samsung Laptop driver
+ *
+ * Copyright (C) 2009 Greg Kroah-Hartman (gregkh@suse.de)
+ * Copyright (C) 2009 Novell 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/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+#include <linux/dmi.h>
+#include <linux/platform_device.h>
+#include <linux/rfkill.h>
+
+/*
+ * This driver is needed because a number of Samsung laptops do not hook
+ * their control settings through ACPI.  So we have to poke around in the
+ * BIOS to do things like brightness values, and "special" key controls.
+ */
+
+/*
+ * We have 0 - 8 as valid brightness levels.  The specs say that level 0 should
+ * be reserved by the BIOS (which really doesn't make much sense), we tell
+ * userspace that the value is 0 - 7 and then just tell the hardware 1 - 8
+ */
+#define MAX_BRIGHT	0x07
+
+
+#define SABI_IFACE_MAIN			0x00
+#define SABI_IFACE_SUB			0x02
+#define SABI_IFACE_COMPLETE		0x04
+#define SABI_IFACE_DATA			0x05
+
+/* Structure to get data back to the calling function */
+struct sabi_retval {
+	u8 retval[20];
+};
+
+struct sabi_header_offsets {
+	u8 port;
+	u8 re_mem;
+	u8 iface_func;
+	u8 en_mem;
+	u8 data_offset;
+	u8 data_segment;
+};
+
+struct sabi_commands {
+	/*
+	 * Brightness is 0 - 8, as described above.
+	 * Value 0 is for the BIOS to use
+	 */
+	u8 get_brightness;
+	u8 set_brightness;
+
+	/*
+	 * first byte:
+	 * 0x00 - wireless is off
+	 * 0x01 - wireless is on
+	 * second byte:
+	 * 0x02 - 3G is off
+	 * 0x03 - 3G is on
+	 * TODO, verify 3G is correct, that doesn't seem right...
+	 */
+	u8 get_wireless_button;
+	u8 set_wireless_button;
+
+	/* 0 is off, 1 is on */
+	u8 get_backlight;
+	u8 set_backlight;
+
+	/*
+	 * 0x80 or 0x00 - no action
+	 * 0x81 - recovery key pressed
+	 */
+	u8 get_recovery_mode;
+	u8 set_recovery_mode;
+
+	/*
+	 * on seclinux: 0 is low, 1 is high,
+	 * on swsmi: 0 is normal, 1 is silent, 2 is turbo
+	 */
+	u8 get_performance_level;
+	u8 set_performance_level;
+
+	/*
+	 * Tell the BIOS that Linux is running on this machine.
+	 * 81 is on, 80 is off
+	 */
+	u8 set_linux;
+};
+
+struct sabi_performance_level {
+	const char *name;
+	u8 value;
+};
+
+struct sabi_config {
+	const char *test_string;
+	u16 main_function;
+	struct sabi_header_offsets header_offsets;
+	struct sabi_commands commands;
+	struct sabi_performance_level performance_levels[4];
+};
+
+static struct sabi_config sabi_configs[] = {
+	{
+		.test_string = "SECLINUX",
+
+		.main_function = 0x4c59,
+
+		.header_offsets = {
+			.port = 0x00,
+			.re_mem = 0x02,
+			.iface_func = 0x03,
+			.en_mem = 0x04,
+			.data_offset = 0x05,
+			.data_segment = 0x07,
+		},
+
+		.commands = {
+			.get_brightness = 0x00,
+			.set_brightness = 0x01,
+
+			.get_wireless_button = 0x02,
+			.set_wireless_button = 0x03,
+
+			.get_backlight = 0x04,
+			.set_backlight = 0x05,
+
+			.get_recovery_mode = 0x06,
+			.set_recovery_mode = 0x07,
+
+			.get_performance_level = 0x08,
+			.set_performance_level = 0x09,
+
+			.set_linux = 0x0a,
+		},
+
+		.performance_levels = {
+			{
+				.name = "silent",
+				.value = 0,
+			},
+			{
+				.name = "normal",
+				.value = 1,
+			},
+			{ },
+		},
+	},
+	{
+		.test_string = "SwSmi@",
+
+		.main_function = 0x5843,
+
+		.header_offsets = {
+			.port = 0x00,
+			.re_mem = 0x04,
+			.iface_func = 0x02,
+			.en_mem = 0x03,
+			.data_offset = 0x05,
+			.data_segment = 0x07,
+		},
+
+		.commands = {
+			.get_brightness = 0x10,
+			.set_brightness = 0x11,
+
+			.get_wireless_button = 0x12,
+			.set_wireless_button = 0x13,
+
+			.get_backlight = 0x2d,
+			.set_backlight = 0x2e,
+
+			.get_recovery_mode = 0xff,
+			.set_recovery_mode = 0xff,
+
+			.get_performance_level = 0x31,
+			.set_performance_level = 0x32,
+
+			.set_linux = 0xff,
+		},
+
+		.performance_levels = {
+			{
+				.name = "normal",
+				.value = 0,
+			},
+			{
+				.name = "silent",
+				.value = 1,
+			},
+			{
+				.name = "overclock",
+				.value = 2,
+			},
+			{ },
+		},
+	},
+	{ },
+};
+
+static struct sabi_config *sabi_config;
+
+static void __iomem *sabi;
+static void __iomem *sabi_iface;
+static void __iomem *f0000_segment;
+static struct backlight_device *backlight_device;
+static struct mutex sabi_mutex;
+static struct platform_device *sdev;
+static struct rfkill *rfk;
+
+static int force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force,
+		"Disable the DMI check and forces the driver to be loaded");
+
+static int debug;
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+static int sabi_get_command(u8 command, struct sabi_retval *sretval)
+{
+	int retval = 0;
+	u16 port = readw(sabi + sabi_config->header_offsets.port);
+
+	mutex_lock(&sabi_mutex);
+
+	/* enable memory to be able to write to it */
+	outb(readb(sabi + sabi_config->header_offsets.en_mem), port);
+
+	/* write out the command */
+	writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN);
+	writew(command, sabi_iface + SABI_IFACE_SUB);
+	writeb(0, sabi_iface + SABI_IFACE_COMPLETE);
+	outb(readb(sabi + sabi_config->header_offsets.iface_func), port);
+
+	/* write protect memory to make it safe */
+	outb(readb(sabi + sabi_config->header_offsets.re_mem), port);
+
+	/* see if the command actually succeeded */
+	if (readb(sabi_iface + SABI_IFACE_COMPLETE) == 0xaa &&
+	    readb(sabi_iface + SABI_IFACE_DATA) != 0xff) {
+		/*
+		 * It did!
+		 * Save off the data into a structure so the caller use it.
+		 * Right now we only care about the first 4 bytes,
+		 * I suppose there are commands that need more, but I don't
+		 * know about them.
+		 */
+		sretval->retval[0] = readb(sabi_iface + SABI_IFACE_DATA);
+		sretval->retval[1] = readb(sabi_iface + SABI_IFACE_DATA + 1);
+		sretval->retval[2] = readb(sabi_iface + SABI_IFACE_DATA + 2);
+		sretval->retval[3] = readb(sabi_iface + SABI_IFACE_DATA + 3);
+		goto exit;
+	}
+
+	/* Something bad happened, so report it and error out */
+	printk(KERN_WARNING "SABI command 0x%02x failed with completion flag 0x%02x and output 0x%02x\n",
+		command, readb(sabi_iface + SABI_IFACE_COMPLETE),
+		readb(sabi_iface + SABI_IFACE_DATA));
+	retval = -EINVAL;
+exit:
+	mutex_unlock(&sabi_mutex);
+	return retval;
+
+}
+
+static int sabi_set_command(u8 command, u8 data)
+{
+	int retval = 0;
+	u16 port = readw(sabi + sabi_config->header_offsets.port);
+
+	mutex_lock(&sabi_mutex);
+
+	/* enable memory to be able to write to it */
+	outb(readb(sabi + sabi_config->header_offsets.en_mem), port);
+
+	/* write out the command */
+	writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN);
+	writew(command, sabi_iface + SABI_IFACE_SUB);
+	writeb(0, sabi_iface + SABI_IFACE_COMPLETE);
+	writeb(data, sabi_iface + SABI_IFACE_DATA);
+	outb(readb(sabi + sabi_config->header_offsets.iface_func), port);
+
+	/* write protect memory to make it safe */
+	outb(readb(sabi + sabi_config->header_offsets.re_mem), port);
+
+	/* see if the command actually succeeded */
+	if (readb(sabi_iface + SABI_IFACE_COMPLETE) == 0xaa &&
+	    readb(sabi_iface + SABI_IFACE_DATA) != 0xff) {
+		/* it did! */
+		goto exit;
+	}
+
+	/* Something bad happened, so report it and error out */
+	printk(KERN_WARNING "SABI command 0x%02x failed with completion flag 0x%02x and output 0x%02x\n",
+		command, readb(sabi_iface + SABI_IFACE_COMPLETE),
+		readb(sabi_iface + SABI_IFACE_DATA));
+	retval = -EINVAL;
+exit:
+	mutex_unlock(&sabi_mutex);
+	return retval;
+}
+
+static void test_backlight(void)
+{
+	struct sabi_retval sretval;
+
+	sabi_get_command(sabi_config->commands.get_backlight, &sretval);
+	printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
+
+	sabi_set_command(sabi_config->commands.set_backlight, 0);
+	printk(KERN_DEBUG "backlight should be off\n");
+
+	sabi_get_command(sabi_config->commands.get_backlight, &sretval);
+	printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
+
+	msleep(1000);
+
+	sabi_set_command(sabi_config->commands.set_backlight, 1);
+	printk(KERN_DEBUG "backlight should be on\n");
+
+	sabi_get_command(sabi_config->commands.get_backlight, &sretval);
+	printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
+}
+
+static void test_wireless(void)
+{
+	struct sabi_retval sretval;
+
+	sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
+	printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
+
+	sabi_set_command(sabi_config->commands.set_wireless_button, 0);
+	printk(KERN_DEBUG "wireless led should be off\n");
+
+	sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
+	printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
+
+	msleep(1000);
+
+	sabi_set_command(sabi_config->commands.set_wireless_button, 1);
+	printk(KERN_DEBUG "wireless led should be on\n");
+
+	sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
+	printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
+}
+
+static u8 read_brightness(void)
+{
+	struct sabi_retval sretval;
+	int user_brightness = 0;
+	int retval;
+
+	retval = sabi_get_command(sabi_config->commands.get_brightness,
+				  &sretval);
+	if (!retval)
+		user_brightness = sretval.retval[0];
+		if (user_brightness != 0)
+			--user_brightness;
+	return user_brightness;
+}
+
+static void set_brightness(u8 user_brightness)
+{
+	sabi_set_command(sabi_config->commands.set_brightness,
+			 user_brightness + 1);
+}
+
+static int get_brightness(struct backlight_device *bd)
+{
+	return (int)read_brightness();
+}
+
+static int update_status(struct backlight_device *bd)
+{
+	set_brightness(bd->props.brightness);
+
+	if (bd->props.power == FB_BLANK_UNBLANK)
+		sabi_set_command(sabi_config->commands.set_backlight, 1);
+	else
+		sabi_set_command(sabi_config->commands.set_backlight, 0);
+	return 0;
+}
+
+static const struct backlight_ops backlight_ops = {
+	.get_brightness	= get_brightness,
+	.update_status	= update_status,
+};
+
+static int rfkill_set(void *data, bool blocked)
+{
+	/* Do something with blocked...*/
+	/*
+	 * blocked == false is on
+	 * blocked == true is off
+	 */
+	if (blocked)
+		sabi_set_command(sabi_config->commands.set_wireless_button, 0);
+	else
+		sabi_set_command(sabi_config->commands.set_wireless_button, 1);
+
+	return 0;
+}
+
+static struct rfkill_ops rfkill_ops = {
+	.set_block = rfkill_set,
+};
+
+static int init_wireless(struct platform_device *sdev)
+{
+	int retval;
+
+	rfk = rfkill_alloc("samsung-wifi", &sdev->dev, RFKILL_TYPE_WLAN,
+			   &rfkill_ops, NULL);
+	if (!rfk)
+		return -ENOMEM;
+
+	retval = rfkill_register(rfk);
+	if (retval) {
+		rfkill_destroy(rfk);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void destroy_wireless(void)
+{
+	rfkill_unregister(rfk);
+	rfkill_destroy(rfk);
+}
+
+static ssize_t get_performance_level(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct sabi_retval sretval;
+	int retval;
+	int i;
+
+	/* Read the state */
+	retval = sabi_get_command(sabi_config->commands.get_performance_level,
+				  &sretval);
+	if (retval)
+		return retval;
+
+	/* The logic is backwards, yeah, lots of fun... */
+	for (i = 0; sabi_config->performance_levels[i].name; ++i) {
+		if (sretval.retval[0] == sabi_config->performance_levels[i].value)
+			return sprintf(buf, "%s\n", sabi_config->performance_levels[i].name);
+	}
+	return sprintf(buf, "%s\n", "unknown");
+}
+
+static ssize_t set_performance_level(struct device *dev,
+				struct device_attribute *attr, const char *buf,
+				size_t count)
+{
+	if (count >= 1) {
+		int i;
+		for (i = 0; sabi_config->performance_levels[i].name; ++i) {
+			struct sabi_performance_level *level =
+				&sabi_config->performance_levels[i];
+			if (!strncasecmp(level->name, buf, strlen(level->name))) {
+				sabi_set_command(sabi_config->commands.set_performance_level,
+						 level->value);
+				break;
+			}
+		}
+		if (!sabi_config->performance_levels[i].name)
+			return -EINVAL;
+	}
+	return count;
+}
+static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO,
+		   get_performance_level, set_performance_level);
+
+
+static int __init dmi_check_cb(const struct dmi_system_id *id)
+{
+	printk(KERN_INFO KBUILD_MODNAME ": found laptop model '%s'\n",
+		id->ident);
+	return 0;
+}
+
+static struct dmi_system_id __initdata samsung_dmi_table[] = {
+	{
+		.ident = "N128",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N128"),
+			DMI_MATCH(DMI_BOARD_NAME, "N128"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "N130",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N130"),
+			DMI_MATCH(DMI_BOARD_NAME, "N130"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "X125",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X125"),
+			DMI_MATCH(DMI_BOARD_NAME, "X125"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "NC10",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "NC10"),
+			DMI_MATCH(DMI_BOARD_NAME, "NC10"),
+		},
+		.callback = dmi_check_cb,
+	},
+		{
+		.ident = "NP-Q45",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"),
+			DMI_MATCH(DMI_BOARD_NAME, "SQ45S70S"),
+		},
+		.callback = dmi_check_cb,
+		},
+	{
+		.ident = "X360",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
+			DMI_MATCH(DMI_BOARD_NAME, "X360"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "R518",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "R518"),
+			DMI_MATCH(DMI_BOARD_NAME, "R518"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "N150/N210/N220",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
+			DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "R530/R730",
+		.matches = {
+		      DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+		      DMI_MATCH(DMI_PRODUCT_NAME, "R530/R730"),
+		      DMI_MATCH(DMI_BOARD_NAME, "R530/R730"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "NF110/NF210/NF310",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"),
+			DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
+
+static int find_signature(void __iomem *memcheck, const char *testStr)
+{
+	int i = 0;
+	int loca;
+
+	for (loca = 0; loca < 0xffff; loca++) {
+		char temp = readb(memcheck + loca);
+
+		if (temp == testStr[i]) {
+			if (i == strlen(testStr)-1)
+				break;
+			++i;
+		} else {
+			i = 0;
+		}
+	}
+	return loca;
+}
+
+static int __init samsung_init(void)
+{
+	struct backlight_properties props;
+	struct sabi_retval sretval;
+	unsigned int ifaceP;
+	int i;
+	int loca;
+	int retval;
+
+	mutex_init(&sabi_mutex);
+
+	if (!force && !dmi_check_system(samsung_dmi_table))
+		return -ENODEV;
+
+	f0000_segment = ioremap(0xf0000, 0xffff);
+	if (!f0000_segment) {
+		printk(KERN_ERR "Can't map the segment at 0xf0000\n");
+		return -EINVAL;
+	}
+
+	/* Try to find one of the signatures in memory to find the header */
+	for (i = 0; sabi_configs[i].test_string != 0; ++i) {
+		sabi_config = &sabi_configs[i];
+		loca = find_signature(f0000_segment, sabi_config->test_string);
+		if (loca != 0xffff)
+			break;
+	}
+
+	if (loca == 0xffff) {
+		printk(KERN_ERR "This computer does not support SABI\n");
+		goto error_no_signature;
+	}
+
+	/* point to the SMI port Number */
+	loca += 1;
+	sabi = (f0000_segment + loca);
+
+	if (debug) {
+		printk(KERN_DEBUG "This computer supports SABI==%x\n",
+			loca + 0xf0000 - 6);
+		printk(KERN_DEBUG "SABI header:\n");
+		printk(KERN_DEBUG " SMI Port Number = 0x%04x\n",
+			readw(sabi + sabi_config->header_offsets.port));
+		printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n",
+			readb(sabi + sabi_config->header_offsets.iface_func));
+		printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n",
+			readb(sabi + sabi_config->header_offsets.en_mem));
+		printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n",
+			readb(sabi + sabi_config->header_offsets.re_mem));
+		printk(KERN_DEBUG " SABI data offset = 0x%04x\n",
+			readw(sabi + sabi_config->header_offsets.data_offset));
+		printk(KERN_DEBUG " SABI data segment = 0x%04x\n",
+			readw(sabi + sabi_config->header_offsets.data_segment));
+	}
+
+	/* Get a pointer to the SABI Interface */
+	ifaceP = (readw(sabi + sabi_config->header_offsets.data_segment) & 0x0ffff) << 4;
+	ifaceP += readw(sabi + sabi_config->header_offsets.data_offset) & 0x0ffff;
+	sabi_iface = ioremap(ifaceP, 16);
+	if (!sabi_iface) {
+		printk(KERN_ERR "Can't remap %x\n", ifaceP);
+		goto exit;
+	}
+	if (debug) {
+		printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP);
+		printk(KERN_DEBUG "sabi_iface = %p\n", sabi_iface);
+
+		test_backlight();
+		test_wireless();
+
+		retval = sabi_get_command(sabi_config->commands.get_brightness,
+					  &sretval);
+		printk(KERN_DEBUG "brightness = 0x%02x\n", sretval.retval[0]);
+	}
+
+	/* Turn on "Linux" mode in the BIOS */
+	if (sabi_config->commands.set_linux != 0xff) {
+		retval = sabi_set_command(sabi_config->commands.set_linux,
+					  0x81);
+		if (retval) {
+			printk(KERN_ERR KBUILD_MODNAME ": Linux mode was not set!\n");
+			goto error_no_platform;
+		}
+	}
+
+	/* knock up a platform device to hang stuff off of */
+	sdev = platform_device_register_simple("samsung", -1, NULL, 0);
+	if (IS_ERR(sdev))
+		goto error_no_platform;
+
+	/* create a backlight device to talk to this one */
+	memset(&props, 0, sizeof(struct backlight_properties));
+	props.max_brightness = MAX_BRIGHT;
+	backlight_device = backlight_device_register("samsung", &sdev->dev,
+						     NULL, &backlight_ops,
+						     &props);
+	if (IS_ERR(backlight_device))
+		goto error_no_backlight;
+
+	backlight_device->props.brightness = read_brightness();
+	backlight_device->props.power = FB_BLANK_UNBLANK;
+	backlight_update_status(backlight_device);
+
+	retval = init_wireless(sdev);
+	if (retval)
+		goto error_no_rfk;
+
+	retval = device_create_file(&sdev->dev, &dev_attr_performance_level);
+	if (retval)
+		goto error_file_create;
+
+exit:
+	return 0;
+
+error_file_create:
+	destroy_wireless();
+
+error_no_rfk:
+	backlight_device_unregister(backlight_device);
+
+error_no_backlight:
+	platform_device_unregister(sdev);
+
+error_no_platform:
+	iounmap(sabi_iface);
+
+error_no_signature:
+	iounmap(f0000_segment);
+	return -EINVAL;
+}
+
+static void __exit samsung_exit(void)
+{
+	/* Turn off "Linux" mode in the BIOS */
+	if (sabi_config->commands.set_linux != 0xff)
+		sabi_set_command(sabi_config->commands.set_linux, 0x80);
+
+	device_remove_file(&sdev->dev, &dev_attr_performance_level);
+	backlight_device_unregister(backlight_device);
+	destroy_wireless();
+	iounmap(sabi_iface);
+	iounmap(f0000_segment);
+	platform_device_unregister(sdev);
+}
+
+module_init(samsung_init);
+module_exit(samsung_exit);
+
+MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>");
+MODULE_DESCRIPTION("Samsung Backlight driver");
+MODULE_LICENSE("GPL");

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-02-09 22:40 [PATCH] Platform: add Samsung Laptop platform driver Greg KH
@ 2011-02-09 22:44 ` Randy Dunlap
  2011-02-09 22:50   ` Greg KH
  2011-02-09 22:50 ` Matthew Garrett
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 53+ messages in thread
From: Randy Dunlap @ 2011-02-09 22:44 UTC (permalink / raw)
  To: Greg KH; +Cc: Matthew Garrett, linux-kernel, platform-driver-x86

On Wed, 9 Feb 2011 14:40:06 -0800 Greg KH wrote:

> From: Greg Kroah-Hartman <gregkh@suse.de>
> 
> This adds the samsung-laptop driver to the kernel.  It now supports
> all known Samsung laptops.
> 
> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
> ---
>  Documentation/ABI/testing/sysfs-driver-samsung-laptop |   19 
>  drivers/platform/x86/Kconfig                          |   13 
>  drivers/platform/x86/Makefile                         |    1 
>  drivers/platform/x86/samsung-laptop.c                 |  768 ++++++++++++++++++
>  4 files changed, 801 insertions(+)
> 
> Matthew, this is a copy of the latest version in the linux-next tree of the
> driver.  Once it has been accepted into your tree, I'll delete the
> staging driver.  Or, if you want to give your ACK, I can just move the
> driver from staging into this directory in my tree, which will properly
> preserve the history of the code.


> diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
> index d163bc2..da9aed1 100644
> --- a/drivers/platform/x86/Kconfig
> +++ b/drivers/platform/x86/Kconfig
> @@ -654,4 +654,17 @@ config XO1_RFKILL
>  	  Support for enabling/disabling the WLAN interface on the OLPC XO-1
>  	  laptop.
>  
> +config SAMSUNG_LAPTOP
> +	tristate "Samsung Laptop driver"
> +	depends on RFKILL && BACKLIGHT_CLASS_DEVICE && X86

This entire Kconfig file already depends on X86, so the "&& X86" above
is redundant.

> +	---help---
> +	  This module implements a driver for a wide range of different
> +	  Samsung laptops.  It offers control over the different
> +	  function keys, wireless LED, LCD backlight level, and
> +	  sometimes provides a "performance_control" sysfs file to allow
> +	  the performance level of the laptop to be changed.
> +
> +	  To compile this driver as a module, choose M here: the module
> +	  will be called samsung-laptop.
> +
>  endif # X86_PLATFORM_DEVICES


---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-02-09 22:44 ` Randy Dunlap
@ 2011-02-09 22:50   ` Greg KH
  2011-02-09 22:58     ` Matthew Garrett
  0 siblings, 1 reply; 53+ messages in thread
From: Greg KH @ 2011-02-09 22:50 UTC (permalink / raw)
  To: Randy Dunlap; +Cc: Matthew Garrett, linux-kernel, platform-driver-x86

On Wed, Feb 09, 2011 at 02:44:19PM -0800, Randy Dunlap wrote:
> On Wed, 9 Feb 2011 14:40:06 -0800 Greg KH wrote:
> 
> > From: Greg Kroah-Hartman <gregkh@suse.de>
> > 
> > This adds the samsung-laptop driver to the kernel.  It now supports
> > all known Samsung laptops.
> > 
> > Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
> > ---
> >  Documentation/ABI/testing/sysfs-driver-samsung-laptop |   19 
> >  drivers/platform/x86/Kconfig                          |   13 
> >  drivers/platform/x86/Makefile                         |    1 
> >  drivers/platform/x86/samsung-laptop.c                 |  768 ++++++++++++++++++
> >  4 files changed, 801 insertions(+)
> > 
> > Matthew, this is a copy of the latest version in the linux-next tree of the
> > driver.  Once it has been accepted into your tree, I'll delete the
> > staging driver.  Or, if you want to give your ACK, I can just move the
> > driver from staging into this directory in my tree, which will properly
> > preserve the history of the code.
> 
> 
> > diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
> > index d163bc2..da9aed1 100644
> > --- a/drivers/platform/x86/Kconfig
> > +++ b/drivers/platform/x86/Kconfig
> > @@ -654,4 +654,17 @@ config XO1_RFKILL
> >  	  Support for enabling/disabling the WLAN interface on the OLPC XO-1
> >  	  laptop.
> >  
> > +config SAMSUNG_LAPTOP
> > +	tristate "Samsung Laptop driver"
> > +	depends on RFKILL && BACKLIGHT_CLASS_DEVICE && X86
> 
> This entire Kconfig file already depends on X86, so the "&& X86" above
> is redundant.

Ah, yeah, nice catch, that came from when it was stand-alone in the
staging directory.  Can't hurt though :)

Matthew, want me to respin for this change?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-02-09 22:40 [PATCH] Platform: add Samsung Laptop platform driver Greg KH
  2011-02-09 22:44 ` Randy Dunlap
@ 2011-02-09 22:50 ` Matthew Garrett
  2011-02-09 23:02   ` Greg KH
  2011-02-11 11:37 ` Richard Schütz
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 53+ messages in thread
From: Matthew Garrett @ 2011-02-09 22:50 UTC (permalink / raw)
  To: Greg KH; +Cc: Randy Dunlap, linux-kernel, platform-driver-x86

\o/

A quick glance suggests that the firmware interface is an abomination 
and really there's no reason for them not to have used an existing 
interface of some sort, but that's par for the course. I'll review it 
properly now.

-- 
Matthew Garrett | mjg59@srcf.ucam.org

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-02-09 22:50   ` Greg KH
@ 2011-02-09 22:58     ` Matthew Garrett
  0 siblings, 0 replies; 53+ messages in thread
From: Matthew Garrett @ 2011-02-09 22:58 UTC (permalink / raw)
  To: Greg KH; +Cc: Randy Dunlap, linux-kernel, platform-driver-x86

Nah, I'll fix that up.

-- 
Matthew Garrett | mjg59@srcf.ucam.org

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-02-09 22:50 ` Matthew Garrett
@ 2011-02-09 23:02   ` Greg KH
  0 siblings, 0 replies; 53+ messages in thread
From: Greg KH @ 2011-02-09 23:02 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: Randy Dunlap, linux-kernel, platform-driver-x86

On Wed, Feb 09, 2011 at 10:50:56PM +0000, Matthew Garrett wrote:
> \o/
> 
> A quick glance suggests that the firmware interface is an abomination 
> and really there's no reason for them not to have used an existing 
> interface of some sort, but that's par for the course. I'll review it 
> properly now.

The firmware interface pre-dates ACPI.  Samsung seems to have only
started using ACPI for their newest models, as it's a requirement for
Win7 certification.  But even there, they still rely on their SABI
interface for the majority of the "odd" hardware control knobs,
including the backlight control, which baffles me even to this day.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-02-09 22:40 [PATCH] Platform: add Samsung Laptop platform driver Greg KH
  2011-02-09 22:44 ` Randy Dunlap
  2011-02-09 22:50 ` Matthew Garrett
@ 2011-02-11 11:37 ` Richard Schütz
  2011-02-11 15:22   ` Greg KH
  2011-02-11 15:45 ` Matthew Garrett
  2011-02-16 10:06 ` Nikolai Kondrashov
  4 siblings, 1 reply; 53+ messages in thread
From: Richard Schütz @ 2011-02-11 11:37 UTC (permalink / raw)
  To: Greg KH; +Cc: Matthew Garrett, Randy Dunlap, linux-kernel, platform-driver-x86

 > +static struct dmi_system_id __initdata samsung_dmi_table[] = {
 > +	{
 > +		.ident = "N128",
 > +		.matches = {
 > +			DMI_MATCH(DMI_SYS_VENDOR,
 > +					"SAMSUNG ELECTRONICS CO., LTD."),
 > +			DMI_MATCH(DMI_PRODUCT_NAME, "N128"),
 > +			DMI_MATCH(DMI_BOARD_NAME, "N128"),
 > +		},
 > +		.callback = dmi_check_cb,
 > +	},
 > +	{
 > +		.ident = "N130",
 > +		.matches = {
 > +			DMI_MATCH(DMI_SYS_VENDOR,
 > +					"SAMSUNG ELECTRONICS CO., LTD."),
 > +			DMI_MATCH(DMI_PRODUCT_NAME, "N130"),
 > +			DMI_MATCH(DMI_BOARD_NAME, "N130"),
 > +		},
 > +		.callback = dmi_check_cb,
 > +	},
 > +	{
 > +		.ident = "X125",
 > +		.matches = {
 > +			DMI_MATCH(DMI_SYS_VENDOR,
 > +					"SAMSUNG ELECTRONICS CO., LTD."),
 > +			DMI_MATCH(DMI_PRODUCT_NAME, "X125"),
 > +			DMI_MATCH(DMI_BOARD_NAME, "X125"),
 > +		},
 > +		.callback = dmi_check_cb,
 > +	},
 > +	{
 > +		.ident = "NC10",
 > +		.matches = {
 > +			DMI_MATCH(DMI_SYS_VENDOR,
 > +					"SAMSUNG ELECTRONICS CO., LTD."),
 > +			DMI_MATCH(DMI_PRODUCT_NAME, "NC10"),
 > +			DMI_MATCH(DMI_BOARD_NAME, "NC10"),
 > +		},
 > +		.callback = dmi_check_cb,
 > +	},
 > +		{
 > +		.ident = "NP-Q45",
 > +		.matches = {
 > +			DMI_MATCH(DMI_SYS_VENDOR,
 > +					"SAMSUNG ELECTRONICS CO., LTD."),
 > +			DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"),
 > +			DMI_MATCH(DMI_BOARD_NAME, "SQ45S70S"),
 > +		},
 > +		.callback = dmi_check_cb,
 > +		},
 > +	{
 > +		.ident = "X360",
 > +		.matches = {
 > +			DMI_MATCH(DMI_SYS_VENDOR,
 > +					"SAMSUNG ELECTRONICS CO., LTD."),
 > +			DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
 > +			DMI_MATCH(DMI_BOARD_NAME, "X360"),
 > +		},
 > +		.callback = dmi_check_cb,
 > +	},
 > +	{
 > +		.ident = "R518",
 > +		.matches = {
 > +			DMI_MATCH(DMI_SYS_VENDOR,
 > +					"SAMSUNG ELECTRONICS CO., LTD."),
 > +			DMI_MATCH(DMI_PRODUCT_NAME, "R518"),
 > +			DMI_MATCH(DMI_BOARD_NAME, "R518"),
 > +		},
 > +		.callback = dmi_check_cb,
 > +	},
 > +	{
 > +		.ident = "N150/N210/N220",
 > +		.matches = {
 > +			DMI_MATCH(DMI_SYS_VENDOR,
 > +					"SAMSUNG ELECTRONICS CO., LTD."),
 > +			DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
 > +			DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
 > +		},
 > +		.callback = dmi_check_cb,
 > +	},
 > +	{
 > +		.ident = "R530/R730",
 > +		.matches = {
 > +		      DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
 > +		      DMI_MATCH(DMI_PRODUCT_NAME, "R530/R730"),
 > +		      DMI_MATCH(DMI_BOARD_NAME, "R530/R730"),
 > +		},
 > +		.callback = dmi_check_cb,
 > +	},
 > +	{
 > +		.ident = "NF110/NF210/NF310",
 > +		.matches = {
 > +			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
 > +			DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"),
 > +			DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"),
 > +		},
 > +		.callback = dmi_check_cb,
 > +	},
 > +	{ },
 > +};
 > +MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);

Could you add

.ident = "N145P/N250P/N260P",
.matches = {
	DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
	DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
	DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
},
.callback = dmi_check_cb,

there, please? I've tested the driver successfully on my N145P.

-- 
Regards,
Richard Schütz

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-02-11 11:37 ` Richard Schütz
@ 2011-02-11 15:22   ` Greg KH
  2011-02-11 16:27     ` Richard Schütz
  0 siblings, 1 reply; 53+ messages in thread
From: Greg KH @ 2011-02-11 15:22 UTC (permalink / raw)
  To: Richard Schütz
  Cc: Matthew Garrett, Randy Dunlap, linux-kernel, platform-driver-x86

On Fri, Feb 11, 2011 at 12:37:26PM +0100, Richard Schütz wrote:
> > +static struct dmi_system_id __initdata samsung_dmi_table[] = {
> > +	{
> > +		.ident = "N128",
> > +		.matches = {
> > +			DMI_MATCH(DMI_SYS_VENDOR,
> > +					"SAMSUNG ELECTRONICS CO., LTD."),
> > +			DMI_MATCH(DMI_PRODUCT_NAME, "N128"),
> > +			DMI_MATCH(DMI_BOARD_NAME, "N128"),
> > +		},
> > +		.callback = dmi_check_cb,
> > +	},
> > +	{
> > +		.ident = "N130",
> > +		.matches = {
> > +			DMI_MATCH(DMI_SYS_VENDOR,
> > +					"SAMSUNG ELECTRONICS CO., LTD."),
> > +			DMI_MATCH(DMI_PRODUCT_NAME, "N130"),
> > +			DMI_MATCH(DMI_BOARD_NAME, "N130"),
> > +		},
> > +		.callback = dmi_check_cb,
> > +	},
> > +	{
> > +		.ident = "X125",
> > +		.matches = {
> > +			DMI_MATCH(DMI_SYS_VENDOR,
> > +					"SAMSUNG ELECTRONICS CO., LTD."),
> > +			DMI_MATCH(DMI_PRODUCT_NAME, "X125"),
> > +			DMI_MATCH(DMI_BOARD_NAME, "X125"),
> > +		},
> > +		.callback = dmi_check_cb,
> > +	},
> > +	{
> > +		.ident = "NC10",
> > +		.matches = {
> > +			DMI_MATCH(DMI_SYS_VENDOR,
> > +					"SAMSUNG ELECTRONICS CO., LTD."),
> > +			DMI_MATCH(DMI_PRODUCT_NAME, "NC10"),
> > +			DMI_MATCH(DMI_BOARD_NAME, "NC10"),
> > +		},
> > +		.callback = dmi_check_cb,
> > +	},
> > +		{
> > +		.ident = "NP-Q45",
> > +		.matches = {
> > +			DMI_MATCH(DMI_SYS_VENDOR,
> > +					"SAMSUNG ELECTRONICS CO., LTD."),
> > +			DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"),
> > +			DMI_MATCH(DMI_BOARD_NAME, "SQ45S70S"),
> > +		},
> > +		.callback = dmi_check_cb,
> > +		},
> > +	{
> > +		.ident = "X360",
> > +		.matches = {
> > +			DMI_MATCH(DMI_SYS_VENDOR,
> > +					"SAMSUNG ELECTRONICS CO., LTD."),
> > +			DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
> > +			DMI_MATCH(DMI_BOARD_NAME, "X360"),
> > +		},
> > +		.callback = dmi_check_cb,
> > +	},
> > +	{
> > +		.ident = "R518",
> > +		.matches = {
> > +			DMI_MATCH(DMI_SYS_VENDOR,
> > +					"SAMSUNG ELECTRONICS CO., LTD."),
> > +			DMI_MATCH(DMI_PRODUCT_NAME, "R518"),
> > +			DMI_MATCH(DMI_BOARD_NAME, "R518"),
> > +		},
> > +		.callback = dmi_check_cb,
> > +	},
> > +	{
> > +		.ident = "N150/N210/N220",
> > +		.matches = {
> > +			DMI_MATCH(DMI_SYS_VENDOR,
> > +					"SAMSUNG ELECTRONICS CO., LTD."),
> > +			DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
> > +			DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
> > +		},
> > +		.callback = dmi_check_cb,
> > +	},
> > +	{
> > +		.ident = "R530/R730",
> > +		.matches = {
> > +		      DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
> > +		      DMI_MATCH(DMI_PRODUCT_NAME, "R530/R730"),
> > +		      DMI_MATCH(DMI_BOARD_NAME, "R530/R730"),
> > +		},
> > +		.callback = dmi_check_cb,
> > +	},
> > +	{
> > +		.ident = "NF110/NF210/NF310",
> > +		.matches = {
> > +			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
> > +			DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"),
> > +			DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"),
> > +		},
> > +		.callback = dmi_check_cb,
> > +	},
> > +	{ },
> > +};
> > +MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
> 
> Could you add
> 
> .ident = "N145P/N250P/N260P",
> .matches = {
> 	DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
> 	DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
> 	DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
> },
> .callback = dmi_check_cb,
> 
> there, please? I've tested the driver successfully on my N145P.

Yes I can, but do you want to send it to me in a format that I can apply
so you can get the proper authorship credit?  Take a look at
Documentation/SubmittingPatches for the details.

If not, I'll be glad to do it myself, but wanted to give you the chance
first.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-02-09 22:40 [PATCH] Platform: add Samsung Laptop platform driver Greg KH
                   ` (2 preceding siblings ...)
  2011-02-11 11:37 ` Richard Schütz
@ 2011-02-11 15:45 ` Matthew Garrett
  2011-02-11 18:42   ` Greg KH
  2011-02-16 10:06 ` Nikolai Kondrashov
  4 siblings, 1 reply; 53+ messages in thread
From: Matthew Garrett @ 2011-02-11 15:45 UTC (permalink / raw)
  To: Greg KH; +Cc: Randy Dunlap, linux-kernel, platform-driver-x86

On Wed, Feb 09, 2011 at 02:40:06PM -0800, Greg KH wrote:

> +/* Structure to get data back to the calling function */
> +struct sabi_retval {
> +	u8 retval[20];
> +};

20 bytes, but only 4 of them end up being used?

> +	if (readb(sabi_iface + SABI_IFACE_COMPLETE) == 0xaa &&
> +	    readb(sabi_iface + SABI_IFACE_DATA) != 0xff) {
> +		/*
> +		 * It did!
> +		 * Save off the data into a structure so the caller use it.
> +		 * Right now we only care about the first 4 bytes,
> +		 * I suppose there are commands that need more, but I don't
> +		 * know about them.
> +		 */
> +		sretval->retval[0] = readb(sabi_iface + SABI_IFACE_DATA);
> +		sretval->retval[1] = readb(sabi_iface + SABI_IFACE_DATA + 1);
> +		sretval->retval[2] = readb(sabi_iface + SABI_IFACE_DATA + 2);
> +		sretval->retval[3] = readb(sabi_iface + SABI_IFACE_DATA + 3);
> +		goto exit;
> +	}

goto on success, continue failure? That's a pretty atypical pattern, and 
the goto's not even really needed in this case.

> +	/* Something bad happened, so report it and error out */
> +	printk(KERN_WARNING "SABI command 0x%02x failed with completion flag 0x%02x and output 0x%02x\n",
> +		command, readb(sabi_iface + SABI_IFACE_COMPLETE),
> +		readb(sabi_iface + SABI_IFACE_DATA));

Is it guaranteed that further reads will still return the failure state?

> +	/* see if the command actually succeeded */
> +	if (readb(sabi_iface + SABI_IFACE_COMPLETE) == 0xaa &&
> +	    readb(sabi_iface + SABI_IFACE_DATA) != 0xff) {
> +		/* it did! */
> +		goto exit;
> +	}

Ditto for this block.

> +static struct dmi_system_id __initdata samsung_dmi_table[] = {

This is kind of ugly. Are there any Samsung laptops where reading the 
bios area is going to cause problems?

> +	/* Get a pointer to the SABI Interface */
> +	ifaceP = (readw(sabi + sabi_config->header_offsets.data_segment) & 0x0ffff) << 4;
> +	ifaceP += readw(sabi + sabi_config->header_offsets.data_offset) & 0x0ffff;
> +	sabi_iface = ioremap(ifaceP, 16);
> +	if (!sabi_iface) {
> +		printk(KERN_ERR "Can't remap %x\n", ifaceP);

dev_err()? It'd be nice to have a prefix on the failure cases.

> +	retval = init_wireless(sdev);

No way to identify whether or not the hardware has wifi before 
registering rfkill?

-- 
Matthew Garrett | mjg59@srcf.ucam.org

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-02-11 15:22   ` Greg KH
@ 2011-02-11 16:27     ` Richard Schütz
  2011-02-25 21:01       ` Greg KH
  0 siblings, 1 reply; 53+ messages in thread
From: Richard Schütz @ 2011-02-11 16:27 UTC (permalink / raw)
  To: Greg KH; +Cc: Matthew Garrett, Randy Dunlap, linux-kernel, platform-driver-x86

Add DMI data for Samsung N145P/N250P/N260P

Signed-off-by: Richard Schütz <r.schtz@t-online.de>
---

> Yes I can, but do you want to send it to me in a format that I can apply
> so you can get the proper authorship credit?

Of course, here it is.

--- a/drivers/platform/x86/samsung-laptop.c
+++ b/drivers/platform/x86/samsung-laptop.c
@@ -592,6 +592,15 @@ static struct dmi_system_id __initdata s
  		},
  		.callback = dmi_check_cb,
  	},
+	{
+		.ident = "N145P/N250P/N260P",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
+			DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
+		},
+		.callback = dmi_check_cb,
+	},
  	{ },
  };
  MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);

-- 
Regards,
Richard Schütz

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-02-11 15:45 ` Matthew Garrett
@ 2011-02-11 18:42   ` Greg KH
  0 siblings, 0 replies; 53+ messages in thread
From: Greg KH @ 2011-02-11 18:42 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: Randy Dunlap, linux-kernel, platform-driver-x86

On Fri, Feb 11, 2011 at 03:45:08PM +0000, Matthew Garrett wrote:
> On Wed, Feb 09, 2011 at 02:40:06PM -0800, Greg KH wrote:
> 
> > +/* Structure to get data back to the calling function */
> > +struct sabi_retval {
> > +	u8 retval[20];
> > +};
> 
> 20 bytes, but only 4 of them end up being used?

Yes, for the commands we care about, we only pay attention to the first
4 bytes, but it really is 20 bytes long from what I can tell.

> > +	if (readb(sabi_iface + SABI_IFACE_COMPLETE) == 0xaa &&
> > +	    readb(sabi_iface + SABI_IFACE_DATA) != 0xff) {
> > +		/*
> > +		 * It did!
> > +		 * Save off the data into a structure so the caller use it.
> > +		 * Right now we only care about the first 4 bytes,
> > +		 * I suppose there are commands that need more, but I don't
> > +		 * know about them.
> > +		 */
> > +		sretval->retval[0] = readb(sabi_iface + SABI_IFACE_DATA);
> > +		sretval->retval[1] = readb(sabi_iface + SABI_IFACE_DATA + 1);
> > +		sretval->retval[2] = readb(sabi_iface + SABI_IFACE_DATA + 2);
> > +		sretval->retval[3] = readb(sabi_iface + SABI_IFACE_DATA + 3);
> > +		goto exit;
> > +	}
> 
> goto on success, continue failure? That's a pretty atypical pattern, and 
> the goto's not even really needed in this case.

Ah, good point.  The code was originally a port from some example code
provided by Samsung, this must have remained from that example, I'll go
fix it up.

Hm, in looking at the code, I think I did this just to make it "only
lock and unlock at one place in the function".  I'll rework it to be a
bit more "sane".


> > +	/* Something bad happened, so report it and error out */
> > +	printk(KERN_WARNING "SABI command 0x%02x failed with completion flag 0x%02x and output 0x%02x\n",
> > +		command, readb(sabi_iface + SABI_IFACE_COMPLETE),
> > +		readb(sabi_iface + SABI_IFACE_DATA));
> 
> Is it guaranteed that further reads will still return the failure state?

Nothing is guaranteed from this interface from what I can tell. :)

I really don't know, in my tests, I only had one failure, and that ended
up being my fault for sending the wrong command.

> > +	/* see if the command actually succeeded */
> > +	if (readb(sabi_iface + SABI_IFACE_COMPLETE) == 0xaa &&
> > +	    readb(sabi_iface + SABI_IFACE_DATA) != 0xff) {
> > +		/* it did! */
> > +		goto exit;
> > +	}
> 
> Ditto for this block.

Will do.

> > +static struct dmi_system_id __initdata samsung_dmi_table[] = {
> 
> This is kind of ugly. Are there any Samsung laptops where reading the 
> bios area is going to cause problems?

Yeah, I was thinking I should just accept all Samsung laptops now that
we can properly detect the type of SABI interface that the machine has.
That would reduce this table, and make users happy that they don't have
to keep adding new devices to it.  I'll make that change as well.

> > +	/* Get a pointer to the SABI Interface */
> > +	ifaceP = (readw(sabi + sabi_config->header_offsets.data_segment) & 0x0ffff) << 4;
> > +	ifaceP += readw(sabi + sabi_config->header_offsets.data_offset) & 0x0ffff;
> > +	sabi_iface = ioremap(ifaceP, 16);
> > +	if (!sabi_iface) {
> > +		printk(KERN_ERR "Can't remap %x\n", ifaceP);
> 
> dev_err()? It'd be nice to have a prefix on the failure cases.

It would, but at this point, we don't have a valid 'struct device' to
hang it off of.  I could create the platform device earlier in the
function, which would allow us to show errors a bit "prettier" if you
think that would be a good idea.

> > +	retval = init_wireless(sdev);
> 
> No way to identify whether or not the hardware has wifi before 
> registering rfkill?

I know of no way to detect this.  The driver assumes that we always have
wifi.  I actually haven't seen a Samsung laptop without it, have you?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-02-09 22:40 [PATCH] Platform: add Samsung Laptop platform driver Greg KH
                   ` (3 preceding siblings ...)
  2011-02-11 15:45 ` Matthew Garrett
@ 2011-02-16 10:06 ` Nikolai Kondrashov
  2011-02-25 21:03   ` Greg KH
  4 siblings, 1 reply; 53+ messages in thread
From: Nikolai Kondrashov @ 2011-02-16 10:06 UTC (permalink / raw)
  To: Greg KH; +Cc: Matthew Garrett, Randy Dunlap, linux-kernel, platform-driver-x86

[-- Attachment #1: Type: text/plain, Size: 503 bytes --]

Hi Greg,

On 02/10/2011 01:40 AM, Greg KH wrote:
> This adds the samsung-laptop driver to the kernel.  It now supports
> all known Samsung laptops.
Thank you for this patch :)!

I've tried it with both 2.6.37 and 2.6.32 on my NP-N210-JA02RU and it fails
the insertion with ENODEV without "force" and with "This computer does not
support SABI" with "force".

I'm ready to provide any diagnostics information you may need and test the
patches.

Please find the dmidecode output attached.

Sincerely,
Nick

[-- Attachment #2: dmi_raw.txt --]
[-- Type: text/plain, Size: 6555 bytes --]

# dmidecode 2.9
SMBIOS 2.5 present.
29 structures occupying 1153 bytes.
Table at 0x000DF010.

Handle 0x0000, DMI type 0, 24 bytes
	Header and Data:
		00 18 00 00 01 02 1E E6 03 1F 90 DA 0B 7C 00 00
		00 00 82 05 06 00 FF FF
	Strings:
		50 68 6F 65 6E 69 78 20 54 65 63 68 6E 6F 6C 6F
		67 69 65 73 20 4C 74 64 2E 00
		"Phoenix Technologies Ltd."
		30 36 4A 49 2E 4D 30 35 33 2E 32 30 31 30 30 31
		32 39 2E 4A 49 50 00
		"06JI.M053.20100129.JIP"
		30 31 2F 32 39 2F 32 30 31 30 00
		"01/29/2010"

Handle 0x0001, DMI type 1, 27 bytes
	Header and Data:
		01 1B 01 00 01 02 03 04 40 B5 E8 30 E8 1D B2 11
		80 00 E5 4E B0 0E A0 58 06 05 06
	Strings:
		53 41 4D 53 55 4E 47 20 45 4C 45 43 54 52 4F 4E
		49 43 53 20 43 4F 2E 2C 20 4C 54 44 2E 00
		"SAMSUNG ELECTRONICS CO., LTD."
		4E 31 35 30 2F 4E 32 31 30 2F 4E 32 32 30 20 20
		20 20 20 20 20 20 20 20 20 20 20 00
		"N150/N210/N220             "
		4E 6F 74 20 41 70 70 6C 69 63 61 62 6C 65 00
		"Not Applicable"
		5A 4F 31 31 39 33 48 5A 32 30 30 38 36 30 00
		"ZO1193HZ200860"
		31 32 33 34 35 36 37 38 39 30 00
		"1234567890"
		31 32 33 34 35 36 37 38 39 30 00
		"1234567890"

Handle 0x0002, DMI type 2, 10 bytes
	Header and Data:
		02 0A 02 00 01 02 03 04 05 09
	Strings:
		53 41 4D 53 55 4E 47 20 45 4C 45 43 54 52 4F 4E
		49 43 53 20 43 4F 2E 2C 20 4C 54 44 2E 00
		"SAMSUNG ELECTRONICS CO., LTD."
		4E 31 35 30 2F 4E 32 31 30 2F 4E 32 32 30 20 20
		20 20 20 20 20 20 20 20 20 20 20 00
		"N150/N210/N220             "
		4E 6F 74 20 41 70 70 6C 69 63 61 62 6C 65 00
		"Not Applicable"
		31 32 33 34 39 30 45 4E 34 30 30 30 31 35 00
		"123490EN400015"
		53 41 4D 53 55 4E 47 00
		"SAMSUNG"

Handle 0x0003, DMI type 3, 17 bytes
	Header and Data:
		03 11 03 00 01 0A 02 03 04 03 03 03 03 34 12 00
		00
	Strings:
		53 41 4D 53 55 4E 47 20 45 4C 45 43 54 52 4F 4E
		49 43 53 20 43 4F 2E 2C 20 4C 54 44 2E 00
		"SAMSUNG ELECTRONICS CO., LTD."
		4E 2F 41 20 20 20 20 20 20 20 20 20 00
		"N/A         "
		4E 6F 6E 65 20 20 20 20 20 20 20 20 00
		"None        "
		4E 6F 20 41 73 73 65 74 20 54 61 67 00
		"No Asset Tag"

Handle 0x0004, DMI type 4, 40 bytes
	Header and Data:
		04 28 04 00 01 03 01 02 CA 06 01 00 FF FB E9 BF
		03 92 00 00 E4 0C 40 06 41 15 05 00 06 00 FF FF
		00 00 00 01 01 02 04 00
	Strings:
		43 50 55 20 31 00
		"CPU 1"
		49 6E 74 65 6C 00
		"Intel"
		43 31 00
		"C1"

Handle 0x0005, DMI type 7, 19 bytes
	Header and Data:
		07 13 05 00 01 88 01 10 00 10 00 58 00 40 00 00
		02 02 02
	Strings:
		4C 31 20 43 61 63 68 65 00
		"L1 Cache"

Handle 0x0006, DMI type 7, 19 bytes
	Header and Data:
		07 13 06 00 01 89 01 00 02 00 02 58 00 08 00 00
		02 02 02
	Strings:
		4C 32 20 43 61 63 68 65 00
		"L2 Cache"

Handle 0x0007, DMI type 8, 9 bytes
	Header and Data:
		08 09 07 00 01 00 02 14 0D
	Strings:
		4A 31 41 31 00
		"J1A1"
		4B 65 79 62 6F 61 72 64 00
		"Keyboard"

Handle 0x0008, DMI type 8, 9 bytes
	Header and Data:
		08 09 08 00 01 00 02 14 0D
	Strings:
		4A 31 41 31 00
		"J1A1"
		50 53 2F 32 20 4D 6F 75 73 65 00
		"PS/2 Mouse"

Handle 0x0009, DMI type 9, 13 bytes
	Header and Data:
		09 0D 09 00 01 A5 05 02 04 00 00 06 00
	Strings:
		50 43 49 65 20 53 6C 6F 74 20 23 31 20 2D 20 4A
		37 43 31 00
		"PCIe Slot #1 - J7C1"

Handle 0x000A, DMI type 9, 13 bytes
	Header and Data:
		09 0D 0A 00 01 A5 05 02 04 00 00 06 00
	Strings:
		50 43 49 65 20 53 6C 6F 74 20 23 32 20 2D 20 4A
		33 42 31 00
		"PCIe Slot #2 - J3B1"

Handle 0x000B, DMI type 10, 6 bytes
	Header and Data:
		0A 06 0B 00 07 01
	Strings:
		48 44 2D 41 75 64 69 6F 00
		"HD-Audio"

Handle 0x000C, DMI type 11, 5 bytes
	Header and Data:
		0B 05 0C 00 02
	Strings:
		41 41 42 41 41 41 41 41 41 41 41 41 00
		"AABAAAAAAAAA"
		32 30 31 30 2F 30 33 2F 31 33 00
		"2010/03/13"

Handle 0x000D, DMI type 12, 5 bytes
	Header and Data:
		0C 05 0D 00 01
	Strings:
		4A 75 6D 70 65 72 20 73 65 74 74 69 6E 67 73 20
		63 61 6E 20 62 65 20 64 65 73 63 72 69 62 65 64
		20 68 65 72 65 2E 00
		"Jumper settings can be described here."

Handle 0x000E, DMI type 16, 15 bytes
	Header and Data:
		10 0F 0E 00 03 03 03 00 00 80 00 FE FF 04 00

Handle 0x000F, DMI type 17, 27 bytes
	Header and Data:
		11 1B 0F 00 0E 00 FF FF 40 00 40 00 00 08 0D 01
		01 02 13 80 00 9B 02 03 04 05 06
	Strings:
		4A 36 47 31 00
		"J6G1"
		44 49 4D 4D 20 30 00
		"DIMM 0"
		34 38 73 70 61 63 65 73 20 20 20 20 20 20 20 20
		20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
		20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
		00
		"48spaces                                        "
		30 31 32 33 34 35 36 37 00
		"01234567"
		30 31 32 33 34 35 36 37 00
		"01234567"
		30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35
		36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31
		32 33 34 35 00
		"012345678901234567890123456789012345"

Handle 0x0010, DMI type 19, 15 bytes
	Header and Data:
		13 0F 10 00 00 00 00 00 FF FF 1F 00 0E 00 02

Handle 0x0011, DMI type 20, 19 bytes
	Header and Data:
		14 13 11 00 00 00 00 00 FF FF 1F 00 0F 00 10 00
		FF FF FF

Handle 0x0012, DMI type 23, 13 bytes
	Header and Data:
		17 0D 12 00 3F FF FF FF FF FF FF FF FF

Handle 0x0013, DMI type 24, 5 bytes
	Header and Data:
		18 05 13 00 33

Handle 0x0014, DMI type 25, 9 bytes
	Header and Data:
		19 09 14 00 12 31 23 59 59

Handle 0x0015, DMI type 26, 20 bytes
	Header and Data:
		1A 14 15 00 01 63 00 80 00 80 00 80 00 80 00 80
		00 00 00 00
	Strings:
		56 6F 6C 74 61 67 65 20 50 72 6F 62 65 00
		"Voltage Probe"

Handle 0x0016, DMI type 27, 12 bytes
	Header and Data:
		1B 0C 16 00 17 00 63 00 00 00 00 00

Handle 0x0017, DMI type 28, 20 bytes
	Header and Data:
		1C 14 17 00 01 63 00 80 00 80 00 80 00 80 00 80
		00 00 00 00
	Strings:
		54 65 6D 70 65 72 61 74 75 72 65 20 50 72 6F 62
		65 00
		"Temperature Probe"

Handle 0x0018, DMI type 29, 20 bytes
	Header and Data:
		1D 14 18 00 01 63 00 80 00 80 00 80 00 80 00 80
		00 00 00 00
	Strings:
		45 6C 65 63 74 72 69 63 61 6C 20 43 75 72 72 65
		6E 74 20 50 72 6F 62 65 00
		"Electrical Current Probe"

Handle 0x0019, DMI type 30, 6 bytes
	Header and Data:
		1E 06 19 00 01 01
	Strings:
		49 6E 74 65 6C 00
		"Intel"

Handle 0x001A, DMI type 32, 20 bytes
	Header and Data:
		20 14 1A 00 00 00 00 00 00 00 00 00 00 00 00 00
		00 00 00 00

Handle 0x001B, DMI type 126, 4 bytes
	Header and Data:
		7E 04 1B 00

Handle 0x001C, DMI type 127, 4 bytes
	Header and Data:
		7F 04 1C 00


[-- Attachment #3: dmi_decoded.txt --]
[-- Type: text/plain, Size: 7831 bytes --]

# dmidecode 2.9
SMBIOS 2.5 present.
29 structures occupying 1153 bytes.
Table at 0x000DF010.

Handle 0x0000, DMI type 0, 24 bytes
BIOS Information
	Vendor: Phoenix Technologies Ltd.
	Version: 06JI.M053.20100129.JIP
	Release Date: 01/29/2010
	Address: 0xE61E0
	Runtime Size: 106016 bytes
	ROM Size: 2048 kB
	Characteristics:
		ISA is supported
		PCI is supported
		PNP is supported
		BIOS is upgradeable
		BIOS shadowing is allowed
		ESCD support is available
		Boot from CD is supported
		Selectable boot is supported
		BIOS ROM is socketed
		EDD is supported
		Print screen service is supported (int 5h)
		8042 keyboard services are supported (int 9h)
		Serial services are supported (int 14h)
		Printer services are supported (int 17h)
		CGA/mono video services are supported (int 10h)
		USB legacy is supported
		Smart battery is supported
		BIOS boot specification is supported
		Targeted content distribution is supported
	BIOS Revision: 6.0

Handle 0x0001, DMI type 1, 27 bytes
System Information
	Manufacturer: SAMSUNG ELECTRONICS CO., LTD.
	Product Name: N150/N210/N220             
	Version: Not Applicable
	Serial Number: ZO1193HZ200860
	UUID: 40B5E830-E81D-B211-8000-E54EB00EA058
	Wake-up Type: Power Switch
	SKU Number: 1234567890
	Family: 1234567890

Handle 0x0002, DMI type 2, 10 bytes
Base Board Information
	Manufacturer: SAMSUNG ELECTRONICS CO., LTD.
	Product Name: N150/N210/N220             
	Version: Not Applicable
	Serial Number: 123490EN400015

Handle 0x0003, DMI type 3, 17 bytes
Chassis Information
	Manufacturer: SAMSUNG ELECTRONICS CO., LTD.
	Type: Notebook
	Lock: Not Present
	Version: N/A         
	Serial Number: None        
	Asset Tag: No Asset Tag
	Boot-up State: Safe
	Power Supply State: Safe
	Thermal State: Safe
	Security Status: None
	OEM Information: 0x00001234

Handle 0x0004, DMI type 4, 40 bytes
Processor Information
	Socket Designation: CPU 1
	Type: Central Processor
	Family: Other
	Manufacturer: Intel
	ID: CA 06 01 00 FF FB E9 BF
	Version: C1
	Voltage: 1.8 V
	External Clock: Unknown
	Max Speed: 3300 MHz
	Current Speed: 1600 MHz
	Status: Populated, Enabled
	Upgrade: Socket LGA775
	L1 Cache Handle: 0x0005
	L2 Cache Handle: 0x0006
	L3 Cache Handle: Not Provided
	Serial Number: Not Specified
	Asset Tag: Not Specified
	Part Number: Not Specified
	Core Count: 1
	Core Enabled: 1
	Thread Count: 2
	Characteristics:
		64-bit capable

Handle 0x0005, DMI type 7, 19 bytes
Cache Information
	Socket Designation: L1 Cache
	Configuration: Enabled, Socketed, Level 1
	Operational Mode: Write Back
	Location: Internal
	Installed Size: 16 KB
	Maximum Size: 16 KB
	Supported SRAM Types:
		Burst
		Pipeline Burst
		Asynchronous
	Installed SRAM Type: Asynchronous
	Speed: Unknown
	Error Correction Type: Unknown
	System Type: Unknown
	Associativity: Unknown

Handle 0x0006, DMI type 7, 19 bytes
Cache Information
	Socket Designation: L2 Cache
	Configuration: Enabled, Socketed, Level 2
	Operational Mode: Write Back
	Location: Internal
	Installed Size: 512 KB
	Maximum Size: 512 KB
	Supported SRAM Types:
		Burst
		Pipeline Burst
		Asynchronous
	Installed SRAM Type: Burst
	Speed: Unknown
	Error Correction Type: Unknown
	System Type: Unknown
	Associativity: Unknown

Handle 0x0007, DMI type 8, 9 bytes
Port Connector Information
	Internal Reference Designator: J1A1
	Internal Connector Type: None
	External Reference Designator: Keyboard
	External Connector Type: Circular DIN-8 male
	Port Type: Keyboard Port

Handle 0x0008, DMI type 8, 9 bytes
Port Connector Information
	Internal Reference Designator: J1A1
	Internal Connector Type: None
	External Reference Designator: PS/2 Mouse
	External Connector Type: Circular DIN-8 male
	Port Type: Keyboard Port

Handle 0x0009, DMI type 9, 13 bytes
System Slot Information
	Designation: PCIe Slot #1 - J7C1
	Type: 32-bit PCI Express
	Current Usage: Unknown
	Length: Long
	ID: 0
	Characteristics:
		5.0 V is provided
		3.3 V is provided

Handle 0x000A, DMI type 9, 13 bytes
System Slot Information
	Designation: PCIe Slot #2 - J3B1
	Type: 32-bit PCI Express
	Current Usage: Unknown
	Length: Long
	ID: 0
	Characteristics:
		5.0 V is provided
		3.3 V is provided

Handle 0x000B, DMI type 10, 6 bytes
On Board Device Information
	Type: Sound
	Status: Disabled
	Description: HD-Audio

Handle 0x000C, DMI type 11, 5 bytes
OEM Strings
	String 1: AABAAAAAAAAA
	String 2: 2010/03/13

Handle 0x000D, DMI type 12, 5 bytes
System Configuration Options
	Option 1: Jumper settings can be described here.

Handle 0x000E, DMI type 16, 15 bytes
Physical Memory Array
	Location: System Board Or Motherboard
	Use: System Memory
	Error Correction Type: None
	Maximum Capacity: 8 GB
	Error Information Handle: Not Provided
	Number Of Devices: 4

Handle 0x000F, DMI type 17, 27 bytes
Memory Device
	Array Handle: 0x000E
	Error Information Handle: No Error
	Total Width: 64 bits
	Data Width: 64 bits
	Size: 2048 MB
	Form Factor: SODIMM
	Set: 1
	Locator: J6G1
	Bank Locator: DIMM 0
	Type: DDR2
	Type Detail: Synchronous
	Speed: 667 MHz (1.5 ns)
	Manufacturer: 48spaces                                        
	Serial Number: 01234567
	Asset Tag: 01234567
	Part Number: 012345678901234567890123456789012345

Handle 0x0010, DMI type 19, 15 bytes
Memory Array Mapped Address
	Starting Address: 0x00000000000
	Ending Address: 0x0007FFFFFFF
	Range Size: 2 GB
	Physical Array Handle: 0x000E
	Partition Width: 0

Handle 0x0011, DMI type 20, 19 bytes
Memory Device Mapped Address
	Starting Address: 0x00000000000
	Ending Address: 0x0007FFFFFFF
	Range Size: 2 GB
	Physical Device Handle: 0x000F
	Memory Array Mapped Address Handle: 0x0010
	Partition Row Position: Unknown
	Interleave Position: Unknown
	Interleaved Data Depth: Unknown

Handle 0x0012, DMI type 23, 13 bytes
System Reset
	Status: Enabled
	Watchdog Timer: Present
	Boot Option: Do Not Reboot
	Boot Option On Limit: Do Not Reboot
	Reset Count: Unknown
	Reset Limit: Unknown
	Timer Interval: Unknown
	Timeout: Unknown

Handle 0x0013, DMI type 24, 5 bytes
Hardware Security
	Power-On Password Status: Disabled
	Keyboard Password Status: Unknown
	Administrator Password Status: Disabled
	Front Panel Reset Status: Unknown

Handle 0x0014, DMI type 25, 9 bytes
	System Power Controls
	Next Scheduled Power-on: 12-31 23:59:59

Handle 0x0015, DMI type 26, 20 bytes
Voltage Probe
	Description: Voltage Probe
	Location: Processor
	Status: OK
	Maximum Value: Unknown
	Minimum Value: Unknown
	Resolution: Unknown
	Tolerance: Unknown
	Accuracy: Unknown
	OEM-specific Information: 0x00000000

Handle 0x0016, DMI type 27, 12 bytes
Cooling Device
	Temperature Probe Handle: 0x0017
	Type: Fan
	Status: OK
	OEM-specific Information: 0x00000000

Handle 0x0017, DMI type 28, 20 bytes
Temperature Probe
	Description: Temperature Probe
	Location: Processor
	Status: OK
	Maximum Value: Unknown
	Minimum Value Unknown
	Resolution: Unknown
	Tolerance: Unknown
	Accuracy: Unknown
	OEM-specific Information: 0x00000000

Handle 0x0018, DMI type 29, 20 bytes
Electrical Current Probe
	Description: Electrical Current Probe
	Location: Processor
	Status: OK
	Maximum Value: Unknown
	Minimum Value: Unknown
	Resolution: Unknown
	Tolerance: Unknown
	Accuracy: Unknown
	OEM-specific Information: 0x00000000

Handle 0x0019, DMI type 30, 6 bytes
Out-of-band Remote Access
	Manufacturer Name: Intel
	Inbound Connection: Enabled
	Outbound Connection: Disabled

Handle 0x001A, DMI type 32, 20 bytes
System Boot Information
	Status: No errors detected

Handle 0x001B, DMI type 126, 4 bytes
Inactive

Handle 0x001C, DMI type 127, 4 bytes
End Of Table


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-02-11 16:27     ` Richard Schütz
@ 2011-02-25 21:01       ` Greg KH
  0 siblings, 0 replies; 53+ messages in thread
From: Greg KH @ 2011-02-25 21:01 UTC (permalink / raw)
  To: Richard Schütz
  Cc: Matthew Garrett, Randy Dunlap, linux-kernel, platform-driver-x86

On Fri, Feb 11, 2011 at 05:27:19PM +0100, Richard Schütz wrote:
> Add DMI data for Samsung N145P/N250P/N260P
> 
> Signed-off-by: Richard Schütz <r.schtz@t-online.de>
> ---
> 
> >Yes I can, but do you want to send it to me in a format that I can apply
> >so you can get the proper authorship credit?
> 
> Of course, here it is.

Thanks, applied.

greg k-h

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-02-16 10:06 ` Nikolai Kondrashov
@ 2011-02-25 21:03   ` Greg KH
  2011-02-25 21:49     ` Nikolai Kondrashov
  0 siblings, 1 reply; 53+ messages in thread
From: Greg KH @ 2011-02-25 21:03 UTC (permalink / raw)
  To: Nikolai Kondrashov
  Cc: Matthew Garrett, Randy Dunlap, linux-kernel, platform-driver-x86

On Wed, Feb 16, 2011 at 01:06:00PM +0300, Nikolai Kondrashov wrote:
> Hi Greg,
> 
> On 02/10/2011 01:40 AM, Greg KH wrote:
> > This adds the samsung-laptop driver to the kernel.  It now supports
> > all known Samsung laptops.
> Thank you for this patch :)!
> 
> I've tried it with both 2.6.37 and 2.6.32 on my NP-N210-JA02RU and it fails
> the insertion with ENODEV without "force" and with "This computer does not
> support SABI" with "force".
> 
> I'm ready to provide any diagnostics information you may need and test the
> patches.
> 
> Please find the dmidecode output attached.

This should work, as we support the N150/N210/N220 versions.

Can you provide the output of:
	grep . /sys/class/dmi/id/*

so I can verify this?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-02-25 21:03   ` Greg KH
@ 2011-02-25 21:49     ` Nikolai Kondrashov
  2011-02-25 22:50       ` Greg KH
  0 siblings, 1 reply; 53+ messages in thread
From: Nikolai Kondrashov @ 2011-02-25 21:49 UTC (permalink / raw)
  To: Greg KH; +Cc: Matthew Garrett, Randy Dunlap, linux-kernel, platform-driver-x86

[-- Attachment #1: Type: text/plain, Size: 358 bytes --]

On 02/26/2011 12:03 AM, Greg KH wrote:
> This should work, as we support the N150/N210/N220 versions.
>
> Can you provide the output of:
> 	grep ./sys/class/dmi/id/*
>
> so I can verify this?
Sure. Please find it attached. It is taken on a stock Debian kernel, without
your patch.

Could I have configured the kernel incorrectly?

Thanks :)

Sincerely,
Nick

[-- Attachment #2: dmi_id_grep.txt --]
[-- Type: text/plain, Size: 1467 bytes --]

/sys/class/dmi/id/bios_date:01/29/2010
/sys/class/dmi/id/bios_vendor:Phoenix Technologies Ltd.
/sys/class/dmi/id/bios_version:06JI.M053.20100129.JIP
/sys/class/dmi/id/board_asset_tag:SAMSUNG
/sys/class/dmi/id/board_name:N150/N210/N220             
/sys/class/dmi/id/board_serial:123490EN400015
/sys/class/dmi/id/board_vendor:SAMSUNG ELECTRONICS CO., LTD.
/sys/class/dmi/id/board_version:Not Applicable
/sys/class/dmi/id/chassis_asset_tag:No Asset Tag
/sys/class/dmi/id/chassis_serial:None        
/sys/class/dmi/id/chassis_type:10
/sys/class/dmi/id/chassis_vendor:SAMSUNG ELECTRONICS CO., LTD.
/sys/class/dmi/id/chassis_version:N/A         
/sys/class/dmi/id/modalias:dmi:bvnPhoenixTechnologiesLtd.:bvr06JI.M053.20100129.JIP:bd01/29/2010:svnSAMSUNGELECTRONICSCO.,LTD.:pnN150/N210/N220:pvrNotApplicable:rvnSAMSUNGELECTRONICSCO.,LTD.:rnN150/N210/N220:rvrNotApplicable:cvnSAMSUNGELECTRONICSCO.,LTD.:ct10:cvrN/A:
/sys/class/dmi/id/product_name:N150/N210/N220             
/sys/class/dmi/id/product_serial:ZO1193HZ200860
/sys/class/dmi/id/product_uuid:40B5E830-E81D-B211-8000-E54EB00EA058
/sys/class/dmi/id/product_version:Not Applicable
/sys/class/dmi/id/sys_vendor:SAMSUNG ELECTRONICS CO., LTD.
/sys/class/dmi/id/uevent:MODALIAS=dmi:bvnPhoenixTechnologiesLtd.:bvr06JI.M053.20100129.JIP:bd01/29/2010:svnSAMSUNGELECTRONICSCO.,LTD.:pnN150/N210/N220:pvrNotApplicable:rvnSAMSUNGELECTRONICSCO.,LTD.:rnN150/N210/N220:rvrNotApplicable:cvnSAMSUNGELECTRONICSCO.,LTD.:ct10:cvrN/A:

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-02-25 21:49     ` Nikolai Kondrashov
@ 2011-02-25 22:50       ` Greg KH
  2011-03-10  7:00         ` Nikolai Kondrashov
  0 siblings, 1 reply; 53+ messages in thread
From: Greg KH @ 2011-02-25 22:50 UTC (permalink / raw)
  To: Nikolai Kondrashov
  Cc: Matthew Garrett, Randy Dunlap, linux-kernel, platform-driver-x86

On Sat, Feb 26, 2011 at 12:49:17AM +0300, Nikolai Kondrashov wrote:
> On 02/26/2011 12:03 AM, Greg KH wrote:
> >This should work, as we support the N150/N210/N220 versions.
> >
> >Can you provide the output of:
> >	grep ./sys/class/dmi/id/*
> >
> >so I can verify this?
> Sure. Please find it attached. It is taken on a stock Debian kernel, without
> your patch.
> 
> Could I have configured the kernel incorrectly?

Maybe, that's odd.

Care to try the version of the patch below to see if that works better
for you or not?

thanks,

greg k-h


--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-samsung-laptop
@@ -0,0 +1,19 @@
+What:		/sys/devices/platform/samsung/performance_level
+Date:		January 1, 2010
+KernelVersion:	2.6.33
+Contact:	Greg Kroah-Hartman <gregkh@suse.de>
+Description:	Some Samsung laptops have different "performance levels"
+		that are can be modified by a function key, and by this
+		sysfs file.  These values don't always make a whole lot
+		of sense, but some users like to modify them to keep
+		their fans quiet at all costs.  Reading from this file
+		will show the current performance level.  Writing to the
+		file can change this value.
+			Valid options:
+				"silent"
+				"normal"
+				"overclock"
+		Note that not all laptops support all of these options.
+		Specifically, not all support the "overclock" option,
+		and it's still unknown if this value even changes
+		anything, other than making the user feel a bit better.
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index a59af5b..5624267 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -654,4 +654,17 @@ config XO1_RFKILL
 	  Support for enabling/disabling the WLAN interface on the OLPC XO-1
 	  laptop.
 
+config SAMSUNG_LAPTOP
+	tristate "Samsung Laptop driver"
+	depends on RFKILL && BACKLIGHT_CLASS_DEVICE && X86
+	---help---
+	  This module implements a driver for a wide range of different
+	  Samsung laptops.  It offers control over the different
+	  function keys, wireless LED, LCD backlight level, and
+	  sometimes provides a "performance_control" sysfs file to allow
+	  the performance level of the laptop to be changed.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called samsung-laptop.
+
 endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 4ec4ff8..ad2fb97 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -34,3 +34,4 @@ obj-$(CONFIG_INTEL_IPS)		+= intel_ips.o
 obj-$(CONFIG_GPIO_INTEL_PMIC)	+= intel_pmic_gpio.o
 obj-$(CONFIG_XO1_RFKILL)	+= xo1-rfkill.o
 obj-$(CONFIG_IBM_RTL)		+= ibm_rtl.o
+obj-$(CONFIG_SAMSUNG_LAPTOP)	+= samsung-laptop.o
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c
new file mode 100644
index 0000000..a8e82b8
--- /dev/null
+++ b/drivers/platform/x86/samsung-laptop.c
@@ -0,0 +1,805 @@
+/*
+ * Samsung Laptop driver
+ *
+ * Copyright (C) 2009,2011 Greg Kroah-Hartman (gregkh@suse.de)
+ * Copyright (C) 2009,2011 Novell 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.
+ *
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+#include <linux/dmi.h>
+#include <linux/platform_device.h>
+#include <linux/rfkill.h>
+
+/*
+ * This driver is needed because a number of Samsung laptops do not hook
+ * their control settings through ACPI.  So we have to poke around in the
+ * BIOS to do things like brightness values, and "special" key controls.
+ */
+
+/*
+ * We have 0 - 8 as valid brightness levels.  The specs say that level 0 should
+ * be reserved by the BIOS (which really doesn't make much sense), we tell
+ * userspace that the value is 0 - 7 and then just tell the hardware 1 - 8
+ */
+#define MAX_BRIGHT	0x07
+
+
+#define SABI_IFACE_MAIN			0x00
+#define SABI_IFACE_SUB			0x02
+#define SABI_IFACE_COMPLETE		0x04
+#define SABI_IFACE_DATA			0x05
+
+/* Structure to get data back to the calling function */
+struct sabi_retval {
+	u8 retval[20];
+};
+
+struct sabi_header_offsets {
+	u8 port;
+	u8 re_mem;
+	u8 iface_func;
+	u8 en_mem;
+	u8 data_offset;
+	u8 data_segment;
+};
+
+struct sabi_commands {
+	/*
+	 * Brightness is 0 - 8, as described above.
+	 * Value 0 is for the BIOS to use
+	 */
+	u8 get_brightness;
+	u8 set_brightness;
+
+	/*
+	 * first byte:
+	 * 0x00 - wireless is off
+	 * 0x01 - wireless is on
+	 * second byte:
+	 * 0x02 - 3G is off
+	 * 0x03 - 3G is on
+	 * TODO, verify 3G is correct, that doesn't seem right...
+	 */
+	u8 get_wireless_button;
+	u8 set_wireless_button;
+
+	/* 0 is off, 1 is on */
+	u8 get_backlight;
+	u8 set_backlight;
+
+	/*
+	 * 0x80 or 0x00 - no action
+	 * 0x81 - recovery key pressed
+	 */
+	u8 get_recovery_mode;
+	u8 set_recovery_mode;
+
+	/*
+	 * on seclinux: 0 is low, 1 is high,
+	 * on swsmi: 0 is normal, 1 is silent, 2 is turbo
+	 */
+	u8 get_performance_level;
+	u8 set_performance_level;
+
+	/*
+	 * Tell the BIOS that Linux is running on this machine.
+	 * 81 is on, 80 is off
+	 */
+	u8 set_linux;
+};
+
+struct sabi_performance_level {
+	const char *name;
+	u8 value;
+};
+
+struct sabi_config {
+	const char *test_string;
+	u16 main_function;
+	struct sabi_header_offsets header_offsets;
+	struct sabi_commands commands;
+	struct sabi_performance_level performance_levels[4];
+};
+
+static struct sabi_config sabi_configs[] = {
+	{
+		.test_string = "SECLINUX",
+
+		.main_function = 0x4c49,
+
+		.header_offsets = {
+			.port = 0x00,
+			.re_mem = 0x02,
+			.iface_func = 0x03,
+			.en_mem = 0x04,
+			.data_offset = 0x05,
+			.data_segment = 0x07,
+		},
+
+		.commands = {
+			.get_brightness = 0x00,
+			.set_brightness = 0x01,
+
+			.get_wireless_button = 0x02,
+			.set_wireless_button = 0x03,
+
+			.get_backlight = 0x04,
+			.set_backlight = 0x05,
+
+			.get_recovery_mode = 0x06,
+			.set_recovery_mode = 0x07,
+
+			.get_performance_level = 0x08,
+			.set_performance_level = 0x09,
+
+			.set_linux = 0x0a,
+		},
+
+		.performance_levels = {
+			{
+				.name = "silent",
+				.value = 0,
+			},
+			{
+				.name = "normal",
+				.value = 1,
+			},
+			{ },
+		},
+	},
+	{
+		.test_string = "SwSmi@",
+
+		.main_function = 0x5843,
+
+		.header_offsets = {
+			.port = 0x00,
+			.re_mem = 0x04,
+			.iface_func = 0x02,
+			.en_mem = 0x03,
+			.data_offset = 0x05,
+			.data_segment = 0x07,
+		},
+
+		.commands = {
+			.get_brightness = 0x10,
+			.set_brightness = 0x11,
+
+			.get_wireless_button = 0x12,
+			.set_wireless_button = 0x13,
+
+			.get_backlight = 0x2d,
+			.set_backlight = 0x2e,
+
+			.get_recovery_mode = 0xff,
+			.set_recovery_mode = 0xff,
+
+			.get_performance_level = 0x31,
+			.set_performance_level = 0x32,
+
+			.set_linux = 0xff,
+		},
+
+		.performance_levels = {
+			{
+				.name = "normal",
+				.value = 0,
+			},
+			{
+				.name = "silent",
+				.value = 1,
+			},
+			{
+				.name = "overclock",
+				.value = 2,
+			},
+			{ },
+		},
+	},
+	{ },
+};
+
+static struct sabi_config *sabi_config;
+
+static void __iomem *sabi;
+static void __iomem *sabi_iface;
+static void __iomem *f0000_segment;
+static struct backlight_device *backlight_device;
+static struct mutex sabi_mutex;
+static struct platform_device *sdev;
+static struct rfkill *rfk;
+
+static int force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force,
+		"Disable the DMI check and forces the driver to be loaded");
+
+static int debug;
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+static int sabi_get_command(u8 command, struct sabi_retval *sretval)
+{
+	int retval = 0;
+	u16 port = readw(sabi + sabi_config->header_offsets.port);
+	u8 complete, iface_data;
+
+	mutex_lock(&sabi_mutex);
+
+	/* enable memory to be able to write to it */
+	outb(readb(sabi + sabi_config->header_offsets.en_mem), port);
+
+	/* write out the command */
+	writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN);
+	writew(command, sabi_iface + SABI_IFACE_SUB);
+	writeb(0, sabi_iface + SABI_IFACE_COMPLETE);
+	outb(readb(sabi + sabi_config->header_offsets.iface_func), port);
+
+	/* write protect memory to make it safe */
+	outb(readb(sabi + sabi_config->header_offsets.re_mem), port);
+
+	/* see if the command actually succeeded */
+	complete = readb(sabi_iface + SABI_IFACE_COMPLETE);
+	iface_data = readb(sabi_iface + SABI_IFACE_DATA);
+	if (complete != 0xaa || iface_data == 0xff) {
+		pr_warn("SABI get command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n",
+		        command, complete, iface_data);
+		retval = -EINVAL;
+		goto exit;
+	}
+	/*
+	 * Save off the data into a structure so the caller use it.
+	 * Right now we only want the first 4 bytes,
+	 * There are commands that need more, but not for the ones we
+	 * currently care about.
+	 */
+	sretval->retval[0] = readb(sabi_iface + SABI_IFACE_DATA);
+	sretval->retval[1] = readb(sabi_iface + SABI_IFACE_DATA + 1);
+	sretval->retval[2] = readb(sabi_iface + SABI_IFACE_DATA + 2);
+	sretval->retval[3] = readb(sabi_iface + SABI_IFACE_DATA + 3);
+
+exit:
+	mutex_unlock(&sabi_mutex);
+	return retval;
+
+}
+
+static int sabi_set_command(u8 command, u8 data)
+{
+	int retval = 0;
+	u16 port = readw(sabi + sabi_config->header_offsets.port);
+	u8 complete, iface_data;
+
+	mutex_lock(&sabi_mutex);
+
+	/* enable memory to be able to write to it */
+	outb(readb(sabi + sabi_config->header_offsets.en_mem), port);
+
+	/* write out the command */
+	writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN);
+	writew(command, sabi_iface + SABI_IFACE_SUB);
+	writeb(0, sabi_iface + SABI_IFACE_COMPLETE);
+	writeb(data, sabi_iface + SABI_IFACE_DATA);
+	outb(readb(sabi + sabi_config->header_offsets.iface_func), port);
+
+	/* write protect memory to make it safe */
+	outb(readb(sabi + sabi_config->header_offsets.re_mem), port);
+
+	/* see if the command actually succeeded */
+	complete = readb(sabi_iface + SABI_IFACE_COMPLETE);
+	iface_data = readb(sabi_iface + SABI_IFACE_DATA);
+	if (complete != 0xaa || iface_data == 0xff) {
+		pr_warn("SABI set command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n",
+		       command, complete, iface_data);
+		retval = -EINVAL;
+	}
+
+	mutex_unlock(&sabi_mutex);
+	return retval;
+}
+
+static void test_backlight(void)
+{
+	struct sabi_retval sretval;
+
+	sabi_get_command(sabi_config->commands.get_backlight, &sretval);
+	printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
+
+	sabi_set_command(sabi_config->commands.set_backlight, 0);
+	printk(KERN_DEBUG "backlight should be off\n");
+
+	sabi_get_command(sabi_config->commands.get_backlight, &sretval);
+	printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
+
+	msleep(1000);
+
+	sabi_set_command(sabi_config->commands.set_backlight, 1);
+	printk(KERN_DEBUG "backlight should be on\n");
+
+	sabi_get_command(sabi_config->commands.get_backlight, &sretval);
+	printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
+}
+
+static void test_wireless(void)
+{
+	struct sabi_retval sretval;
+
+	sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
+	printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
+
+	sabi_set_command(sabi_config->commands.set_wireless_button, 0);
+	printk(KERN_DEBUG "wireless led should be off\n");
+
+	sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
+	printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
+
+	msleep(1000);
+
+	sabi_set_command(sabi_config->commands.set_wireless_button, 1);
+	printk(KERN_DEBUG "wireless led should be on\n");
+
+	sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
+	printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
+}
+
+static u8 read_brightness(void)
+{
+	struct sabi_retval sretval;
+	int user_brightness = 0;
+	int retval;
+
+	retval = sabi_get_command(sabi_config->commands.get_brightness,
+				  &sretval);
+	if (!retval)
+		user_brightness = sretval.retval[0];
+		if (user_brightness != 0)
+			--user_brightness;
+	return user_brightness;
+}
+
+static void set_brightness(u8 user_brightness)
+{
+	sabi_set_command(sabi_config->commands.set_brightness,
+			 user_brightness + 1);
+}
+
+static int get_brightness(struct backlight_device *bd)
+{
+	return (int)read_brightness();
+}
+
+static int update_status(struct backlight_device *bd)
+{
+	set_brightness(bd->props.brightness);
+
+	if (bd->props.power == FB_BLANK_UNBLANK)
+		sabi_set_command(sabi_config->commands.set_backlight, 1);
+	else
+		sabi_set_command(sabi_config->commands.set_backlight, 0);
+	return 0;
+}
+
+static const struct backlight_ops backlight_ops = {
+	.get_brightness	= get_brightness,
+	.update_status	= update_status,
+};
+
+static int rfkill_set(void *data, bool blocked)
+{
+	/* Do something with blocked...*/
+	/*
+	 * blocked == false is on
+	 * blocked == true is off
+	 */
+	if (blocked)
+		sabi_set_command(sabi_config->commands.set_wireless_button, 0);
+	else
+		sabi_set_command(sabi_config->commands.set_wireless_button, 1);
+
+	return 0;
+}
+
+static struct rfkill_ops rfkill_ops = {
+	.set_block = rfkill_set,
+};
+
+static int init_wireless(struct platform_device *sdev)
+{
+	int retval;
+
+	rfk = rfkill_alloc("samsung-wifi", &sdev->dev, RFKILL_TYPE_WLAN,
+			   &rfkill_ops, NULL);
+	if (!rfk)
+		return -ENOMEM;
+
+	retval = rfkill_register(rfk);
+	if (retval) {
+		rfkill_destroy(rfk);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void destroy_wireless(void)
+{
+	rfkill_unregister(rfk);
+	rfkill_destroy(rfk);
+}
+
+static ssize_t get_performance_level(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct sabi_retval sretval;
+	int retval;
+	int i;
+
+	/* Read the state */
+	retval = sabi_get_command(sabi_config->commands.get_performance_level,
+				  &sretval);
+	if (retval)
+		return retval;
+
+	/* The logic is backwards, yeah, lots of fun... */
+	for (i = 0; sabi_config->performance_levels[i].name; ++i) {
+		if (sretval.retval[0] == sabi_config->performance_levels[i].value)
+			return sprintf(buf, "%s\n", sabi_config->performance_levels[i].name);
+	}
+	return sprintf(buf, "%s\n", "unknown");
+}
+
+static ssize_t set_performance_level(struct device *dev,
+				struct device_attribute *attr, const char *buf,
+				size_t count)
+{
+	if (count >= 1) {
+		int i;
+		for (i = 0; sabi_config->performance_levels[i].name; ++i) {
+			struct sabi_performance_level *level =
+				&sabi_config->performance_levels[i];
+			if (!strncasecmp(level->name, buf, strlen(level->name))) {
+				sabi_set_command(sabi_config->commands.set_performance_level,
+						 level->value);
+				break;
+			}
+		}
+		if (!sabi_config->performance_levels[i].name)
+			return -EINVAL;
+	}
+	return count;
+}
+static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO,
+		   get_performance_level, set_performance_level);
+
+
+static int __init dmi_check_cb(const struct dmi_system_id *id)
+{
+	pr_info("found laptop model '%s'\n",
+		id->ident);
+	return 0;
+}
+
+static struct dmi_system_id __initdata samsung_dmi_table[] = {
+	{
+		.ident = "N128",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N128"),
+			DMI_MATCH(DMI_BOARD_NAME, "N128"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "N130",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N130"),
+			DMI_MATCH(DMI_BOARD_NAME, "N130"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "X125",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X125"),
+			DMI_MATCH(DMI_BOARD_NAME, "X125"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "X120/X170",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X120/X170"),
+			DMI_MATCH(DMI_BOARD_NAME, "X120/X170"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "NC10",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "NC10"),
+			DMI_MATCH(DMI_BOARD_NAME, "NC10"),
+		},
+		.callback = dmi_check_cb,
+	},
+		{
+		.ident = "NP-Q45",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"),
+			DMI_MATCH(DMI_BOARD_NAME, "SQ45S70S"),
+		},
+		.callback = dmi_check_cb,
+		},
+	{
+		.ident = "X360",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
+			DMI_MATCH(DMI_BOARD_NAME, "X360"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "R518",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "R518"),
+			DMI_MATCH(DMI_BOARD_NAME, "R518"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "R519/R719",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "R519/R719"),
+			DMI_MATCH(DMI_BOARD_NAME, "R519/R719"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "N150/N210/N220",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
+			DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "R530/R730",
+		.matches = {
+		      DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+		      DMI_MATCH(DMI_PRODUCT_NAME, "R530/R730"),
+		      DMI_MATCH(DMI_BOARD_NAME, "R530/R730"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "NF110/NF210/NF310",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"),
+			DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "N145P/N250P/N260P",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
+			DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "R70/R71",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "R70/R71"),
+			DMI_MATCH(DMI_BOARD_NAME, "R70/R71"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
+
+static int find_signature(void __iomem *memcheck, const char *testStr)
+{
+	int i = 0;
+	int loca;
+
+	for (loca = 0; loca < 0xffff; loca++) {
+		char temp = readb(memcheck + loca);
+
+		if (temp == testStr[i]) {
+			if (i == strlen(testStr)-1)
+				break;
+			++i;
+		} else {
+			i = 0;
+		}
+	}
+	return loca;
+}
+
+static int __init samsung_init(void)
+{
+	struct backlight_properties props;
+	struct sabi_retval sretval;
+	unsigned int ifaceP;
+	int i;
+	int loca;
+	int retval;
+
+	mutex_init(&sabi_mutex);
+
+	if (!force && !dmi_check_system(samsung_dmi_table))
+		return -ENODEV;
+
+	f0000_segment = ioremap(0xf0000, 0xffff);
+	if (!f0000_segment) {
+		pr_err("Can't map the segment at 0xf0000\n");
+		return -EINVAL;
+	}
+
+	/* Try to find one of the signatures in memory to find the header */
+	for (i = 0; sabi_configs[i].test_string != 0; ++i) {
+		sabi_config = &sabi_configs[i];
+		loca = find_signature(f0000_segment, sabi_config->test_string);
+		if (loca != 0xffff)
+			break;
+	}
+
+	if (loca == 0xffff) {
+		pr_err("This computer does not support SABI\n");
+		goto error_no_signature;
+	}
+
+	/* point to the SMI port Number */
+	loca += 1;
+	sabi = (f0000_segment + loca);
+
+	if (debug) {
+		printk(KERN_DEBUG "This computer supports SABI==%x\n",
+			loca + 0xf0000 - 6);
+		printk(KERN_DEBUG "SABI header:\n");
+		printk(KERN_DEBUG " SMI Port Number = 0x%04x\n",
+			readw(sabi + sabi_config->header_offsets.port));
+		printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n",
+			readb(sabi + sabi_config->header_offsets.iface_func));
+		printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n",
+			readb(sabi + sabi_config->header_offsets.en_mem));
+		printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n",
+			readb(sabi + sabi_config->header_offsets.re_mem));
+		printk(KERN_DEBUG " SABI data offset = 0x%04x\n",
+			readw(sabi + sabi_config->header_offsets.data_offset));
+		printk(KERN_DEBUG " SABI data segment = 0x%04x\n",
+			readw(sabi + sabi_config->header_offsets.data_segment));
+	}
+
+	/* Get a pointer to the SABI Interface */
+	ifaceP = (readw(sabi + sabi_config->header_offsets.data_segment) & 0x0ffff) << 4;
+	ifaceP += readw(sabi + sabi_config->header_offsets.data_offset) & 0x0ffff;
+	sabi_iface = ioremap(ifaceP, 16);
+	if (!sabi_iface) {
+		pr_err("Can't remap %x\n", ifaceP);
+		goto exit;
+	}
+	if (debug) {
+		printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP);
+		printk(KERN_DEBUG "sabi_iface = %p\n", sabi_iface);
+
+		test_backlight();
+		test_wireless();
+
+		retval = sabi_get_command(sabi_config->commands.get_brightness,
+					  &sretval);
+		printk(KERN_DEBUG "brightness = 0x%02x\n", sretval.retval[0]);
+	}
+
+	/* Turn on "Linux" mode in the BIOS */
+	if (sabi_config->commands.set_linux != 0xff) {
+		retval = sabi_set_command(sabi_config->commands.set_linux,
+					  0x81);
+		if (retval) {
+			pr_warn("Linux mode was not set!\n");
+			goto error_no_platform;
+		}
+	}
+
+	/* knock up a platform device to hang stuff off of */
+	sdev = platform_device_register_simple("samsung", -1, NULL, 0);
+	if (IS_ERR(sdev))
+		goto error_no_platform;
+
+	/* create a backlight device to talk to this one */
+	memset(&props, 0, sizeof(struct backlight_properties));
+	props.max_brightness = MAX_BRIGHT;
+	backlight_device = backlight_device_register("samsung", &sdev->dev,
+						     NULL, &backlight_ops,
+						     &props);
+	if (IS_ERR(backlight_device))
+		goto error_no_backlight;
+
+	backlight_device->props.brightness = read_brightness();
+	backlight_device->props.power = FB_BLANK_UNBLANK;
+	backlight_update_status(backlight_device);
+
+	retval = init_wireless(sdev);
+	if (retval)
+		goto error_no_rfk;
+
+	retval = device_create_file(&sdev->dev, &dev_attr_performance_level);
+	if (retval)
+		goto error_file_create;
+
+exit:
+	return 0;
+
+error_file_create:
+	destroy_wireless();
+
+error_no_rfk:
+	backlight_device_unregister(backlight_device);
+
+error_no_backlight:
+	platform_device_unregister(sdev);
+
+error_no_platform:
+	iounmap(sabi_iface);
+
+error_no_signature:
+	iounmap(f0000_segment);
+	return -EINVAL;
+}
+
+static void __exit samsung_exit(void)
+{
+	/* Turn off "Linux" mode in the BIOS */
+	if (sabi_config->commands.set_linux != 0xff)
+		sabi_set_command(sabi_config->commands.set_linux, 0x80);
+
+	device_remove_file(&sdev->dev, &dev_attr_performance_level);
+	backlight_device_unregister(backlight_device);
+	destroy_wireless();
+	iounmap(sabi_iface);
+	iounmap(f0000_segment);
+	platform_device_unregister(sdev);
+}
+
+module_init(samsung_init);
+module_exit(samsung_exit);
+
+MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>");
+MODULE_DESCRIPTION("Samsung Backlight driver");
+MODULE_LICENSE("GPL");

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-02-25 22:50       ` Greg KH
@ 2011-03-10  7:00         ` Nikolai Kondrashov
  2011-03-10 17:01           ` Greg KH
  0 siblings, 1 reply; 53+ messages in thread
From: Nikolai Kondrashov @ 2011-03-10  7:00 UTC (permalink / raw)
  To: Greg KH; +Cc: Matthew Garrett, Randy Dunlap, linux-kernel, platform-driver-x86

Hi Greg,

On 02/26/2011 12:50 AM, Greg KH wrote:
> On Sat, Feb 26, 2011 at 12:49:17AM +0300, Nikolai Kondrashov wrote:
>> On 02/26/2011 12:03 AM, Greg KH wrote:
>>> This should work, as we support the N150/N210/N220 versions.
>>>
>>> Can you provide the output of:
>>> 	grep ./sys/class/dmi/id/*
>>>
>>> so I can verify this?
>> Sure. Please find it attached. It is taken on a stock Debian kernel, without
>> your patch.
>>
>> Could I have configured the kernel incorrectly?
>
> Maybe, that's odd.
>
> Care to try the version of the patch below to see if that works better
> for you or not?
Thank you. The result is the same: ENODEV without "force" and "This computer
doesn't support SABI" and EINVAL with "force".

Sorry for the delay - I'm in the process of chaning my job as well as the
country of living now.

Sincerely,
Nick

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-10  7:00         ` Nikolai Kondrashov
@ 2011-03-10 17:01           ` Greg KH
  2011-03-10 17:13             ` Nikolai Kondrashov
  0 siblings, 1 reply; 53+ messages in thread
From: Greg KH @ 2011-03-10 17:01 UTC (permalink / raw)
  To: Nikolai Kondrashov
  Cc: Matthew Garrett, Randy Dunlap, linux-kernel, platform-driver-x86

On Thu, Mar 10, 2011 at 09:00:36AM +0200, Nikolai Kondrashov wrote:
> Hi Greg,
> 
> On 02/26/2011 12:50 AM, Greg KH wrote:
> >On Sat, Feb 26, 2011 at 12:49:17AM +0300, Nikolai Kondrashov wrote:
> >>On 02/26/2011 12:03 AM, Greg KH wrote:
> >>>This should work, as we support the N150/N210/N220 versions.
> >>>
> >>>Can you provide the output of:
> >>>	grep ./sys/class/dmi/id/*
> >>>
> >>>so I can verify this?
> >>Sure. Please find it attached. It is taken on a stock Debian kernel, without
> >>your patch.
> >>
> >>Could I have configured the kernel incorrectly?
> >
> >Maybe, that's odd.
> >
> >Care to try the version of the patch below to see if that works better
> >for you or not?
> Thank you. The result is the same: ENODEV without "force" and "This computer
> doesn't support SABI" and EINVAL with "force".

Ok, then I'm afraid that this driver will not support your laptop,
sorry.

greg k-h

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-10 17:01           ` Greg KH
@ 2011-03-10 17:13             ` Nikolai Kondrashov
  2011-03-10 17:19               ` Greg KH
  0 siblings, 1 reply; 53+ messages in thread
From: Nikolai Kondrashov @ 2011-03-10 17:13 UTC (permalink / raw)
  To: Greg KH; +Cc: Matthew Garrett, Randy Dunlap, linux-kernel, platform-driver-x86

Hi Greg,

On Thu, Mar 10, 2011 at 7:01 PM, Greg KH <greg@kroah.com> wrote:
> Ok, then I'm afraid that this driver will not support your laptop,
> sorry.
Oh, heck! I forgot I've upgraded my netbook to n230 (which is not
supported as I see now) and left n210 to my wife.
I'll test it on n210 and then report back to you.

Sorry for the noise.

BTW, I'm ready to test n230 support, if you implement it.

Sincerely,
Nick

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-10 17:13             ` Nikolai Kondrashov
@ 2011-03-10 17:19               ` Greg KH
  2011-03-10 17:28                 ` Nikolai Kondrashov
  0 siblings, 1 reply; 53+ messages in thread
From: Greg KH @ 2011-03-10 17:19 UTC (permalink / raw)
  To: Nikolai Kondrashov
  Cc: Matthew Garrett, Randy Dunlap, linux-kernel, platform-driver-x86

On Thu, Mar 10, 2011 at 07:13:14PM +0200, Nikolai Kondrashov wrote:
> Hi Greg,
> 
> On Thu, Mar 10, 2011 at 7:01 PM, Greg KH <greg@kroah.com> wrote:
> > Ok, then I'm afraid that this driver will not support your laptop,
> > sorry.
> Oh, heck! I forgot I've upgraded my netbook to n230 (which is not
> supported as I see now) and left n210 to my wife.
> I'll test it on n210 and then report back to you.
> 
> Sorry for the noise.
> 
> BTW, I'm ready to test n230 support, if you implement it.

Can you provide me the output of:
	grep . /sys/class/dmi/id/*
so I can try to add support for this machine to the driver?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-10 17:19               ` Greg KH
@ 2011-03-10 17:28                 ` Nikolai Kondrashov
  2011-03-10 18:09                   ` Greg KH
  0 siblings, 1 reply; 53+ messages in thread
From: Nikolai Kondrashov @ 2011-03-10 17:28 UTC (permalink / raw)
  To: Greg KH; +Cc: Matthew Garrett, Randy Dunlap, linux-kernel, platform-driver-x86

[-- Attachment #1: Type: text/plain, Size: 202 bytes --]

On 03/10/2011 07:19 PM, Greg KH wrote:
> Can you provide me the output of:
> 	grep . /sys/class/dmi/id/*
> so I can try to add support for this machine to the driver?
Sure, here it is.

Sincerely,
Nick

[-- Attachment #2: n230_dmi_id_grep.txt --]
[-- Type: text/plain, Size: 1427 bytes --]

/sys/class/dmi/id/bios_date:05/18/2010
/sys/class/dmi/id/bios_vendor:Phoenix Technologies Ltd.
/sys/class/dmi/id/bios_version:00MA.M000.20100518.JIP
/sys/class/dmi/id/board_asset_tag:SAMSUNG
/sys/class/dmi/id/board_name:N230                       
/sys/class/dmi/id/board_serial:123490EN400015
/sys/class/dmi/id/board_vendor:SAMSUNG ELECTRONICS CO., LTD.
/sys/class/dmi/id/board_version:Not Applicable
/sys/class/dmi/id/chassis_asset_tag:No Asset Tag
/sys/class/dmi/id/chassis_serial:None        
/sys/class/dmi/id/chassis_type:10
/sys/class/dmi/id/chassis_vendor:SAMSUNG ELECTRONICS CO., LTD.
/sys/class/dmi/id/chassis_version:N/A         
/sys/class/dmi/id/modalias:dmi:bvnPhoenixTechnologiesLtd.:bvr00MA.M000.20100518.JIP:bd05/18/2010:svnSAMSUNGELECTRONICSCO.,LTD.:pnN230:pvrNotApplicable:rvnSAMSUNGELECTRONICSCO.,LTD.:rnN230:rvrNotApplicable:cvnSAMSUNGELECTRONICSCO.,LTD.:ct10:cvrN/A:
/sys/class/dmi/id/product_name:N230                       
/sys/class/dmi/id/product_serial:ZT7H93HZ800194
/sys/class/dmi/id/product_uuid:000CDBD1-E31D-B211-8000-92BC375397DA
/sys/class/dmi/id/product_version:Not Applicable
/sys/class/dmi/id/sys_vendor:SAMSUNG ELECTRONICS CO., LTD.
/sys/class/dmi/id/uevent:MODALIAS=dmi:bvnPhoenixTechnologiesLtd.:bvr00MA.M000.20100518.JIP:bd05/18/2010:svnSAMSUNGELECTRONICSCO.,LTD.:pnN230:pvrNotApplicable:rvnSAMSUNGELECTRONICSCO.,LTD.:rnN230:rvrNotApplicable:cvnSAMSUNGELECTRONICSCO.,LTD.:ct10:cvrN/A:

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-10 17:28                 ` Nikolai Kondrashov
@ 2011-03-10 18:09                   ` Greg KH
  2011-03-10 21:05                     ` Nikolai Kondrashov
  0 siblings, 1 reply; 53+ messages in thread
From: Greg KH @ 2011-03-10 18:09 UTC (permalink / raw)
  To: Nikolai Kondrashov
  Cc: Matthew Garrett, Randy Dunlap, linux-kernel, platform-driver-x86

[-- Attachment #1: Type: text/plain, Size: 463 bytes --]

On Thu, Mar 10, 2011 at 07:28:00PM +0200, Nikolai Kondrashov wrote:
> On 03/10/2011 07:19 PM, Greg KH wrote:
> >Can you provide me the output of:
> >	grep . /sys/class/dmi/id/*
> >so I can try to add support for this machine to the driver?
> Sure, here it is.

Great, here's a new version of the samsung-laptop.c file, can you
replace it whereever you were building the previous one, rebuild it and
test it for this machine to see if it works?

thanks,

greg k-h

[-- Attachment #2: samsung-laptop.c --]
[-- Type: text/x-c++src, Size: 20714 bytes --]

/*
 * Samsung Laptop driver
 *
 * Copyright (C) 2009,2011 Greg Kroah-Hartman (gregkh@suse.de)
 * Copyright (C) 2009,2011 Novell 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.
 *
 */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/backlight.h>
#include <linux/fb.h>
#include <linux/dmi.h>
#include <linux/platform_device.h>
#include <linux/rfkill.h>

/*
 * This driver is needed because a number of Samsung laptops do not hook
 * their control settings through ACPI.  So we have to poke around in the
 * BIOS to do things like brightness values, and "special" key controls.
 */

/*
 * We have 0 - 8 as valid brightness levels.  The specs say that level 0 should
 * be reserved by the BIOS (which really doesn't make much sense), we tell
 * userspace that the value is 0 - 7 and then just tell the hardware 1 - 8
 */
#define MAX_BRIGHT	0x07


#define SABI_IFACE_MAIN			0x00
#define SABI_IFACE_SUB			0x02
#define SABI_IFACE_COMPLETE		0x04
#define SABI_IFACE_DATA			0x05

/* Structure to get data back to the calling function */
struct sabi_retval {
	u8 retval[20];
};

struct sabi_header_offsets {
	u8 port;
	u8 re_mem;
	u8 iface_func;
	u8 en_mem;
	u8 data_offset;
	u8 data_segment;
};

struct sabi_commands {
	/*
	 * Brightness is 0 - 8, as described above.
	 * Value 0 is for the BIOS to use
	 */
	u8 get_brightness;
	u8 set_brightness;

	/*
	 * first byte:
	 * 0x00 - wireless is off
	 * 0x01 - wireless is on
	 * second byte:
	 * 0x02 - 3G is off
	 * 0x03 - 3G is on
	 * TODO, verify 3G is correct, that doesn't seem right...
	 */
	u8 get_wireless_button;
	u8 set_wireless_button;

	/* 0 is off, 1 is on */
	u8 get_backlight;
	u8 set_backlight;

	/*
	 * 0x80 or 0x00 - no action
	 * 0x81 - recovery key pressed
	 */
	u8 get_recovery_mode;
	u8 set_recovery_mode;

	/*
	 * on seclinux: 0 is low, 1 is high,
	 * on swsmi: 0 is normal, 1 is silent, 2 is turbo
	 */
	u8 get_performance_level;
	u8 set_performance_level;

	/*
	 * Tell the BIOS that Linux is running on this machine.
	 * 81 is on, 80 is off
	 */
	u8 set_linux;
};

struct sabi_performance_level {
	const char *name;
	u8 value;
};

struct sabi_config {
	const char *test_string;
	u16 main_function;
	const struct sabi_header_offsets header_offsets;
	const struct sabi_commands commands;
	const struct sabi_performance_level performance_levels[4];
	u8 min_brightness;
	u8 max_brightness;
};

static const struct sabi_config sabi_configs[] = {
	{
		.test_string = "SECLINUX",

		.main_function = 0x4c49,

		.header_offsets = {
			.port = 0x00,
			.re_mem = 0x02,
			.iface_func = 0x03,
			.en_mem = 0x04,
			.data_offset = 0x05,
			.data_segment = 0x07,
		},

		.commands = {
			.get_brightness = 0x00,
			.set_brightness = 0x01,

			.get_wireless_button = 0x02,
			.set_wireless_button = 0x03,

			.get_backlight = 0x04,
			.set_backlight = 0x05,

			.get_recovery_mode = 0x06,
			.set_recovery_mode = 0x07,

			.get_performance_level = 0x08,
			.set_performance_level = 0x09,

			.set_linux = 0x0a,
		},

		.performance_levels = {
			{
				.name = "silent",
				.value = 0,
			},
			{
				.name = "normal",
				.value = 1,
			},
			{ },
		},
		.min_brightness = 1,
		.max_brightness = 8,
	},
	{
		.test_string = "SwSmi@",

		.main_function = 0x5843,

		.header_offsets = {
			.port = 0x00,
			.re_mem = 0x04,
			.iface_func = 0x02,
			.en_mem = 0x03,
			.data_offset = 0x05,
			.data_segment = 0x07,
		},

		.commands = {
			.get_brightness = 0x10,
			.set_brightness = 0x11,

			.get_wireless_button = 0x12,
			.set_wireless_button = 0x13,

			.get_backlight = 0x2d,
			.set_backlight = 0x2e,

			.get_recovery_mode = 0xff,
			.set_recovery_mode = 0xff,

			.get_performance_level = 0x31,
			.set_performance_level = 0x32,

			.set_linux = 0xff,
		},

		.performance_levels = {
			{
				.name = "normal",
				.value = 0,
			},
			{
				.name = "silent",
				.value = 1,
			},
			{
				.name = "overclock",
				.value = 2,
			},
			{ },
		},
		.min_brightness = 0,
		.max_brightness = 8,
	},
	{ },
};

static const struct sabi_config *sabi_config;

static void __iomem *sabi;
static void __iomem *sabi_iface;
static void __iomem *f0000_segment;
static struct backlight_device *backlight_device;
static struct mutex sabi_mutex;
static struct platform_device *sdev;
static struct rfkill *rfk;

static int force;
module_param(force, bool, 0);
MODULE_PARM_DESC(force,
		"Disable the DMI check and forces the driver to be loaded");

static int debug;
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");

static int sabi_get_command(u8 command, struct sabi_retval *sretval)
{
	int retval = 0;
	u16 port = readw(sabi + sabi_config->header_offsets.port);
	u8 complete, iface_data;

	mutex_lock(&sabi_mutex);

	/* enable memory to be able to write to it */
	outb(readb(sabi + sabi_config->header_offsets.en_mem), port);

	/* write out the command */
	writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN);
	writew(command, sabi_iface + SABI_IFACE_SUB);
	writeb(0, sabi_iface + SABI_IFACE_COMPLETE);
	outb(readb(sabi + sabi_config->header_offsets.iface_func), port);

	/* write protect memory to make it safe */
	outb(readb(sabi + sabi_config->header_offsets.re_mem), port);

	/* see if the command actually succeeded */
	complete = readb(sabi_iface + SABI_IFACE_COMPLETE);
	iface_data = readb(sabi_iface + SABI_IFACE_DATA);
	if (complete != 0xaa || iface_data == 0xff) {
		pr_warn("SABI get command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n",
		        command, complete, iface_data);
		retval = -EINVAL;
		goto exit;
	}
	/*
	 * Save off the data into a structure so the caller use it.
	 * Right now we only want the first 4 bytes,
	 * There are commands that need more, but not for the ones we
	 * currently care about.
	 */
	sretval->retval[0] = readb(sabi_iface + SABI_IFACE_DATA);
	sretval->retval[1] = readb(sabi_iface + SABI_IFACE_DATA + 1);
	sretval->retval[2] = readb(sabi_iface + SABI_IFACE_DATA + 2);
	sretval->retval[3] = readb(sabi_iface + SABI_IFACE_DATA + 3);

exit:
	mutex_unlock(&sabi_mutex);
	return retval;

}

static int sabi_set_command(u8 command, u8 data)
{
	int retval = 0;
	u16 port = readw(sabi + sabi_config->header_offsets.port);
	u8 complete, iface_data;

	mutex_lock(&sabi_mutex);

	/* enable memory to be able to write to it */
	outb(readb(sabi + sabi_config->header_offsets.en_mem), port);

	/* write out the command */
	writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN);
	writew(command, sabi_iface + SABI_IFACE_SUB);
	writeb(0, sabi_iface + SABI_IFACE_COMPLETE);
	writeb(data, sabi_iface + SABI_IFACE_DATA);
	outb(readb(sabi + sabi_config->header_offsets.iface_func), port);

	/* write protect memory to make it safe */
	outb(readb(sabi + sabi_config->header_offsets.re_mem), port);

	/* see if the command actually succeeded */
	complete = readb(sabi_iface + SABI_IFACE_COMPLETE);
	iface_data = readb(sabi_iface + SABI_IFACE_DATA);
	if (complete != 0xaa || iface_data == 0xff) {
		pr_warn("SABI set command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n",
		       command, complete, iface_data);
		retval = -EINVAL;
	}

	mutex_unlock(&sabi_mutex);
	return retval;
}

static void test_backlight(void)
{
	struct sabi_retval sretval;

	sabi_get_command(sabi_config->commands.get_backlight, &sretval);
	printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);

	sabi_set_command(sabi_config->commands.set_backlight, 0);
	printk(KERN_DEBUG "backlight should be off\n");

	sabi_get_command(sabi_config->commands.get_backlight, &sretval);
	printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);

	msleep(1000);

	sabi_set_command(sabi_config->commands.set_backlight, 1);
	printk(KERN_DEBUG "backlight should be on\n");

	sabi_get_command(sabi_config->commands.get_backlight, &sretval);
	printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
}

static void test_wireless(void)
{
	struct sabi_retval sretval;

	sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
	printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);

	sabi_set_command(sabi_config->commands.set_wireless_button, 0);
	printk(KERN_DEBUG "wireless led should be off\n");

	sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
	printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);

	msleep(1000);

	sabi_set_command(sabi_config->commands.set_wireless_button, 1);
	printk(KERN_DEBUG "wireless led should be on\n");

	sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
	printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
}

static u8 read_brightness(void)
{
	struct sabi_retval sretval;
	int user_brightness = 0;
	int retval;

	retval = sabi_get_command(sabi_config->commands.get_brightness,
				  &sretval);
	if (!retval) {
		user_brightness = sretval.retval[0];
		if (user_brightness != 0)
			user_brightness -= sabi_config->min_brightness;
	}
	return user_brightness;
}

static void set_brightness(u8 user_brightness)
{
	u8 user_level = user_brightness - sabi_config->min_brightness;

	sabi_set_command(sabi_config->commands.set_brightness, user_level);
}

static int get_brightness(struct backlight_device *bd)
{
	return (int)read_brightness();
}

static int update_status(struct backlight_device *bd)
{
	set_brightness(bd->props.brightness);

	if (bd->props.power == FB_BLANK_UNBLANK)
		sabi_set_command(sabi_config->commands.set_backlight, 1);
	else
		sabi_set_command(sabi_config->commands.set_backlight, 0);
	return 0;
}

static const struct backlight_ops backlight_ops = {
	.get_brightness	= get_brightness,
	.update_status	= update_status,
};

static int rfkill_set(void *data, bool blocked)
{
	/* Do something with blocked...*/
	/*
	 * blocked == false is on
	 * blocked == true is off
	 */
	if (blocked)
		sabi_set_command(sabi_config->commands.set_wireless_button, 0);
	else
		sabi_set_command(sabi_config->commands.set_wireless_button, 1);

	return 0;
}

static struct rfkill_ops rfkill_ops = {
	.set_block = rfkill_set,
};

static int init_wireless(struct platform_device *sdev)
{
	int retval;

	rfk = rfkill_alloc("samsung-wifi", &sdev->dev, RFKILL_TYPE_WLAN,
			   &rfkill_ops, NULL);
	if (!rfk)
		return -ENOMEM;

	retval = rfkill_register(rfk);
	if (retval) {
		rfkill_destroy(rfk);
		return -ENODEV;
	}

	return 0;
}

static void destroy_wireless(void)
{
	rfkill_unregister(rfk);
	rfkill_destroy(rfk);
}

static ssize_t get_performance_level(struct device *dev,
				     struct device_attribute *attr, char *buf)
{
	struct sabi_retval sretval;
	int retval;
	int i;

	/* Read the state */
	retval = sabi_get_command(sabi_config->commands.get_performance_level,
				  &sretval);
	if (retval)
		return retval;

	/* The logic is backwards, yeah, lots of fun... */
	for (i = 0; sabi_config->performance_levels[i].name; ++i) {
		if (sretval.retval[0] == sabi_config->performance_levels[i].value)
			return sprintf(buf, "%s\n", sabi_config->performance_levels[i].name);
	}
	return sprintf(buf, "%s\n", "unknown");
}

static ssize_t set_performance_level(struct device *dev,
				struct device_attribute *attr, const char *buf,
				size_t count)
{
	if (count >= 1) {
		int i;
		for (i = 0; sabi_config->performance_levels[i].name; ++i) {
			const struct sabi_performance_level *level =
				&sabi_config->performance_levels[i];
			if (!strncasecmp(level->name, buf, strlen(level->name))) {
				sabi_set_command(sabi_config->commands.set_performance_level,
						 level->value);
				break;
			}
		}
		if (!sabi_config->performance_levels[i].name)
			return -EINVAL;
	}
	return count;
}
static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO,
		   get_performance_level, set_performance_level);


static int __init dmi_check_cb(const struct dmi_system_id *id)
{
	pr_info("found laptop model '%s'\n",
		id->ident);
	return 0;
}

static struct dmi_system_id __initdata samsung_dmi_table[] = {
	{
		.ident = "N128",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR,
					"SAMSUNG ELECTRONICS CO., LTD."),
			DMI_MATCH(DMI_PRODUCT_NAME, "N128"),
			DMI_MATCH(DMI_BOARD_NAME, "N128"),
		},
		.callback = dmi_check_cb,
	},
	{
		.ident = "N130",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR,
					"SAMSUNG ELECTRONICS CO., LTD."),
			DMI_MATCH(DMI_PRODUCT_NAME, "N130"),
			DMI_MATCH(DMI_BOARD_NAME, "N130"),
		},
		.callback = dmi_check_cb,
	},
	{
		.ident = "X125",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR,
					"SAMSUNG ELECTRONICS CO., LTD."),
			DMI_MATCH(DMI_PRODUCT_NAME, "X125"),
			DMI_MATCH(DMI_BOARD_NAME, "X125"),
		},
		.callback = dmi_check_cb,
	},
	{
		.ident = "X120/X170",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR,
					"SAMSUNG ELECTRONICS CO., LTD."),
			DMI_MATCH(DMI_PRODUCT_NAME, "X120/X170"),
			DMI_MATCH(DMI_BOARD_NAME, "X120/X170"),
		},
		.callback = dmi_check_cb,
	},
	{
		.ident = "NC10",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR,
					"SAMSUNG ELECTRONICS CO., LTD."),
			DMI_MATCH(DMI_PRODUCT_NAME, "NC10"),
			DMI_MATCH(DMI_BOARD_NAME, "NC10"),
		},
		.callback = dmi_check_cb,
	},
		{
		.ident = "NP-Q45",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR,
					"SAMSUNG ELECTRONICS CO., LTD."),
			DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"),
			DMI_MATCH(DMI_BOARD_NAME, "SQ45S70S"),
		},
		.callback = dmi_check_cb,
		},
	{
		.ident = "X360",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR,
					"SAMSUNG ELECTRONICS CO., LTD."),
			DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
			DMI_MATCH(DMI_BOARD_NAME, "X360"),
		},
		.callback = dmi_check_cb,
	},
	{
		.ident = "R410 Plus",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR,
					"SAMSUNG ELECTRONICS CO., LTD."),
			DMI_MATCH(DMI_PRODUCT_NAME, "R410P"),
			DMI_MATCH(DMI_BOARD_NAME, "R460"),
		},
		.callback = dmi_check_cb,
	},
	{
		.ident = "R518",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR,
					"SAMSUNG ELECTRONICS CO., LTD."),
			DMI_MATCH(DMI_PRODUCT_NAME, "R518"),
			DMI_MATCH(DMI_BOARD_NAME, "R518"),
		},
		.callback = dmi_check_cb,
	},
	{
		.ident = "R519/R719",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR,
					"SAMSUNG ELECTRONICS CO., LTD."),
			DMI_MATCH(DMI_PRODUCT_NAME, "R519/R719"),
			DMI_MATCH(DMI_BOARD_NAME, "R519/R719"),
		},
		.callback = dmi_check_cb,
	},
	{
		.ident = "N150/N210/N220/N230",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR,
					"SAMSUNG ELECTRONICS CO., LTD."),
			DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220/N230"),
			DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220/N230"),
		},
		.callback = dmi_check_cb,
	},
	{
		.ident = "N150P/N210P/N220P",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR,
					"SAMSUNG ELECTRONICS CO., LTD."),
			DMI_MATCH(DMI_PRODUCT_NAME, "N150P/N210P/N220P"),
			DMI_MATCH(DMI_BOARD_NAME, "N150P/N210P/N220P"),
		},
		.callback = dmi_check_cb,
	},
	{
		.ident = "R530/R730",
		.matches = {
		      DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
		      DMI_MATCH(DMI_PRODUCT_NAME, "R530/R730"),
		      DMI_MATCH(DMI_BOARD_NAME, "R530/R730"),
		},
		.callback = dmi_check_cb,
	},
	{
		.ident = "NF110/NF210/NF310",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
			DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"),
			DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"),
		},
		.callback = dmi_check_cb,
	},
	{
		.ident = "N145P/N250P/N260P",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
			DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
			DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
		},
		.callback = dmi_check_cb,
	},
	{
		.ident = "R70/R71",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR,
					"SAMSUNG ELECTRONICS CO., LTD."),
			DMI_MATCH(DMI_PRODUCT_NAME, "R70/R71"),
			DMI_MATCH(DMI_BOARD_NAME, "R70/R71"),
		},
		.callback = dmi_check_cb,
	},
	{
		.ident = "P460",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
			DMI_MATCH(DMI_PRODUCT_NAME, "P460"),
			DMI_MATCH(DMI_BOARD_NAME, "P460"),
		},
		.callback = dmi_check_cb,
	},
	{ },
};
MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);

static int find_signature(void __iomem *memcheck, const char *testStr)
{
	int i = 0;
	int loca;

	for (loca = 0; loca < 0xffff; loca++) {
		char temp = readb(memcheck + loca);

		if (temp == testStr[i]) {
			if (i == strlen(testStr)-1)
				break;
			++i;
		} else {
			i = 0;
		}
	}
	return loca;
}

static int __init samsung_init(void)
{
	struct backlight_properties props;
	struct sabi_retval sretval;
	unsigned int ifaceP;
	int i;
	int loca;
	int retval;

	mutex_init(&sabi_mutex);

	if (!force && !dmi_check_system(samsung_dmi_table))
		return -ENODEV;

	f0000_segment = ioremap_nocache(0xf0000, 0xffff);
	if (!f0000_segment) {
		pr_err("Can't map the segment at 0xf0000\n");
		return -EINVAL;
	}

	/* Try to find one of the signatures in memory to find the header */
	for (i = 0; sabi_configs[i].test_string != 0; ++i) {
		sabi_config = &sabi_configs[i];
		loca = find_signature(f0000_segment, sabi_config->test_string);
		if (loca != 0xffff)
			break;
	}

	if (loca == 0xffff) {
		pr_err("This computer does not support SABI\n");
		goto error_no_signature;
	}

	/* point to the SMI port Number */
	loca += 1;
	sabi = (f0000_segment + loca);

	if (debug) {
		printk(KERN_DEBUG "This computer supports SABI==%x\n",
			loca + 0xf0000 - 6);
		printk(KERN_DEBUG "SABI header:\n");
		printk(KERN_DEBUG " SMI Port Number = 0x%04x\n",
			readw(sabi + sabi_config->header_offsets.port));
		printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n",
			readb(sabi + sabi_config->header_offsets.iface_func));
		printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n",
			readb(sabi + sabi_config->header_offsets.en_mem));
		printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n",
			readb(sabi + sabi_config->header_offsets.re_mem));
		printk(KERN_DEBUG " SABI data offset = 0x%04x\n",
			readw(sabi + sabi_config->header_offsets.data_offset));
		printk(KERN_DEBUG " SABI data segment = 0x%04x\n",
			readw(sabi + sabi_config->header_offsets.data_segment));
	}

	/* Get a pointer to the SABI Interface */
	ifaceP = (readw(sabi + sabi_config->header_offsets.data_segment) & 0x0ffff) << 4;
	ifaceP += readw(sabi + sabi_config->header_offsets.data_offset) & 0x0ffff;
	sabi_iface = ioremap_nocache(ifaceP, 16);
	if (!sabi_iface) {
		pr_err("Can't remap %x\n", ifaceP);
		goto exit;
	}
	if (debug) {
		printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP);
		printk(KERN_DEBUG "sabi_iface = %p\n", sabi_iface);

		test_backlight();
		test_wireless();

		retval = sabi_get_command(sabi_config->commands.get_brightness,
					  &sretval);
		printk(KERN_DEBUG "brightness = 0x%02x\n", sretval.retval[0]);
	}

	/* Turn on "Linux" mode in the BIOS */
	if (sabi_config->commands.set_linux != 0xff) {
		retval = sabi_set_command(sabi_config->commands.set_linux,
					  0x81);
		if (retval) {
			pr_warn("Linux mode was not set!\n");
			goto error_no_platform;
		}
	}

	/* knock up a platform device to hang stuff off of */
	sdev = platform_device_register_simple("samsung", -1, NULL, 0);
	if (IS_ERR(sdev))
		goto error_no_platform;

	/* create a backlight device to talk to this one */
	memset(&props, 0, sizeof(struct backlight_properties));
	props.max_brightness = sabi_config->max_brightness;
	backlight_device = backlight_device_register("samsung", &sdev->dev,
						     NULL, &backlight_ops,
						     &props);
	if (IS_ERR(backlight_device))
		goto error_no_backlight;

	backlight_device->props.brightness = read_brightness();
	backlight_device->props.power = FB_BLANK_UNBLANK;
	backlight_update_status(backlight_device);

	retval = init_wireless(sdev);
	if (retval)
		goto error_no_rfk;

	retval = device_create_file(&sdev->dev, &dev_attr_performance_level);
	if (retval)
		goto error_file_create;

exit:
	return 0;

error_file_create:
	destroy_wireless();

error_no_rfk:
	backlight_device_unregister(backlight_device);

error_no_backlight:
	platform_device_unregister(sdev);

error_no_platform:
	iounmap(sabi_iface);

error_no_signature:
	iounmap(f0000_segment);
	return -EINVAL;
}

static void __exit samsung_exit(void)
{
	/* Turn off "Linux" mode in the BIOS */
	if (sabi_config->commands.set_linux != 0xff)
		sabi_set_command(sabi_config->commands.set_linux, 0x80);

	device_remove_file(&sdev->dev, &dev_attr_performance_level);
	backlight_device_unregister(backlight_device);
	destroy_wireless();
	iounmap(sabi_iface);
	iounmap(f0000_segment);
	platform_device_unregister(sdev);
}

module_init(samsung_init);
module_exit(samsung_exit);

MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>");
MODULE_DESCRIPTION("Samsung Backlight driver");
MODULE_LICENSE("GPL");

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-10 18:09                   ` Greg KH
@ 2011-03-10 21:05                     ` Nikolai Kondrashov
  2011-03-10 21:15                       ` Greg KH
  0 siblings, 1 reply; 53+ messages in thread
From: Nikolai Kondrashov @ 2011-03-10 21:05 UTC (permalink / raw)
  To: Greg KH; +Cc: Matthew Garrett, Randy Dunlap, linux-kernel, platform-driver-x86

On 03/10/2011 08:09 PM, Greg KH wrote:
> Great, here's a new version of the samsung-laptop.c file, can you
> replace it whereever you were building the previous one, rebuild it and
> test it for this machine to see if it works?
This is really strange.

It's all the same. I tried the new samsung-laptop.c on n230 and the previous
version on n210 - the results are the same as before.

Could it be that samsung-laptop has some dependencies unspecified?

I'm using the stock 2.6.32 kernel configuration on 2.6.37 after running make
menuconfig. I can' send it to you, if you wish.

Thank you :)

Sincerely,
Nick

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-10 21:05                     ` Nikolai Kondrashov
@ 2011-03-10 21:15                       ` Greg KH
  2011-03-11  7:12                         ` Nikolai Kondrashov
  0 siblings, 1 reply; 53+ messages in thread
From: Greg KH @ 2011-03-10 21:15 UTC (permalink / raw)
  To: Nikolai Kondrashov
  Cc: Matthew Garrett, Randy Dunlap, linux-kernel, platform-driver-x86

On Thu, Mar 10, 2011 at 11:05:09PM +0200, Nikolai Kondrashov wrote:
> On 03/10/2011 08:09 PM, Greg KH wrote:
> >Great, here's a new version of the samsung-laptop.c file, can you
> >replace it whereever you were building the previous one, rebuild it and
> >test it for this machine to see if it works?
> This is really strange.
> 
> It's all the same. I tried the new samsung-laptop.c on n230 and the previous
> version on n210 - the results are the same as before.
> 
> Could it be that samsung-laptop has some dependencies unspecified?
> 
> I'm using the stock 2.6.32 kernel configuration on 2.6.37 after running make
> menuconfig. I can' send it to you, if you wish.

Wierd.

Are you sure the driver is loaded?

What happens if you do:
	rmmod samsung-laptop
	dmesg -c
	modprobe samsung-laptop debug=1

can you send me the output of 'dmesg' after doing the above as root?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-10 21:15                       ` Greg KH
@ 2011-03-11  7:12                         ` Nikolai Kondrashov
  2011-03-11 17:03                           ` Greg KH
  0 siblings, 1 reply; 53+ messages in thread
From: Nikolai Kondrashov @ 2011-03-11  7:12 UTC (permalink / raw)
  To: Greg KH; +Cc: Matthew Garrett, Randy Dunlap, linux-kernel, platform-driver-x86

On 03/10/2011 11:15 PM, Greg KH wrote:
> Are you sure the driver is loaded?
It doesn't load - it fails on inserting.
I should've probably reminded you that in my recent messages.

> What happens if you do:
> 	rmmod samsung-laptop
> 	dmesg -c
> 	modprobe samsung-laptop debug=1
>
> can you send me the output of 'dmesg' after doing the above as root?
Sure:

nick@merry:~$ dmesg
nick@merry:~$ sudo modprobe samsung-laptop debug=1
FATAL: Error inserting samsung_laptop 
(/lib/modules/2.6.37+/kernel/drivers/staging/samsung-laptop/samsung-laptop.ko): 
No such device
nick@merry:~$ dmesg
[  179.689516] samsung_laptop: module is from the staging directory, the 
quality is unknown, you have been warned.
nick@merry:~$ sudo modprobe samsung-laptop debug=1 force=1
FATAL: Error inserting samsung_laptop 
(/lib/modules/2.6.37+/kernel/drivers/staging/samsung-laptop/samsung-laptop.ko): 
Invalid argument
nick@merry:~$ dmesg
[  179.689516] samsung_laptop: module is from the staging directory, the 
quality is unknown, you have been warned.
[  190.474615] samsung_laptop: module is from the staging directory, the 
quality is unknown, you have been warned.
[  190.479681] This computer does not support SABI
nick@merry:~$

Thank you.

Sincerely,
Nick

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-11  7:12                         ` Nikolai Kondrashov
@ 2011-03-11 17:03                           ` Greg KH
  2011-03-11 19:07                             ` Nikolai Kondrashov
  0 siblings, 1 reply; 53+ messages in thread
From: Greg KH @ 2011-03-11 17:03 UTC (permalink / raw)
  To: Nikolai Kondrashov
  Cc: Matthew Garrett, Randy Dunlap, linux-kernel, platform-driver-x86

On Fri, Mar 11, 2011 at 09:12:07AM +0200, Nikolai Kondrashov wrote:
> On 03/10/2011 11:15 PM, Greg KH wrote:
> >Are you sure the driver is loaded?
> It doesn't load - it fails on inserting.
> I should've probably reminded you that in my recent messages.
> 
> >What happens if you do:
> >	rmmod samsung-laptop
> >	dmesg -c
> >	modprobe samsung-laptop debug=1
> >
> >can you send me the output of 'dmesg' after doing the above as root?
> Sure:
> 
> nick@merry:~$ dmesg
> nick@merry:~$ sudo modprobe samsung-laptop debug=1
> FATAL: Error inserting samsung_laptop (/lib/modules/2.6.37+/kernel/drivers/staging/samsung-laptop/samsung-laptop.ko):
> No such device
> nick@merry:~$ dmesg
> [  179.689516] samsung_laptop: module is from the staging directory,
> the quality is unknown, you have been warned.
> nick@merry:~$ sudo modprobe samsung-laptop debug=1 force=1
> FATAL: Error inserting samsung_laptop (/lib/modules/2.6.37+/kernel/drivers/staging/samsung-laptop/samsung-laptop.ko):
> Invalid argument
> nick@merry:~$ dmesg
> [  179.689516] samsung_laptop: module is from the staging directory,
> the quality is unknown, you have been warned.
> [  190.474615] samsung_laptop: module is from the staging directory,
> the quality is unknown, you have been warned.
> [  190.479681] This computer does not support SABI

Are you sure this was the driver you just built that I sent you?  Can
you send the output of 'modinfo samsung-laptop'?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-11 17:03                           ` Greg KH
@ 2011-03-11 19:07                             ` Nikolai Kondrashov
  2011-03-11 19:34                               ` Greg KH
  0 siblings, 1 reply; 53+ messages in thread
From: Nikolai Kondrashov @ 2011-03-11 19:07 UTC (permalink / raw)
  To: Greg KH; +Cc: Matthew Garrett, Randy Dunlap, linux-kernel, platform-driver-x86

On 03/11/2011 07:03 PM, Greg KH wrote:
> Are you sure this was the driver you just built that I sent you?  Can
> you send the output of 'modinfo samsung-laptop'?
Yes, I'm pretty sure. Here is the modinfo output:

filename: 
/lib/modules/2.6.37+/kernel/drivers/staging/samsung-laptop/samsung-laptop.ko
license:        GPL
description:    Samsung Backlight driver
author:         Greg Kroah-Hartman <gregkh@suse.de>
alias:          dmi*:svn*SAMSUNGELECTRONICSCO.,LTD.*:pn*N130*:rn*N130*:
alias:          dmi*:svn*SAMSUNGELECTRONICSCO.,LTD.*:pn*N128*:rn*N128*:
depends:        rfkill
staging:        Y
vermagic:       2.6.37+ SMP mod_unload modversions 686
parm:           force:Disable the DMI check and forces the driver to be 
loaded (bool)
parm:           debug:Debug enabled or not (bool)

However, there seems to be some problem with aliases.

Thank you :)

Sincerely,
Nick

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-11 19:07                             ` Nikolai Kondrashov
@ 2011-03-11 19:34                               ` Greg KH
  2011-03-11 20:20                                 ` Nikolai Kondrashov
  0 siblings, 1 reply; 53+ messages in thread
From: Greg KH @ 2011-03-11 19:34 UTC (permalink / raw)
  To: Nikolai Kondrashov
  Cc: Matthew Garrett, Randy Dunlap, linux-kernel, platform-driver-x86

On Fri, Mar 11, 2011 at 09:07:15PM +0200, Nikolai Kondrashov wrote:
> On 03/11/2011 07:03 PM, Greg KH wrote:
> >Are you sure this was the driver you just built that I sent you?  Can
> >you send the output of 'modinfo samsung-laptop'?
> Yes, I'm pretty sure. Here is the modinfo output:
> 
> filename: /lib/modules/2.6.37+/kernel/drivers/staging/samsung-laptop/samsung-laptop.ko
> license:        GPL
> description:    Samsung Backlight driver
> author:         Greg Kroah-Hartman <gregkh@suse.de>
> alias:          dmi*:svn*SAMSUNGELECTRONICSCO.,LTD.*:pn*N130*:rn*N130*:
> alias:          dmi*:svn*SAMSUNGELECTRONICSCO.,LTD.*:pn*N128*:rn*N128*:
> depends:        rfkill

Ok, this shows you are not loading the driver I sent to you, this is the
"original" one I sent, which will fail for your machine.

You need to build and install the one I sent you.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-11 19:34                               ` Greg KH
@ 2011-03-11 20:20                                 ` Nikolai Kondrashov
  2011-03-11 20:23                                   ` Nikolai Kondrashov
  2011-03-11 20:30                                   ` Greg KH
  0 siblings, 2 replies; 53+ messages in thread
From: Nikolai Kondrashov @ 2011-03-11 20:20 UTC (permalink / raw)
  To: Greg KH; +Cc: Matthew Garrett, Randy Dunlap, linux-kernel, platform-driver-x86

[-- Attachment #1: Type: text/plain, Size: 654 bytes --]

On 03/11/2011 09:34 PM, Greg KH wrote:
> Ok, this shows you are not loading the driver I sent to you, this is the
> "original" one I sent, which will fail for your machine.
Sorry, I didn't know the old version was still there.
For some reason until I removed the staging samsung-laptop from the
Makefile, the new one didn't get installed.

> You need to build and install the one I sent you.
Done. So far tested on n230 only.

It fails to insert without "force" with the same message. With force it
installs, but doesn't seem to work, at least for brightness buttons.

Please find modinfo output and dmesg output attached.

Thank you :)

Sincerely,
Nick

[-- Attachment #2: n230_dmesg.txt --]
[-- Type: text/plain, Size: 13188 bytes --]

[  252.249599] This computer supports SABI==f51cf
[  252.249606] SABI header:
[  252.249611]  SMI Port Number = 0x00b2
[  252.249615]  SMI Interface Function = 0xc0
[  252.249620]  SMI enable memory buffer = 0xc1
[  252.249625]  SMI restore memory buffer = 0xc2
[  252.249629]  SABI data offset = 0x0f00
[  252.249634]  SABI data segment = 0xdf01
[  252.249639] ifaceP = 0x000dff10
[  252.249644] sabi_iface = c00dff10
[  252.251359] backlight = 0x01
[  252.252977] backlight should be off
[  252.254667] backlight = 0x00
[  253.258069] backlight should be on
[  253.260227] backlight = 0x01
[  253.262005] wireless led = 0x01
[  253.264147] wireless led should be off
[  253.264159] wl0: MAC Detected a change on the RF Disable Input 0x10000
[  253.265929] wireless led = 0x00
[  254.148087] ops->tx called while down
[  254.148101] ops->tx called while down
[  254.148108] ops->tx called while down
[  254.148114] ops->tx called while down
[  254.148120] ops->tx called while down
[  254.148126] ops->tx called while down
[  254.148132] ops->tx called while down
[  254.148137] ops->tx called while down
[  254.148143] ops->tx called while down
[  254.148149] ops->tx called while down
[  254.148155] ops->tx called while down
[  254.148161] ------------[ cut here ]------------
[  254.148212] WARNING: at /home/nick/projects/kernel.org/linus/linux-2.6/net/mac80211/tx.c:1490 ieee80211_tx+0x16c/0x18a [mac80211]()
[  254.148222] Hardware name: N230                       
[  254.148228] tx refused but queue active
[  254.148234] Modules linked in: samsung_laptop(+) aes_i586 aes_generic i915 drm_kms_helper drm i2c_algo_bit parport_pc ppdev lp parport sco acpi_cpufreq mperf bridge stp cpufreq_stats bnep cpufreq_userspace cpufreq_conservative cpufreq_powersave rfcomm l2cap vboxnetadp vboxnetflt vboxdrv uinput fuse ext4 jbd2 crc16 loop dm_crypt dm_mod arc4 ecb snd_hda_codec_realtek snd_hda_intel brcm80211(C) snd_hda_codec uvcvideo btusb joydev videodev snd_hwdep snd_pcm mac80211 snd_seq snd_timer snd_seq_device snd cfg80211 evdev bluetooth i2c_i801 v4l1_compat tpm_tis soundcore snd_page_alloc tpm video psmouse i2c_core tpm_bios rfkill processor output pcspkr battery button serio_raw shpchp pci_hotplug ac ext3 jbd mbcache raid10 raid456 async_raid6_recov async_pq raid6_pq async_xor xor async_memcpy async_tx raid1 raid0 multipath linear md_mod sd_mod crc_t10dif ahci uhci_hcd libahci libata ehci_hcd usbcore scsi_mod sky2 thermal thermal_sys nls_base [last unloaded: samsung_laptop]
[  254.148486] Pid: 189, comm: kworker/u:2 Tainted: G        WC  2.6.37+ #3
[  254.148493] Call Trace:
[  254.148511]  [<c102f079>] ? warn_slowpath_common+0x6a/0x7b
[  254.148553]  [<f87c43a9>] ? ieee80211_tx+0x16c/0x18a [mac80211]
[  254.148567]  [<c102f0f0>] ? warn_slowpath_fmt+0x28/0x2c
[  254.148608]  [<f87c43a9>] ? ieee80211_tx+0x16c/0x18a [mac80211]
[  254.148653]  [<f87c454b>] ? ieee80211_xmit+0x184/0x18c [mac80211]
[  254.148668]  [<c11dcca7>] ? __alloc_skb+0x4c/0xda
[  254.148709]  [<f87c458f>] ? ieee80211_tx_skb+0x3c/0x43 [mac80211]
[  254.148744]  [<f87b5441>] ? ieee80211_offchannel_stop_station+0xcf/0xea [mac80211]
[  254.148779]  [<f87b5078>] ? ieee80211_scan_work+0x340/0x418 [mac80211]
[  254.148794]  [<c10403b1>] ? process_one_work+0x181/0x25e
[  254.148830]  [<f87b4d38>] ? ieee80211_scan_work+0x0/0x418 [mac80211]
[  254.148843]  [<c1041907>] ? worker_thread+0xf3/0x1f4
[  254.148855]  [<c1041814>] ? worker_thread+0x0/0x1f4
[  254.148866]  [<c1043f49>] ? kthread+0x63/0x68
[  254.148877]  [<c1043ee6>] ? kthread+0x0/0x68
[  254.148890]  [<c100353e>] ? kernel_thread_helper+0x6/0x10
[  254.148899] ---[ end trace e9ed04a305514141 ]---
[  254.248185] ops->tx called while down
[  254.248199] ops->tx called while down
[  254.248208] ops->tx called while down
[  254.248216] ops->tx called while down
[  254.248224] ops->tx called while down
[  254.248232] ops->tx called while down
[  254.248242] ops->tx called while down
[  254.248250] ops->tx called while down
[  254.248258] ops->tx called while down
[  254.248266] ops->tx called while down
[  254.248273] ops->tx called while down
[  254.248281] ------------[ cut here ]------------
[  254.248342] WARNING: at /home/nick/projects/kernel.org/linus/linux-2.6/net/mac80211/tx.c:1490 ieee80211_tx+0x16c/0x18a [mac80211]()
[  254.248357] Hardware name: N230                       
[  254.248365] tx refused but queue active
[  254.248373] Modules linked in: samsung_laptop(+) aes_i586 aes_generic i915 drm_kms_helper drm i2c_algo_bit parport_pc ppdev lp parport sco acpi_cpufreq mperf bridge stp cpufreq_stats bnep cpufreq_userspace cpufreq_conservative cpufreq_powersave rfcomm l2cap vboxnetadp vboxnetflt vboxdrv uinput fuse ext4 jbd2 crc16 loop dm_crypt dm_mod arc4 ecb snd_hda_codec_realtek snd_hda_intel brcm80211(C) snd_hda_codec uvcvideo btusb joydev videodev snd_hwdep snd_pcm mac80211 snd_seq snd_timer snd_seq_device snd cfg80211 evdev bluetooth i2c_i801 v4l1_compat tpm_tis soundcore snd_page_alloc tpm video psmouse i2c_core tpm_bios rfkill processor output pcspkr battery button serio_raw shpchp pci_hotplug ac ext3 jbd mbcache raid10 raid456 async_raid6_recov async_pq raid6_pq async_xor xor async_memcpy async_tx raid1 raid0 multipath linear md_mod sd_mod crc_t10dif ahci uhci_hcd libahci libata ehci_hcd usbcore scsi_mod sky2 thermal thermal_sys nls_base [last unloaded: samsung_laptop]
[  254.248707] Pid: 189, comm: kworker/u:2 Tainted: G        WC  2.6.37+ #3
[  254.248719] Call Trace:
[  254.248743]  [<c102f079>] ? warn_slowpath_common+0x6a/0x7b
[  254.248803]  [<f87c43a9>] ? ieee80211_tx+0x16c/0x18a [mac80211]
[  254.248822]  [<c102f0f0>] ? warn_slowpath_fmt+0x28/0x2c
[  254.248881]  [<f87c43a9>] ? ieee80211_tx+0x16c/0x18a [mac80211]
[  254.248947]  [<f87c454b>] ? ieee80211_xmit+0x184/0x18c [mac80211]
[  254.248968]  [<c11dcca7>] ? __alloc_skb+0x4c/0xda
[  254.249025]  [<f87c458f>] ? ieee80211_tx_skb+0x3c/0x43 [mac80211]
[  254.249076]  [<f87b51c2>] ? ieee80211_offchannel_return+0x72/0x158 [mac80211]
[  254.249132]  [<f87b4686>] ? __ieee80211_scan_completed_finish+0x3c/0x7b [mac80211]
[  254.249154]  [<c10403b1>] ? process_one_work+0x181/0x25e
[  254.249206]  [<f87b4d38>] ? ieee80211_scan_work+0x0/0x418 [mac80211]
[  254.249225]  [<c1041907>] ? worker_thread+0xf3/0x1f4
[  254.249242]  [<c1041814>] ? worker_thread+0x0/0x1f4
[  254.249257]  [<c1043f49>] ? kthread+0x63/0x68
[  254.249272]  [<c1043ee6>] ? kthread+0x0/0x68
[  254.249288]  [<c100353e>] ? kernel_thread_helper+0x6/0x10
[  254.249300] ---[ end trace e9ed04a305514142 ]---
[  254.250639] ops->tx called while down
[  254.250654] ops->tx called while down
[  254.250663] ops->tx called while down
[  254.250671] ops->tx called while down
[  254.250679] ops->tx called while down
[  254.250687] ops->tx called while down
[  254.250695] ops->tx called while down
[  254.250704] ops->tx called while down
[  254.250712] ops->tx called while down
[  254.250720] ops->tx called while down
[  254.250728] ops->tx called while down
[  254.250736] ------------[ cut here ]------------
[  254.250797] WARNING: at /home/nick/projects/kernel.org/linus/linux-2.6/net/mac80211/tx.c:1490 ieee80211_tx+0x16c/0x18a [mac80211]()
[  254.250812] Hardware name: N230                       
[  254.250821] tx refused but queue active
[  254.250829] Modules linked in: samsung_laptop(+) aes_i586 aes_generic i915 drm_kms_helper drm i2c_algo_bit parport_pc ppdev lp parport sco acpi_cpufreq mperf bridge stp cpufreq_stats bnep cpufreq_userspace cpufreq_conservative cpufreq_powersave rfcomm l2cap vboxnetadp vboxnetflt vboxdrv uinput fuse ext4 jbd2 crc16 loop dm_crypt dm_mod arc4 ecb snd_hda_codec_realtek snd_hda_intel brcm80211(C) snd_hda_codec uvcvideo btusb joydev videodev snd_hwdep snd_pcm mac80211 snd_seq snd_timer snd_seq_device snd cfg80211 evdev bluetooth i2c_i801 v4l1_compat tpm_tis soundcore snd_page_alloc tpm video psmouse i2c_core tpm_bios rfkill processor output pcspkr battery button serio_raw shpchp pci_hotplug ac ext3 jbd mbcache raid10 raid456 async_raid6_recov async_pq raid6_pq async_xor xor async_memcpy async_tx raid1 raid0 multipath linear md_mod sd_mod crc_t10dif ahci uhci_hcd libahci libata ehci_hcd usbcore scsi_mod sky2 thermal thermal_sys nls_base [last unloaded: samsung_laptop]
[  254.251160] Pid: 189, comm: kworker/u:2 Tainted: G        WC  2.6.37+ #3
[  254.251171] Call Trace:
[  254.251195]  [<c102f079>] ? warn_slowpath_common+0x6a/0x7b
[  254.251256]  [<f87c43a9>] ? ieee80211_tx+0x16c/0x18a [mac80211]
[  254.251277]  [<c102f0f0>] ? warn_slowpath_fmt+0x28/0x2c
[  254.251335]  [<f87c43a9>] ? ieee80211_tx+0x16c/0x18a [mac80211]
[  254.251401]  [<f87c454b>] ? ieee80211_xmit+0x184/0x18c [mac80211]
[  254.251459]  [<f87c4801>] ? ieee80211_probereq_get+0xd7/0xeb [mac80211]
[  254.251516]  [<f87c458f>] ? ieee80211_tx_skb+0x3c/0x43 [mac80211]
[  254.251577]  [<f87c759c>] ? ieee80211_send_probe_req+0xdb/0xeb [mac80211]
[  254.251634]  [<f87b8b84>] ? ieee80211_mgd_probe_ap_send+0x35/0x6e [mac80211]
[  254.251686]  [<f87b9c13>] ? ieee80211_mgd_probe_ap+0xac/0xba [mac80211]
[  254.251708]  [<c10403b1>] ? process_one_work+0x181/0x25e
[  254.251763]  [<f87b9c21>] ? ieee80211_sta_monitor_work+0x0/0xc [mac80211]
[  254.251783]  [<c1041907>] ? worker_thread+0xf3/0x1f4
[  254.251800]  [<c1041814>] ? worker_thread+0x0/0x1f4
[  254.251816]  [<c1043f49>] ? kthread+0x63/0x68
[  254.251831]  [<c1043ee6>] ? kthread+0x0/0x68
[  254.251848]  [<c100353e>] ? kernel_thread_helper+0x6/0x10
[  254.251862] ---[ end trace e9ed04a305514143 ]---
[  254.269440] wireless led should be on
[  254.270687] wireless led = 0x01
[  254.271941] brightness = 0x08
[  254.748101] ops->tx called while down
[  254.748114] ops->tx called while down
[  254.748121] ops->tx called while down
[  254.748127] ops->tx called while down
[  254.748132] ops->tx called while down
[  254.748138] ops->tx called while down
[  254.748144] ops->tx called while down
[  254.748150] ops->tx called while down
[  254.748155] ops->tx called while down
[  254.748161] ops->tx called while down
[  254.748167] ops->tx called while down
[  254.748173] ------------[ cut here ]------------
[  254.748225] WARNING: at /home/nick/projects/kernel.org/linus/linux-2.6/net/mac80211/tx.c:1490 ieee80211_tx+0x16c/0x18a [mac80211]()
[  254.748235] Hardware name: N230                       
[  254.748241] tx refused but queue active
[  254.748247] Modules linked in: samsung_laptop aes_i586 aes_generic i915 drm_kms_helper drm i2c_algo_bit parport_pc ppdev lp parport sco acpi_cpufreq mperf bridge stp cpufreq_stats bnep cpufreq_userspace cpufreq_conservative cpufreq_powersave rfcomm l2cap vboxnetadp vboxnetflt vboxdrv uinput fuse ext4 jbd2 crc16 loop dm_crypt dm_mod arc4 ecb snd_hda_codec_realtek snd_hda_intel brcm80211(C) snd_hda_codec uvcvideo btusb joydev videodev snd_hwdep snd_pcm mac80211 snd_seq snd_timer snd_seq_device snd cfg80211 evdev bluetooth i2c_i801 v4l1_compat tpm_tis soundcore snd_page_alloc tpm video psmouse i2c_core tpm_bios rfkill processor output pcspkr battery button serio_raw shpchp pci_hotplug ac ext3 jbd mbcache raid10 raid456 async_raid6_recov async_pq raid6_pq async_xor xor async_memcpy async_tx raid1 raid0 multipath linear md_mod sd_mod crc_t10dif ahci uhci_hcd libahci libata ehci_hcd usbcore scsi_mod sky2 thermal thermal_sys nls_base [last unloaded: samsung_laptop]
[  254.748499] Pid: 189, comm: kworker/u:2 Tainted: G        WC  2.6.37+ #3
[  254.748506] Call Trace:
[  254.748525]  [<c102f079>] ? warn_slowpath_common+0x6a/0x7b
[  254.748567]  [<f87c43a9>] ? ieee80211_tx+0x16c/0x18a [mac80211]
[  254.748581]  [<c102f0f0>] ? warn_slowpath_fmt+0x28/0x2c
[  254.748622]  [<f87c43a9>] ? ieee80211_tx+0x16c/0x18a [mac80211]
[  254.748666]  [<f87c454b>] ? ieee80211_xmit+0x184/0x18c [mac80211]
[  254.748705]  [<f87c4801>] ? ieee80211_probereq_get+0xd7/0xeb [mac80211]
[  254.748745]  [<f87c458f>] ? ieee80211_tx_skb+0x3c/0x43 [mac80211]
[  254.748784]  [<f87c759c>] ? ieee80211_send_probe_req+0xdb/0xeb [mac80211]
[  254.748821]  [<f87b8b84>] ? ieee80211_mgd_probe_ap_send+0x35/0x6e [mac80211]
[  254.748857]  [<f87b8c4b>] ? ieee80211_sta_work+0x8e/0x125 [mac80211]
[  254.748871]  [<c10403b1>] ? process_one_work+0x181/0x25e
[  254.748909]  [<f87bcd13>] ? ieee80211_iface_work+0x0/0x266 [mac80211]
[  254.748922]  [<c1041907>] ? worker_thread+0xf3/0x1f4
[  254.748934]  [<c1041814>] ? worker_thread+0x0/0x1f4
[  254.748945]  [<c1043f49>] ? kthread+0x63/0x68
[  254.748956]  [<c1043ee6>] ? kthread+0x0/0x68
[  254.748969]  [<c100353e>] ? kernel_thread_helper+0x6/0x10
[  254.748978] ---[ end trace e9ed04a305514144 ]---
[  256.748114] ieee80211 phy0: wlan0: No probe response from AP 00:02:61:48:cb:bc after 500ms, disconnecting.
[  256.751615] Associated:	False
[  256.780783] cfg80211: Calling CRDA to update world regulatory domain
[  257.873874] wlan0: authenticate with 00:02:61:48:cb:bc (try 1)
[  257.875646] wlan0: authenticated
[  257.875718] wlan0: associate with 00:02:61:48:cb:bc (try 1)
[  257.883091] wlan0: RX AssocResp from 00:02:61:48:cb:bc (capab=0x431 status=0 aid=1)
[  257.883098] wlan0: associated
[  257.883990] Associated:	True
[  257.884551] cfg80211: Calling CRDA for country: NA

[-- Attachment #3: n230_modinfo.txt --]
[-- Type: text/plain, Size: 1788 bytes --]

filename:       /lib/modules/2.6.37+/kernel/drivers/platform/x86/samsung-laptop.ko
license:        GPL
description:    Samsung Backlight driver
author:         Greg Kroah-Hartman <gregkh@suse.de>
alias:          dmi*:svn*SAMSUNGELECTRONICSCO.,LTD.*:pn*P460*:rn*P460*:
alias:          dmi*:svn*SAMSUNGELECTRONICSCO.,LTD.*:pn*R70/R71*:rn*R70/R71*:
alias:          dmi*:svn*SAMSUNGELECTRONICSCO.,LTD.*:pn*N145P/N250P/N260P*:rn*N145P/N250P/N260P*:
alias:          dmi*:svn*SAMSUNGELECTRONICSCO.,LTD.*:pn*NF110/NF210/NF310*:rn*NF110/NF210/NF310*:
alias:          dmi*:svn*SAMSUNGELECTRONICSCO.,LTD.*:pn*R530/R730*:rn*R530/R730*:
alias:          dmi*:svn*SAMSUNGELECTRONICSCO.,LTD.*:pn*N150P/N210P/N220P*:rn*N150P/N210P/N220P*:
alias:          dmi*:svn*SAMSUNGELECTRONICSCO.,LTD.*:pn*N150/N210/N220/N230*:rn*N150/N210/N220/N230*:
alias:          dmi*:svn*SAMSUNGELECTRONICSCO.,LTD.*:pn*R519/R719*:rn*R519/R719*:
alias:          dmi*:svn*SAMSUNGELECTRONICSCO.,LTD.*:pn*R518*:rn*R518*:
alias:          dmi*:svn*SAMSUNGELECTRONICSCO.,LTD.*:pn*R410P*:rn*R460*:
alias:          dmi*:svn*SAMSUNGELECTRONICSCO.,LTD.*:pn*X360*:rn*X360*:
alias:          dmi*:svn*SAMSUNGELECTRONICSCO.,LTD.*:pn*SQ45S70S*:rn*SQ45S70S*:
alias:          dmi*:svn*SAMSUNGELECTRONICSCO.,LTD.*:pn*NC10*:rn*NC10*:
alias:          dmi*:svn*SAMSUNGELECTRONICSCO.,LTD.*:pn*X120/X170*:rn*X120/X170*:
alias:          dmi*:svn*SAMSUNGELECTRONICSCO.,LTD.*:pn*X125*:rn*X125*:
alias:          dmi*:svn*SAMSUNGELECTRONICSCO.,LTD.*:pn*N130*:rn*N130*:
alias:          dmi*:svn*SAMSUNGELECTRONICSCO.,LTD.*:pn*N128*:rn*N128*:
depends:        rfkill
vermagic:       2.6.37+ SMP mod_unload modversions 686 
parm:           force:Disable the DMI check and forces the driver to be loaded (bool)
parm:           debug:Debug enabled or not (bool)

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-11 20:20                                 ` Nikolai Kondrashov
@ 2011-03-11 20:23                                   ` Nikolai Kondrashov
  2011-03-11 20:35                                     ` Greg KH
  2011-03-11 20:30                                   ` Greg KH
  1 sibling, 1 reply; 53+ messages in thread
From: Nikolai Kondrashov @ 2011-03-11 20:23 UTC (permalink / raw)
  To: Greg KH; +Cc: Matthew Garrett, Randy Dunlap, linux-kernel, platform-driver-x86

On 03/11/2011 10:20 PM, Nikolai Kondrashov wrote:
> It fails to insert without "force" with the same message. With force it
> installs, but doesn't seem to work, at least for brightness buttons.
Oh, and upon insertion both backlight and WLAN LED turn off and then 
back on again, indeed.

Sincerely,
Nick

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-11 20:20                                 ` Nikolai Kondrashov
  2011-03-11 20:23                                   ` Nikolai Kondrashov
@ 2011-03-11 20:30                                   ` Greg KH
  2011-03-13 10:03                                     ` Nikolai Kondrashov
  1 sibling, 1 reply; 53+ messages in thread
From: Greg KH @ 2011-03-11 20:30 UTC (permalink / raw)
  To: Nikolai Kondrashov
  Cc: Matthew Garrett, Randy Dunlap, linux-kernel, platform-driver-x86

On Fri, Mar 11, 2011 at 10:20:41PM +0200, Nikolai Kondrashov wrote:
> On 03/11/2011 09:34 PM, Greg KH wrote:
> >Ok, this shows you are not loading the driver I sent to you, this is the
> >"original" one I sent, which will fail for your machine.
> Sorry, I didn't know the old version was still there.
> For some reason until I removed the staging samsung-laptop from the
> Makefile, the new one didn't get installed.
> 
> >You need to build and install the one I sent you.
> Done. So far tested on n230 only.
> 
> It fails to insert without "force" with the same message. With force it
> installs, but doesn't seem to work, at least for brightness buttons.

The brightness button hookup is in userspace, and odds are that's not
working right, you need newer gnome to handle that.

But, when you insert this with "debug=1" does the screen turn off and
then on?

You can also go into the /sys/class/backlight/samsung/ directory and
mess with the backlight values in the files to see if it gets brighter
and dimmer.  If that works, then the driver is working properly.

I'll work on getting the "force" thing to work properly, as I think I'll
just enable this for all Samsung laptops as Matthew recommends.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-11 20:23                                   ` Nikolai Kondrashov
@ 2011-03-11 20:35                                     ` Greg KH
  0 siblings, 0 replies; 53+ messages in thread
From: Greg KH @ 2011-03-11 20:35 UTC (permalink / raw)
  To: Nikolai Kondrashov
  Cc: Matthew Garrett, Randy Dunlap, linux-kernel, platform-driver-x86

On Fri, Mar 11, 2011 at 10:23:41PM +0200, Nikolai Kondrashov wrote:
> On 03/11/2011 10:20 PM, Nikolai Kondrashov wrote:
> >It fails to insert without "force" with the same message. With force it
> >installs, but doesn't seem to work, at least for brightness buttons.
> Oh, and upon insertion both backlight and WLAN LED turn off and then
> back on again, indeed.

Ah, good, thanks for letting me know, that means it is working properly.

greg k-h

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-11 20:30                                   ` Greg KH
@ 2011-03-13 10:03                                     ` Nikolai Kondrashov
  2011-03-13 10:55                                       ` Richard Schütz
  2011-03-13 16:17                                       ` Greg KH
  0 siblings, 2 replies; 53+ messages in thread
From: Nikolai Kondrashov @ 2011-03-13 10:03 UTC (permalink / raw)
  To: Greg KH; +Cc: Matthew Garrett, Randy Dunlap, linux-kernel, platform-driver-x86

Hi Greg,

On 03/11/2011 10:30 PM, Greg KH wrote:
> You can also go into the /sys/class/backlight/samsung/ directory and
> mess with the backlight values in the files to see if it gets brighter
> and dimmer.  If that works, then the driver is working properly.
Thanks :)
I see some strange behavior, though.

Every time I execute this in the /sys/class/backlight/samsung directory:
sudo bash -c 'echo 1 > brightness'
brightness is reduced a little until it reaches the minimum.

After that, every time I execute this:
sudo bash -c 'echo 8 > brightness'
it increases a little until it reaches the maximum.

And each time a message appears in dmesg: "ACPI: Failed to switch the
brightness", until the brightness stops changing.

At the same time, the little Gnome brightness adjustment window appears,
showing the percentage of the brightness, which drops/raises to
minimum/maximum in only four executions of these commands. After that, while
brightness drops/raises with each execution, the percentage stays at
minimum/maximum.

Is this all normal?

Also, brightness buttons seem to invoke the Gnome brightness percentage
window, which shows it changing, but the brightness itself doesn't change.
Is it also normal? If so, is it solved in the newer Gnome and is it what you
tried to tell me before?

Sometime ago I've found this hack on some forum, which I use currently
to set the brightness:

setpci -s 00:02.0 f4.b="$HEX_BYTE"

It allows finer control of the brightness, but it seems it operates directly
on the video card PCI register. I assume there is no sane way to use
this interface from the platform driver, right?

Then, does the wireless on/off button require gnome support too?

Thank you very much :)

Sincerely,
Nick

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-13 10:03                                     ` Nikolai Kondrashov
@ 2011-03-13 10:55                                       ` Richard Schütz
  2011-03-13 13:02                                         ` Nikolai Kondrashov
  2011-03-13 16:17                                       ` Greg KH
  1 sibling, 1 reply; 53+ messages in thread
From: Richard Schütz @ 2011-03-13 10:55 UTC (permalink / raw)
  To: Nikolai Kondrashov
  Cc: Greg KH, Matthew Garrett, Randy Dunlap, linux-kernel,
	platform-driver-x86

> Every time I execute this in the /sys/class/backlight/samsung directory:
> sudo bash -c 'echo 1 > brightness'
> brightness is reduced a little until it reaches the minimum.
>
> After that, every time I execute this:
> sudo bash -c 'echo 8 > brightness'
> it increases a little until it reaches the maximum.
>
> And each time a message appears in dmesg: "ACPI: Failed to switch the
> brightness", until the brightness stops changing.
>
> At the same time, the little Gnome brightness adjustment window appears,
> showing the percentage of the brightness, which drops/raises to
> minimum/maximum in only four executions of these commands. After that,
> while
> brightness drops/raises with each execution, the percentage stays at
> minimum/maximum.
>
> Is this all normal?

That sounds like the driver is interfering with the ACPI video driver. 
Add "acpi_backlight=vendor" to your kernel boot parameters and try again.

-- 
Regards,
Richard Schütz

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-13 10:55                                       ` Richard Schütz
@ 2011-03-13 13:02                                         ` Nikolai Kondrashov
  2011-03-13 16:18                                           ` Greg KH
  0 siblings, 1 reply; 53+ messages in thread
From: Nikolai Kondrashov @ 2011-03-13 13:02 UTC (permalink / raw)
  To: Richard Schütz
  Cc: Greg KH, Matthew Garrett, Randy Dunlap, linux-kernel,
	platform-driver-x86

On 03/13/2011 12:55 PM, Richard Schütz wrote:
> That sounds like the driver is interfering with the ACPI video driver.
> Add "acpi_backlight=vendor" to your kernel boot parameters and try again.
Thank you, this helped :)

Greg, is it OK that both 0 and 1 backlight values have the same effect on
brightness?

Thanks.

Sincerely,
Nick

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-13 10:03                                     ` Nikolai Kondrashov
  2011-03-13 10:55                                       ` Richard Schütz
@ 2011-03-13 16:17                                       ` Greg KH
  2011-03-13 16:28                                         ` Matthew Garrett
  2011-03-13 17:50                                         ` Nikolai Kondrashov
  1 sibling, 2 replies; 53+ messages in thread
From: Greg KH @ 2011-03-13 16:17 UTC (permalink / raw)
  To: Nikolai Kondrashov
  Cc: Matthew Garrett, Randy Dunlap, linux-kernel, platform-driver-x86

On Sun, Mar 13, 2011 at 12:03:20PM +0200, Nikolai Kondrashov wrote:
> Sometime ago I've found this hack on some forum, which I use currently
> to set the brightness:
> 
> setpci -s 00:02.0 f4.b="$HEX_BYTE"
> 
> It allows finer control of the brightness, but it seems it operates directly
> on the video card PCI register. I assume there is no sane way to use
> this interface from the platform driver, right?

Yes, do not do this, it causes all sorts of problems in the end, not the
least being the BIOS doesn't know what is going on at all as you are
changing the brightness without it knowing it.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-13 13:02                                         ` Nikolai Kondrashov
@ 2011-03-13 16:18                                           ` Greg KH
  2011-03-13 17:49                                             ` Nikolai Kondrashov
  0 siblings, 1 reply; 53+ messages in thread
From: Greg KH @ 2011-03-13 16:18 UTC (permalink / raw)
  To: Nikolai Kondrashov
  Cc: Richard Schütz, Matthew Garrett, Randy Dunlap, linux-kernel,
	platform-driver-x86

On Sun, Mar 13, 2011 at 03:02:00PM +0200, Nikolai Kondrashov wrote:
> On 03/13/2011 12:55 PM, Richard Schütz wrote:
> >That sounds like the driver is interfering with the ACPI video driver.
> >Add "acpi_backlight=vendor" to your kernel boot parameters and try again.
> Thank you, this helped :)
> 
> Greg, is it OK that both 0 and 1 backlight values have the same effect on
> brightness?

I really don't know, sorry.  Try messing with the actual_brightness file
instead, that's the one to use.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-13 16:17                                       ` Greg KH
@ 2011-03-13 16:28                                         ` Matthew Garrett
  2011-03-13 17:51                                           ` Nikolai Kondrashov
  2011-03-13 17:50                                         ` Nikolai Kondrashov
  1 sibling, 1 reply; 53+ messages in thread
From: Matthew Garrett @ 2011-03-13 16:28 UTC (permalink / raw)
  To: Greg KH
  Cc: Nikolai Kondrashov, Randy Dunlap, linux-kernel, platform-driver-x86

On Sun, Mar 13, 2011 at 09:17:53AM -0700, Greg KH wrote:
> On Sun, Mar 13, 2011 at 12:03:20PM +0200, Nikolai Kondrashov wrote:
> > Sometime ago I've found this hack on some forum, which I use currently
> > to set the brightness:
> > 
> > setpci -s 00:02.0 f4.b="$HEX_BYTE"
> > 
> > It allows finer control of the brightness, but it seems it operates directly
> > on the video card PCI register. I assume there is no sane way to use
> > this interface from the platform driver, right?
> 
> Yes, do not do this, it causes all sorts of problems in the end, not the
> least being the BIOS doesn't know what is going on at all as you are
> changing the brightness without it knowing it.

It's also modifying configuration that belongs to a device being managed 
by another driver, so it's the kind of thing we frown upon. Having said 
that, the Intel driver should gain native backlight support in .39.

-- 
Matthew Garrett | mjg59@srcf.ucam.org

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-13 16:18                                           ` Greg KH
@ 2011-03-13 17:49                                             ` Nikolai Kondrashov
  2011-03-13 17:58                                               ` Greg KH
  0 siblings, 1 reply; 53+ messages in thread
From: Nikolai Kondrashov @ 2011-03-13 17:49 UTC (permalink / raw)
  To: Greg KH
  Cc: Richard Schütz, Matthew Garrett, Randy Dunlap, linux-kernel,
	platform-driver-x86

On 03/13/2011 06:18 PM, Greg KH wrote:
> I really don't know, sorry.  Try messing with the actual_brightness file
> instead, that's the one to use.
Sure, thank you :)

Still, what about the wireless on/off button? Is Gnome support required, or
it should work as is? Because mine doesn't seem to do anything.

Thanks.

Sincerely,
Nick

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-13 16:17                                       ` Greg KH
  2011-03-13 16:28                                         ` Matthew Garrett
@ 2011-03-13 17:50                                         ` Nikolai Kondrashov
  1 sibling, 0 replies; 53+ messages in thread
From: Nikolai Kondrashov @ 2011-03-13 17:50 UTC (permalink / raw)
  To: Greg KH; +Cc: Matthew Garrett, Randy Dunlap, linux-kernel, platform-driver-x86

On 03/13/2011 06:17 PM, Greg KH wrote:
> Yes, do not do this, it causes all sorts of problems in the end, not the
> least being the BIOS doesn't know what is going on at all as you are
> changing the brightness without it knowing it.
Sure.
It's just there wasn't any other way before your driver.

Thank you :)

Sincerely,
Nick

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-13 16:28                                         ` Matthew Garrett
@ 2011-03-13 17:51                                           ` Nikolai Kondrashov
  0 siblings, 0 replies; 53+ messages in thread
From: Nikolai Kondrashov @ 2011-03-13 17:51 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: Greg KH, Randy Dunlap, linux-kernel, platform-driver-x86

On 03/13/2011 06:28 PM, Matthew Garrett wrote:
> It's also modifying configuration that belongs to a device being managed
> by another driver, so it's the kind of thing we frown upon.
Sure, then I guessed right.

> Having said that, the Intel driver should gain native backlight support in
> .39.
Great news!

Thank you :)

Sincerely,
Nick

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-13 17:49                                             ` Nikolai Kondrashov
@ 2011-03-13 17:58                                               ` Greg KH
  0 siblings, 0 replies; 53+ messages in thread
From: Greg KH @ 2011-03-13 17:58 UTC (permalink / raw)
  To: Nikolai Kondrashov
  Cc: Richard Schütz, Matthew Garrett, Randy Dunlap, linux-kernel,
	platform-driver-x86

On Sun, Mar 13, 2011 at 07:49:04PM +0200, Nikolai Kondrashov wrote:
> On 03/13/2011 06:18 PM, Greg KH wrote:
> >I really don't know, sorry.  Try messing with the actual_brightness file
> >instead, that's the one to use.
> Sure, thank you :)
> 
> Still, what about the wireless on/off button? Is Gnome support required, or
> it should work as is? Because mine doesn't seem to do anything.

It should "just work", as it does on my machine, but I'm running a very
new Gnome, so it might have hooks to look at the rfkill stuff built in.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
@ 2011-06-26 15:08 J Witteveen
  0 siblings, 0 replies; 53+ messages in thread
From: J Witteveen @ 2011-06-26 15:08 UTC (permalink / raw)
  To: mjg; +Cc: platform-driver-x86, linux-kernel

On Fri, Feb 11, 2011 at 10:17, Jouke Witteveen <j.witteveen@gmail.com> wrote:
> On Wed, Feb 9, 2011 at 23:40, Greg KH <greg@kroah.com> wrote:
>> From: Greg Kroah-Hartman <gregkh@suse.de>
>>
>> This adds the samsung-laptop driver to the kernel.  It now supports
>> all known Samsung laptops.
>>
>
> I don't see the N510, is this intentional? The netbook does not differ
> that much from some that are included.
>

The N510 benefits from this code as well. Below is a patch to include support.

Signed-off-by: Jouke Witteveen <j.witteveen@gmail.com>

Thanks,
- Jouke

--- a/drivers/platform/x86/samsung-laptop.c	2011-06-26 16:18:06.517840468 +0200
+++ b/drivers/platform/x86/samsung-laptop.c	2011-06-26 16:19:14.677574644 +0200
@@ -521,6 +521,16 @@ static struct dmi_system_id __initdata s
 		.callback = dmi_check_cb,
 	},
 	{
+		.ident = "N510",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N510"),
+			DMI_MATCH(DMI_BOARD_NAME, "N510"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
 		.ident = "X125",
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR,


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-11 19:55         ` Matthew Garrett
@ 2011-03-14 15:18           ` Jörg-Volker Peetz
  0 siblings, 0 replies; 53+ messages in thread
From: Jörg-Volker Peetz @ 2011-03-14 15:18 UTC (permalink / raw)
  To: linux-kernel

[-- Attachment #1: Type: text/plain, Size: 926 bytes --]

Hi Matthew,

concering the hp-wmi driver I would like to answer a few questions.

My GNU/Linux Debian system with a self compiled custom kernel 2.6.37.3 is
running on a HP Pavilion DV7-4151sg notebook (dmidecode output, DSDT, and kernel
config attached).
I activated the driver on my HP notebook in order to achieve several goals:
(1) make the rfkill hardware button work
    (seems to work according to the output of rfkill list and acpi_listen)
(2) make the buttons for lowering and increasing display brightness work
    (do not work, no output with acpi_listen)
(3) the display back side has an illuminated "hp" logo which I would like to
    be able to switch off (alone or together with the display) to save a
    little energy
How can I found out if these functionality is achievable via ACPI WMI functions
or somehow else?
What would I have to change in hp-wmi.c?

Any help is appreciated.
Best regards,
Jörg-Volker.


[-- Attachment #2: DSDT.dsl.gz --]
[-- Type: application/x-tar, Size: 41119 bytes --]

[-- Attachment #3: config-2.6.37.3.gz --]
[-- Type: application/x-tar, Size: 13639 bytes --]

[-- Attachment #4: dmidecode.gz --]
[-- Type: application/x-tar, Size: 2226 bytes --]

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-11 19:52       ` Greg KH
@ 2011-03-11 19:55         ` Matthew Garrett
  2011-03-14 15:18           ` Jörg-Volker Peetz
  0 siblings, 1 reply; 53+ messages in thread
From: Matthew Garrett @ 2011-03-11 19:55 UTC (permalink / raw)
  To: Greg KH; +Cc: Randy Dunlap, linux-kernel, platform-driver-x86

On Fri, Mar 11, 2011 at 11:52:21AM -0800, Greg KH wrote:

> I wouldn't mind just doing a DMI match on all Samsung laptops, it would
> save me having to constantly send patch updates, so I'll let this be
> your call :)

I think it'd be worth a go, at least. dell-laptop has example alias 
lines for that, there's a few different DMI classes that can be used for 
laptops so you'd need to check which one Samsung are using.

-- 
Matthew Garrett | mjg59@srcf.ucam.org

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-11 19:44     ` Matthew Garrett
@ 2011-03-11 19:52       ` Greg KH
  2011-03-11 19:55         ` Matthew Garrett
  0 siblings, 1 reply; 53+ messages in thread
From: Greg KH @ 2011-03-11 19:52 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: Randy Dunlap, linux-kernel, platform-driver-x86

On Fri, Mar 11, 2011 at 07:44:22PM +0000, Matthew Garrett wrote:
> On Fri, Mar 11, 2011 at 11:35:12AM -0800, Greg KH wrote:
> > On Fri, Mar 11, 2011 at 05:43:39PM +0000, Matthew Garrett wrote:
> > > Applied, thanks.
> > 
> > Great, any pointers to where it was applied?  I think I need to send you
> > a few more 'add a new device id' patches and I want to make sure I get
> > the right version to patch against.
> 
> http://git.kernel.org/?p=linux/kernel/git/mjg59/platform-drivers-x86.git;a=shortlog;h=refs/heads/linux-next 

Thanks.

> - ideally we'd just have it id against all Samsung laptops and check for 
> SABI? Or are there machines where that might break?

I thought all samsung laptops had SABI, but as the other samsung laptop
driver shows, that's not true.

I don't know what happens if we try to check for SABI on those machines.
We are just rooting around in the BIOS rom and reading values,
_hopefully_ that wouldn't break any other machines, but I don't really
know.

I wouldn't mind just doing a DMI match on all Samsung laptops, it would
save me having to constantly send patch updates, so I'll let this be
your call :)

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-11 19:35   ` Greg KH
@ 2011-03-11 19:44     ` Matthew Garrett
  2011-03-11 19:52       ` Greg KH
  0 siblings, 1 reply; 53+ messages in thread
From: Matthew Garrett @ 2011-03-11 19:44 UTC (permalink / raw)
  To: Greg KH; +Cc: Randy Dunlap, linux-kernel, platform-driver-x86

On Fri, Mar 11, 2011 at 11:35:12AM -0800, Greg KH wrote:
> On Fri, Mar 11, 2011 at 05:43:39PM +0000, Matthew Garrett wrote:
> > Applied, thanks.
> 
> Great, any pointers to where it was applied?  I think I need to send you
> a few more 'add a new device id' patches and I want to make sure I get
> the right version to patch against.

http://git.kernel.org/?p=linux/kernel/git/mjg59/platform-drivers-x86.git;a=shortlog;h=refs/heads/linux-next 
- ideally we'd just have it id against all Samsung laptops and check for 
SABI? Or are there machines where that might break?

-- 
Matthew Garrett | mjg59@srcf.ucam.org

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-11 17:43 ` Matthew Garrett
@ 2011-03-11 19:35   ` Greg KH
  2011-03-11 19:44     ` Matthew Garrett
  0 siblings, 1 reply; 53+ messages in thread
From: Greg KH @ 2011-03-11 19:35 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: Randy Dunlap, linux-kernel, platform-driver-x86

On Fri, Mar 11, 2011 at 05:43:39PM +0000, Matthew Garrett wrote:
> Applied, thanks.

Great, any pointers to where it was applied?  I think I need to send you
a few more 'add a new device id' patches and I want to make sure I get
the right version to patch against.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
@ 2011-03-11 17:57 Tommaso Massimi
  0 siblings, 0 replies; 53+ messages in thread
From: Tommaso Massimi @ 2011-03-11 17:57 UTC (permalink / raw)
  To: linux-kernel

On 03/10/2011 08:09 PM, Greg KH wrote:
>On Thu, Mar 10, 2011 at 07:28:00PM +0200, Nikolai Kondrashov wrote:
> > On 03/10/2011 07:19 PM, Greg KH wrote:
> > >Can you provide me the output of:
> > > grep . /sys/class/dmi/id/*
> > >so I can try to add support for this machine to the driver?
> > Sure, here it is.
>
> Great, here's a new version of the samsung-laptop.c file, can you
> replace it whereever you were building the previous one, rebuild it and
> test it for this machine to see if it works?

Hi,
here the output you required from my laptop:

tom@localhost tom_samsung]$ grep . /sys/class/dmi/id/*
/sys/class/dmi/id/bios_date:09/21/2009
/sys/class/dmi/id/bios_vendor:Phoenix Technologies Ltd.
/sys/class/dmi/id/bios_version:04IA.M005.20090921.KSY
/sys/class/dmi/id/board_name:X420/X520
grep: /sys/class/dmi/id/board_serial: Permission denied
/sys/class/dmi/id/board_vendor:SAMSUNG ELECTRONICS CO., LTD.
/sys/class/dmi/id/board_version:Not Applicable
/sys/class/dmi/id/chassis_asset_tag:No Asset Tag
grep: /sys/class/dmi/id/chassis_serial: Permission denied
/sys/class/dmi/id/chassis_type:10
/sys/class/dmi/id/chassis_vendor:SAMSUNG ELECTRONICS CO., LTD.
/sys/class/dmi/id/chassis_version:N/A
/sys/class/dmi/id/modalias:dmi:bvnPhoenixTechnologiesLtd.:bvr04IA.M005.20090921.KSY:bd09/21/2009:svnSAMSUNGELECTRONICSCO.,LTD.:pnX420/X520:pvrNotApplicable:rvnSAMSUNGELECTRONICSCO.,LTD.:rnX420/X520:rvrNotApplicable:cvnSAMSUNGELECTRONICSCO.,LTD.:ct10:cvrN/A:
/sys/class/dmi/id/product_name:X420/X520
grep: /sys/class/dmi/id/product_serial: Permission denied
grep: /sys/class/dmi/id/product_uuid: Permission denied
/sys/class/dmi/id/product_version:Not Applicable
/sys/class/dmi/id/sys_vendor:SAMSUNG ELECTRONICS CO., LTD.
/sys/class/dmi/id/uevent:MODALIAS=dmi:bvnPhoenixTechnologiesLtd.:bvr04IA.M005.20090921.KSY:bd09/21/2009:svnSAMSUNGELECTRONICSCO.,LTD.:pnX420/X520:pvrNotApplicable:rvnSAMSUNGELECTRONICSCO.,LTD.:rnX420/X520:rvrNotApplicable:cvnSAMSUNGELECTRONICSCO.,LTD.:ct10:cvrN/A:

I have added these lines to your source file

668a669,677
>               {
>               .ident = "X520",
>               .matches = {
>                       DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
>                       DMI_MATCH(DMI_PRODUCT_NAME, "X520"),
>                       DMI_MATCH(DMI_BOARD_NAME, "X520"),
>               },
>               .callback = dmi_check_cb,
>       },

When I load the module with the option debug=1,
it turns on and off my backligth and my wireless card,
so I think it is working fine.
Here what dmesg says:

samsung_laptop: module is from the staging directory, the quality is
unknown, you have been warned.
samsung_laptop: found laptop model 'X520'
This computer supports SABI==f48b4
SABI header:
 SMI Port Number = 0x00b2
 SMI Interface Function = 0xc0
 SMI enable memory buffer = 0xc1
 SMI restore memory buffer = 0xc2
 SABI data offset = 0x0f00
 SABI data segment = 0xdf01
ifaceP = 0x000dff10
sabi_iface = ffff8800000dff10
backlight = 0x01
backlight should be off
backlight = 0x00
backlight should be on
backlight = 0x01
wireless led = 0x01
wireless led should be off
wireless led = 0x00
wireless led should be on
wireless led = 0x01
brightness = 0x08
atkbd serio0: Unknown key pressed (translated set 2, code 0x89 on
isa0060/serio0).
atkbd serio0: Use 'setkeycodes e009 <keycode>' to make it known.

Now I think I need only to use the setkeycodes command to have
these new commands under my fingers :)

Thanks for that!!

Tom

PS: I'm not subscribed to the list, so please CC me if you need some other info

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH] Platform: add Samsung Laptop platform driver
  2011-03-05  4:24 Greg KH
@ 2011-03-11 17:43 ` Matthew Garrett
  2011-03-11 19:35   ` Greg KH
  0 siblings, 1 reply; 53+ messages in thread
From: Matthew Garrett @ 2011-03-11 17:43 UTC (permalink / raw)
  To: Greg KH; +Cc: Randy Dunlap, linux-kernel, platform-driver-x86

Applied, thanks.

-- 
Matthew Garrett | mjg59@srcf.ucam.org

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH] Platform: add Samsung Laptop platform driver
@ 2011-03-05  4:24 Greg KH
  2011-03-11 17:43 ` Matthew Garrett
  0 siblings, 1 reply; 53+ messages in thread
From: Greg KH @ 2011-03-05  4:24 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: Randy Dunlap, linux-kernel, platform-driver-x86

From: Greg Kroah-Hartman <gregkh@suse.de>

This adds the samsung-laptop driver to the kernel.  It now supports
all known Samsung laptops that use the SABI interface.

Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 Documentation/ABI/testing/sysfs-driver-samsung-laptop |   19 
 drivers/platform/x86/Kconfig                          |   13 
 drivers/platform/x86/Makefile                         |    1 
 drivers/platform/x86/samsung-laptop.c                 |  832 ++++++++++++++++++
 4 files changed, 865 insertions(+)

Matthew, this is a copy of the latest version in the linux-next tree of the
driver.  Once it has been accepted into your tree, I'll delete the
staging driver.  Or, if you want to give your ACK, I can just move the
driver from staging into this directory in my tree, which will properly
preserve the history of the code.

v2 - I have also addressed all of the review comments you gave me
     previously, and fixed a bug in the previous version that broke the
     driver on the N128 laptop, as well as added support for a wide
     range of other laptops thanks to many testers who sent in patches.

v3 - Added a few more device ids, const changes, and now supports
     variable brightness levels as not all laptops are the same with
     this.


diff --git a/Documentation/ABI/testing/sysfs-driver-samsung-laptop b/Documentation/ABI/testing/sysfs-driver-samsung-laptop
new file mode 100644
index 0000000..0a81023
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-samsung-laptop
@@ -0,0 +1,19 @@
+What:		/sys/devices/platform/samsung/performance_level
+Date:		January 1, 2010
+KernelVersion:	2.6.33
+Contact:	Greg Kroah-Hartman <gregkh@suse.de>
+Description:	Some Samsung laptops have different "performance levels"
+		that are can be modified by a function key, and by this
+		sysfs file.  These values don't always make a whole lot
+		of sense, but some users like to modify them to keep
+		their fans quiet at all costs.  Reading from this file
+		will show the current performance level.  Writing to the
+		file can change this value.
+			Valid options:
+				"silent"
+				"normal"
+				"overclock"
+		Note that not all laptops support all of these options.
+		Specifically, not all support the "overclock" option,
+		and it's still unknown if this value even changes
+		anything, other than making the user feel a bit better.
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index a59af5b..5624267 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -654,4 +654,17 @@ config XO1_RFKILL
 	  Support for enabling/disabling the WLAN interface on the OLPC XO-1
 	  laptop.
 
+config SAMSUNG_LAPTOP
+	tristate "Samsung Laptop driver"
+	depends on RFKILL && BACKLIGHT_CLASS_DEVICE && X86
+	---help---
+	  This module implements a driver for a wide range of different
+	  Samsung laptops.  It offers control over the different
+	  function keys, wireless LED, LCD backlight level, and
+	  sometimes provides a "performance_control" sysfs file to allow
+	  the performance level of the laptop to be changed.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called samsung-laptop.
+
 endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 4ec4ff8..ad2fb97 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -34,3 +34,4 @@ obj-$(CONFIG_INTEL_IPS)		+= intel_ips.o
 obj-$(CONFIG_GPIO_INTEL_PMIC)	+= intel_pmic_gpio.o
 obj-$(CONFIG_XO1_RFKILL)	+= xo1-rfkill.o
 obj-$(CONFIG_IBM_RTL)		+= ibm_rtl.o
+obj-$(CONFIG_SAMSUNG_LAPTOP)	+= samsung-laptop.o
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c
new file mode 100644
index 0000000..e0b390d
--- /dev/null
+++ b/drivers/platform/x86/samsung-laptop.c
@@ -0,0 +1,832 @@
+/*
+ * Samsung Laptop driver
+ *
+ * Copyright (C) 2009,2011 Greg Kroah-Hartman (gregkh@suse.de)
+ * Copyright (C) 2009,2011 Novell 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.
+ *
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+#include <linux/dmi.h>
+#include <linux/platform_device.h>
+#include <linux/rfkill.h>
+
+/*
+ * This driver is needed because a number of Samsung laptops do not hook
+ * their control settings through ACPI.  So we have to poke around in the
+ * BIOS to do things like brightness values, and "special" key controls.
+ */
+
+/*
+ * We have 0 - 8 as valid brightness levels.  The specs say that level 0 should
+ * be reserved by the BIOS (which really doesn't make much sense), we tell
+ * userspace that the value is 0 - 7 and then just tell the hardware 1 - 8
+ */
+#define MAX_BRIGHT	0x07
+
+
+#define SABI_IFACE_MAIN			0x00
+#define SABI_IFACE_SUB			0x02
+#define SABI_IFACE_COMPLETE		0x04
+#define SABI_IFACE_DATA			0x05
+
+/* Structure to get data back to the calling function */
+struct sabi_retval {
+	u8 retval[20];
+};
+
+struct sabi_header_offsets {
+	u8 port;
+	u8 re_mem;
+	u8 iface_func;
+	u8 en_mem;
+	u8 data_offset;
+	u8 data_segment;
+};
+
+struct sabi_commands {
+	/*
+	 * Brightness is 0 - 8, as described above.
+	 * Value 0 is for the BIOS to use
+	 */
+	u8 get_brightness;
+	u8 set_brightness;
+
+	/*
+	 * first byte:
+	 * 0x00 - wireless is off
+	 * 0x01 - wireless is on
+	 * second byte:
+	 * 0x02 - 3G is off
+	 * 0x03 - 3G is on
+	 * TODO, verify 3G is correct, that doesn't seem right...
+	 */
+	u8 get_wireless_button;
+	u8 set_wireless_button;
+
+	/* 0 is off, 1 is on */
+	u8 get_backlight;
+	u8 set_backlight;
+
+	/*
+	 * 0x80 or 0x00 - no action
+	 * 0x81 - recovery key pressed
+	 */
+	u8 get_recovery_mode;
+	u8 set_recovery_mode;
+
+	/*
+	 * on seclinux: 0 is low, 1 is high,
+	 * on swsmi: 0 is normal, 1 is silent, 2 is turbo
+	 */
+	u8 get_performance_level;
+	u8 set_performance_level;
+
+	/*
+	 * Tell the BIOS that Linux is running on this machine.
+	 * 81 is on, 80 is off
+	 */
+	u8 set_linux;
+};
+
+struct sabi_performance_level {
+	const char *name;
+	u8 value;
+};
+
+struct sabi_config {
+	const char *test_string;
+	u16 main_function;
+	const struct sabi_header_offsets header_offsets;
+	const struct sabi_commands commands;
+	const struct sabi_performance_level performance_levels[4];
+	u8 min_brightness;
+	u8 max_brightness;
+};
+
+static const struct sabi_config sabi_configs[] = {
+	{
+		.test_string = "SECLINUX",
+
+		.main_function = 0x4c49,
+
+		.header_offsets = {
+			.port = 0x00,
+			.re_mem = 0x02,
+			.iface_func = 0x03,
+			.en_mem = 0x04,
+			.data_offset = 0x05,
+			.data_segment = 0x07,
+		},
+
+		.commands = {
+			.get_brightness = 0x00,
+			.set_brightness = 0x01,
+
+			.get_wireless_button = 0x02,
+			.set_wireless_button = 0x03,
+
+			.get_backlight = 0x04,
+			.set_backlight = 0x05,
+
+			.get_recovery_mode = 0x06,
+			.set_recovery_mode = 0x07,
+
+			.get_performance_level = 0x08,
+			.set_performance_level = 0x09,
+
+			.set_linux = 0x0a,
+		},
+
+		.performance_levels = {
+			{
+				.name = "silent",
+				.value = 0,
+			},
+			{
+				.name = "normal",
+				.value = 1,
+			},
+			{ },
+		},
+		.min_brightness = 1,
+		.max_brightness = 8,
+	},
+	{
+		.test_string = "SwSmi@",
+
+		.main_function = 0x5843,
+
+		.header_offsets = {
+			.port = 0x00,
+			.re_mem = 0x04,
+			.iface_func = 0x02,
+			.en_mem = 0x03,
+			.data_offset = 0x05,
+			.data_segment = 0x07,
+		},
+
+		.commands = {
+			.get_brightness = 0x10,
+			.set_brightness = 0x11,
+
+			.get_wireless_button = 0x12,
+			.set_wireless_button = 0x13,
+
+			.get_backlight = 0x2d,
+			.set_backlight = 0x2e,
+
+			.get_recovery_mode = 0xff,
+			.set_recovery_mode = 0xff,
+
+			.get_performance_level = 0x31,
+			.set_performance_level = 0x32,
+
+			.set_linux = 0xff,
+		},
+
+		.performance_levels = {
+			{
+				.name = "normal",
+				.value = 0,
+			},
+			{
+				.name = "silent",
+				.value = 1,
+			},
+			{
+				.name = "overclock",
+				.value = 2,
+			},
+			{ },
+		},
+		.min_brightness = 0,
+		.max_brightness = 8,
+	},
+	{ },
+};
+
+static const struct sabi_config *sabi_config;
+
+static void __iomem *sabi;
+static void __iomem *sabi_iface;
+static void __iomem *f0000_segment;
+static struct backlight_device *backlight_device;
+static struct mutex sabi_mutex;
+static struct platform_device *sdev;
+static struct rfkill *rfk;
+
+static int force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force,
+		"Disable the DMI check and forces the driver to be loaded");
+
+static int debug;
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+static int sabi_get_command(u8 command, struct sabi_retval *sretval)
+{
+	int retval = 0;
+	u16 port = readw(sabi + sabi_config->header_offsets.port);
+	u8 complete, iface_data;
+
+	mutex_lock(&sabi_mutex);
+
+	/* enable memory to be able to write to it */
+	outb(readb(sabi + sabi_config->header_offsets.en_mem), port);
+
+	/* write out the command */
+	writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN);
+	writew(command, sabi_iface + SABI_IFACE_SUB);
+	writeb(0, sabi_iface + SABI_IFACE_COMPLETE);
+	outb(readb(sabi + sabi_config->header_offsets.iface_func), port);
+
+	/* write protect memory to make it safe */
+	outb(readb(sabi + sabi_config->header_offsets.re_mem), port);
+
+	/* see if the command actually succeeded */
+	complete = readb(sabi_iface + SABI_IFACE_COMPLETE);
+	iface_data = readb(sabi_iface + SABI_IFACE_DATA);
+	if (complete != 0xaa || iface_data == 0xff) {
+		pr_warn("SABI get command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n",
+		        command, complete, iface_data);
+		retval = -EINVAL;
+		goto exit;
+	}
+	/*
+	 * Save off the data into a structure so the caller use it.
+	 * Right now we only want the first 4 bytes,
+	 * There are commands that need more, but not for the ones we
+	 * currently care about.
+	 */
+	sretval->retval[0] = readb(sabi_iface + SABI_IFACE_DATA);
+	sretval->retval[1] = readb(sabi_iface + SABI_IFACE_DATA + 1);
+	sretval->retval[2] = readb(sabi_iface + SABI_IFACE_DATA + 2);
+	sretval->retval[3] = readb(sabi_iface + SABI_IFACE_DATA + 3);
+
+exit:
+	mutex_unlock(&sabi_mutex);
+	return retval;
+
+}
+
+static int sabi_set_command(u8 command, u8 data)
+{
+	int retval = 0;
+	u16 port = readw(sabi + sabi_config->header_offsets.port);
+	u8 complete, iface_data;
+
+	mutex_lock(&sabi_mutex);
+
+	/* enable memory to be able to write to it */
+	outb(readb(sabi + sabi_config->header_offsets.en_mem), port);
+
+	/* write out the command */
+	writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN);
+	writew(command, sabi_iface + SABI_IFACE_SUB);
+	writeb(0, sabi_iface + SABI_IFACE_COMPLETE);
+	writeb(data, sabi_iface + SABI_IFACE_DATA);
+	outb(readb(sabi + sabi_config->header_offsets.iface_func), port);
+
+	/* write protect memory to make it safe */
+	outb(readb(sabi + sabi_config->header_offsets.re_mem), port);
+
+	/* see if the command actually succeeded */
+	complete = readb(sabi_iface + SABI_IFACE_COMPLETE);
+	iface_data = readb(sabi_iface + SABI_IFACE_DATA);
+	if (complete != 0xaa || iface_data == 0xff) {
+		pr_warn("SABI set command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n",
+		       command, complete, iface_data);
+		retval = -EINVAL;
+	}
+
+	mutex_unlock(&sabi_mutex);
+	return retval;
+}
+
+static void test_backlight(void)
+{
+	struct sabi_retval sretval;
+
+	sabi_get_command(sabi_config->commands.get_backlight, &sretval);
+	printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
+
+	sabi_set_command(sabi_config->commands.set_backlight, 0);
+	printk(KERN_DEBUG "backlight should be off\n");
+
+	sabi_get_command(sabi_config->commands.get_backlight, &sretval);
+	printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
+
+	msleep(1000);
+
+	sabi_set_command(sabi_config->commands.set_backlight, 1);
+	printk(KERN_DEBUG "backlight should be on\n");
+
+	sabi_get_command(sabi_config->commands.get_backlight, &sretval);
+	printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
+}
+
+static void test_wireless(void)
+{
+	struct sabi_retval sretval;
+
+	sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
+	printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
+
+	sabi_set_command(sabi_config->commands.set_wireless_button, 0);
+	printk(KERN_DEBUG "wireless led should be off\n");
+
+	sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
+	printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
+
+	msleep(1000);
+
+	sabi_set_command(sabi_config->commands.set_wireless_button, 1);
+	printk(KERN_DEBUG "wireless led should be on\n");
+
+	sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
+	printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
+}
+
+static u8 read_brightness(void)
+{
+	struct sabi_retval sretval;
+	int user_brightness = 0;
+	int retval;
+
+	retval = sabi_get_command(sabi_config->commands.get_brightness,
+				  &sretval);
+	if (!retval) {
+		user_brightness = sretval.retval[0];
+		if (user_brightness != 0)
+			user_brightness -= sabi_config->min_brightness;
+	}
+	return user_brightness;
+}
+
+static void set_brightness(u8 user_brightness)
+{
+	u8 user_level = user_brightness - sabi_config->min_brightness;
+
+	sabi_set_command(sabi_config->commands.set_brightness, user_level);
+}
+
+static int get_brightness(struct backlight_device *bd)
+{
+	return (int)read_brightness();
+}
+
+static int update_status(struct backlight_device *bd)
+{
+	set_brightness(bd->props.brightness);
+
+	if (bd->props.power == FB_BLANK_UNBLANK)
+		sabi_set_command(sabi_config->commands.set_backlight, 1);
+	else
+		sabi_set_command(sabi_config->commands.set_backlight, 0);
+	return 0;
+}
+
+static const struct backlight_ops backlight_ops = {
+	.get_brightness	= get_brightness,
+	.update_status	= update_status,
+};
+
+static int rfkill_set(void *data, bool blocked)
+{
+	/* Do something with blocked...*/
+	/*
+	 * blocked == false is on
+	 * blocked == true is off
+	 */
+	if (blocked)
+		sabi_set_command(sabi_config->commands.set_wireless_button, 0);
+	else
+		sabi_set_command(sabi_config->commands.set_wireless_button, 1);
+
+	return 0;
+}
+
+static struct rfkill_ops rfkill_ops = {
+	.set_block = rfkill_set,
+};
+
+static int init_wireless(struct platform_device *sdev)
+{
+	int retval;
+
+	rfk = rfkill_alloc("samsung-wifi", &sdev->dev, RFKILL_TYPE_WLAN,
+			   &rfkill_ops, NULL);
+	if (!rfk)
+		return -ENOMEM;
+
+	retval = rfkill_register(rfk);
+	if (retval) {
+		rfkill_destroy(rfk);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void destroy_wireless(void)
+{
+	rfkill_unregister(rfk);
+	rfkill_destroy(rfk);
+}
+
+static ssize_t get_performance_level(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct sabi_retval sretval;
+	int retval;
+	int i;
+
+	/* Read the state */
+	retval = sabi_get_command(sabi_config->commands.get_performance_level,
+				  &sretval);
+	if (retval)
+		return retval;
+
+	/* The logic is backwards, yeah, lots of fun... */
+	for (i = 0; sabi_config->performance_levels[i].name; ++i) {
+		if (sretval.retval[0] == sabi_config->performance_levels[i].value)
+			return sprintf(buf, "%s\n", sabi_config->performance_levels[i].name);
+	}
+	return sprintf(buf, "%s\n", "unknown");
+}
+
+static ssize_t set_performance_level(struct device *dev,
+				struct device_attribute *attr, const char *buf,
+				size_t count)
+{
+	if (count >= 1) {
+		int i;
+		for (i = 0; sabi_config->performance_levels[i].name; ++i) {
+			const struct sabi_performance_level *level =
+				&sabi_config->performance_levels[i];
+			if (!strncasecmp(level->name, buf, strlen(level->name))) {
+				sabi_set_command(sabi_config->commands.set_performance_level,
+						 level->value);
+				break;
+			}
+		}
+		if (!sabi_config->performance_levels[i].name)
+			return -EINVAL;
+	}
+	return count;
+}
+static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO,
+		   get_performance_level, set_performance_level);
+
+
+static int __init dmi_check_cb(const struct dmi_system_id *id)
+{
+	pr_info("found laptop model '%s'\n",
+		id->ident);
+	return 0;
+}
+
+static struct dmi_system_id __initdata samsung_dmi_table[] = {
+	{
+		.ident = "N128",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N128"),
+			DMI_MATCH(DMI_BOARD_NAME, "N128"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "N130",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N130"),
+			DMI_MATCH(DMI_BOARD_NAME, "N130"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "X125",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X125"),
+			DMI_MATCH(DMI_BOARD_NAME, "X125"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "X120/X170",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X120/X170"),
+			DMI_MATCH(DMI_BOARD_NAME, "X120/X170"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "NC10",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "NC10"),
+			DMI_MATCH(DMI_BOARD_NAME, "NC10"),
+		},
+		.callback = dmi_check_cb,
+	},
+		{
+		.ident = "NP-Q45",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"),
+			DMI_MATCH(DMI_BOARD_NAME, "SQ45S70S"),
+		},
+		.callback = dmi_check_cb,
+		},
+	{
+		.ident = "X360",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
+			DMI_MATCH(DMI_BOARD_NAME, "X360"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "R518",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "R518"),
+			DMI_MATCH(DMI_BOARD_NAME, "R518"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "R519/R719",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "R519/R719"),
+			DMI_MATCH(DMI_BOARD_NAME, "R519/R719"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "N150/N210/N220",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
+			DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "N150P/N210P/N220P",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N150P/N210P/N220P"),
+			DMI_MATCH(DMI_BOARD_NAME, "N150P/N210P/N220P"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "R530/R730",
+		.matches = {
+		      DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+		      DMI_MATCH(DMI_PRODUCT_NAME, "R530/R730"),
+		      DMI_MATCH(DMI_BOARD_NAME, "R530/R730"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "NF110/NF210/NF310",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"),
+			DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "N145P/N250P/N260P",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
+			DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "R70/R71",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "R70/R71"),
+			DMI_MATCH(DMI_BOARD_NAME, "R70/R71"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "P460",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "P460"),
+			DMI_MATCH(DMI_BOARD_NAME, "P460"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
+
+static int find_signature(void __iomem *memcheck, const char *testStr)
+{
+	int i = 0;
+	int loca;
+
+	for (loca = 0; loca < 0xffff; loca++) {
+		char temp = readb(memcheck + loca);
+
+		if (temp == testStr[i]) {
+			if (i == strlen(testStr)-1)
+				break;
+			++i;
+		} else {
+			i = 0;
+		}
+	}
+	return loca;
+}
+
+static int __init samsung_init(void)
+{
+	struct backlight_properties props;
+	struct sabi_retval sretval;
+	unsigned int ifaceP;
+	int i;
+	int loca;
+	int retval;
+
+	mutex_init(&sabi_mutex);
+
+	if (!force && !dmi_check_system(samsung_dmi_table))
+		return -ENODEV;
+
+	f0000_segment = ioremap_nocache(0xf0000, 0xffff);
+	if (!f0000_segment) {
+		pr_err("Can't map the segment at 0xf0000\n");
+		return -EINVAL;
+	}
+
+	/* Try to find one of the signatures in memory to find the header */
+	for (i = 0; sabi_configs[i].test_string != 0; ++i) {
+		sabi_config = &sabi_configs[i];
+		loca = find_signature(f0000_segment, sabi_config->test_string);
+		if (loca != 0xffff)
+			break;
+	}
+
+	if (loca == 0xffff) {
+		pr_err("This computer does not support SABI\n");
+		goto error_no_signature;
+	}
+
+	/* point to the SMI port Number */
+	loca += 1;
+	sabi = (f0000_segment + loca);
+
+	if (debug) {
+		printk(KERN_DEBUG "This computer supports SABI==%x\n",
+			loca + 0xf0000 - 6);
+		printk(KERN_DEBUG "SABI header:\n");
+		printk(KERN_DEBUG " SMI Port Number = 0x%04x\n",
+			readw(sabi + sabi_config->header_offsets.port));
+		printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n",
+			readb(sabi + sabi_config->header_offsets.iface_func));
+		printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n",
+			readb(sabi + sabi_config->header_offsets.en_mem));
+		printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n",
+			readb(sabi + sabi_config->header_offsets.re_mem));
+		printk(KERN_DEBUG " SABI data offset = 0x%04x\n",
+			readw(sabi + sabi_config->header_offsets.data_offset));
+		printk(KERN_DEBUG " SABI data segment = 0x%04x\n",
+			readw(sabi + sabi_config->header_offsets.data_segment));
+	}
+
+	/* Get a pointer to the SABI Interface */
+	ifaceP = (readw(sabi + sabi_config->header_offsets.data_segment) & 0x0ffff) << 4;
+	ifaceP += readw(sabi + sabi_config->header_offsets.data_offset) & 0x0ffff;
+	sabi_iface = ioremap_nocache(ifaceP, 16);
+	if (!sabi_iface) {
+		pr_err("Can't remap %x\n", ifaceP);
+		goto exit;
+	}
+	if (debug) {
+		printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP);
+		printk(KERN_DEBUG "sabi_iface = %p\n", sabi_iface);
+
+		test_backlight();
+		test_wireless();
+
+		retval = sabi_get_command(sabi_config->commands.get_brightness,
+					  &sretval);
+		printk(KERN_DEBUG "brightness = 0x%02x\n", sretval.retval[0]);
+	}
+
+	/* Turn on "Linux" mode in the BIOS */
+	if (sabi_config->commands.set_linux != 0xff) {
+		retval = sabi_set_command(sabi_config->commands.set_linux,
+					  0x81);
+		if (retval) {
+			pr_warn("Linux mode was not set!\n");
+			goto error_no_platform;
+		}
+	}
+
+	/* knock up a platform device to hang stuff off of */
+	sdev = platform_device_register_simple("samsung", -1, NULL, 0);
+	if (IS_ERR(sdev))
+		goto error_no_platform;
+
+	/* create a backlight device to talk to this one */
+	memset(&props, 0, sizeof(struct backlight_properties));
+	props.max_brightness = sabi_config->max_brightness;
+	backlight_device = backlight_device_register("samsung", &sdev->dev,
+						     NULL, &backlight_ops,
+						     &props);
+	if (IS_ERR(backlight_device))
+		goto error_no_backlight;
+
+	backlight_device->props.brightness = read_brightness();
+	backlight_device->props.power = FB_BLANK_UNBLANK;
+	backlight_update_status(backlight_device);
+
+	retval = init_wireless(sdev);
+	if (retval)
+		goto error_no_rfk;
+
+	retval = device_create_file(&sdev->dev, &dev_attr_performance_level);
+	if (retval)
+		goto error_file_create;
+
+exit:
+	return 0;
+
+error_file_create:
+	destroy_wireless();
+
+error_no_rfk:
+	backlight_device_unregister(backlight_device);
+
+error_no_backlight:
+	platform_device_unregister(sdev);
+
+error_no_platform:
+	iounmap(sabi_iface);
+
+error_no_signature:
+	iounmap(f0000_segment);
+	return -EINVAL;
+}
+
+static void __exit samsung_exit(void)
+{
+	/* Turn off "Linux" mode in the BIOS */
+	if (sabi_config->commands.set_linux != 0xff)
+		sabi_set_command(sabi_config->commands.set_linux, 0x80);
+
+	device_remove_file(&sdev->dev, &dev_attr_performance_level);
+	backlight_device_unregister(backlight_device);
+	destroy_wireless();
+	iounmap(sabi_iface);
+	iounmap(f0000_segment);
+	platform_device_unregister(sdev);
+}
+
+module_init(samsung_init);
+module_exit(samsung_exit);
+
+MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>");
+MODULE_DESCRIPTION("Samsung Backlight driver");
+MODULE_LICENSE("GPL");
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH] Platform: add Samsung Laptop platform driver
@ 2011-02-27 15:36 Greg KH
  0 siblings, 0 replies; 53+ messages in thread
From: Greg KH @ 2011-02-27 15:36 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: Randy Dunlap, linux-kernel, platform-driver-x86

From: Greg Kroah-Hartman <gregkh@suse.de>

This adds the samsung-laptop driver to the kernel.  It now supports
all known Samsung laptops that use the SABI interface.

Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 Documentation/ABI/testing/sysfs-driver-samsung-laptop |   19 
 drivers/platform/x86/Kconfig                          |   13 
 drivers/platform/x86/Makefile                         |    1 
 drivers/platform/x86/samsung-laptop.c                 |  832 ++++++++++++++++++
 4 files changed, 865 insertions(+)

Matthew, this is a copy of the latest version in the linux-next tree of the
driver.  Once it has been accepted into your tree, I'll delete the
staging driver.  Or, if you want to give your ACK, I can just move the
driver from staging into this directory in my tree, which will properly
preserve the history of the code.

v2 - I have also addressed all of the review comments you gave me
     previously, and fixed a bug in the previous version that broke the
     driver on the N128 laptop, as well as added support for a wide
     range of other laptops thanks to many testers who sent in patches.

v3 - Added a few more device ids, const changes, and now supports
     variable brightness levels as not all laptops are the same with
     this.


diff --git a/Documentation/ABI/testing/sysfs-driver-samsung-laptop b/Documentation/ABI/testing/sysfs-driver-samsung-laptop
new file mode 100644
index 0000000..0a81023
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-samsung-laptop
@@ -0,0 +1,19 @@
+What:		/sys/devices/platform/samsung/performance_level
+Date:		January 1, 2010
+KernelVersion:	2.6.33
+Contact:	Greg Kroah-Hartman <gregkh@suse.de>
+Description:	Some Samsung laptops have different "performance levels"
+		that are can be modified by a function key, and by this
+		sysfs file.  These values don't always make a whole lot
+		of sense, but some users like to modify them to keep
+		their fans quiet at all costs.  Reading from this file
+		will show the current performance level.  Writing to the
+		file can change this value.
+			Valid options:
+				"silent"
+				"normal"
+				"overclock"
+		Note that not all laptops support all of these options.
+		Specifically, not all support the "overclock" option,
+		and it's still unknown if this value even changes
+		anything, other than making the user feel a bit better.
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index a59af5b..5624267 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -654,4 +654,17 @@ config XO1_RFKILL
 	  Support for enabling/disabling the WLAN interface on the OLPC XO-1
 	  laptop.
 
+config SAMSUNG_LAPTOP
+	tristate "Samsung Laptop driver"
+	depends on RFKILL && BACKLIGHT_CLASS_DEVICE && X86
+	---help---
+	  This module implements a driver for a wide range of different
+	  Samsung laptops.  It offers control over the different
+	  function keys, wireless LED, LCD backlight level, and
+	  sometimes provides a "performance_control" sysfs file to allow
+	  the performance level of the laptop to be changed.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called samsung-laptop.
+
 endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 4ec4ff8..ad2fb97 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -34,3 +34,4 @@ obj-$(CONFIG_INTEL_IPS)		+= intel_ips.o
 obj-$(CONFIG_GPIO_INTEL_PMIC)	+= intel_pmic_gpio.o
 obj-$(CONFIG_XO1_RFKILL)	+= xo1-rfkill.o
 obj-$(CONFIG_IBM_RTL)		+= ibm_rtl.o
+obj-$(CONFIG_SAMSUNG_LAPTOP)	+= samsung-laptop.o
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c
new file mode 100644
index 0000000..e0b390d
--- /dev/null
+++ b/drivers/platform/x86/samsung-laptop.c
@@ -0,0 +1,832 @@
+/*
+ * Samsung Laptop driver
+ *
+ * Copyright (C) 2009,2011 Greg Kroah-Hartman (gregkh@suse.de)
+ * Copyright (C) 2009,2011 Novell 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.
+ *
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+#include <linux/dmi.h>
+#include <linux/platform_device.h>
+#include <linux/rfkill.h>
+
+/*
+ * This driver is needed because a number of Samsung laptops do not hook
+ * their control settings through ACPI.  So we have to poke around in the
+ * BIOS to do things like brightness values, and "special" key controls.
+ */
+
+/*
+ * We have 0 - 8 as valid brightness levels.  The specs say that level 0 should
+ * be reserved by the BIOS (which really doesn't make much sense), we tell
+ * userspace that the value is 0 - 7 and then just tell the hardware 1 - 8
+ */
+#define MAX_BRIGHT	0x07
+
+
+#define SABI_IFACE_MAIN			0x00
+#define SABI_IFACE_SUB			0x02
+#define SABI_IFACE_COMPLETE		0x04
+#define SABI_IFACE_DATA			0x05
+
+/* Structure to get data back to the calling function */
+struct sabi_retval {
+	u8 retval[20];
+};
+
+struct sabi_header_offsets {
+	u8 port;
+	u8 re_mem;
+	u8 iface_func;
+	u8 en_mem;
+	u8 data_offset;
+	u8 data_segment;
+};
+
+struct sabi_commands {
+	/*
+	 * Brightness is 0 - 8, as described above.
+	 * Value 0 is for the BIOS to use
+	 */
+	u8 get_brightness;
+	u8 set_brightness;
+
+	/*
+	 * first byte:
+	 * 0x00 - wireless is off
+	 * 0x01 - wireless is on
+	 * second byte:
+	 * 0x02 - 3G is off
+	 * 0x03 - 3G is on
+	 * TODO, verify 3G is correct, that doesn't seem right...
+	 */
+	u8 get_wireless_button;
+	u8 set_wireless_button;
+
+	/* 0 is off, 1 is on */
+	u8 get_backlight;
+	u8 set_backlight;
+
+	/*
+	 * 0x80 or 0x00 - no action
+	 * 0x81 - recovery key pressed
+	 */
+	u8 get_recovery_mode;
+	u8 set_recovery_mode;
+
+	/*
+	 * on seclinux: 0 is low, 1 is high,
+	 * on swsmi: 0 is normal, 1 is silent, 2 is turbo
+	 */
+	u8 get_performance_level;
+	u8 set_performance_level;
+
+	/*
+	 * Tell the BIOS that Linux is running on this machine.
+	 * 81 is on, 80 is off
+	 */
+	u8 set_linux;
+};
+
+struct sabi_performance_level {
+	const char *name;
+	u8 value;
+};
+
+struct sabi_config {
+	const char *test_string;
+	u16 main_function;
+	const struct sabi_header_offsets header_offsets;
+	const struct sabi_commands commands;
+	const struct sabi_performance_level performance_levels[4];
+	u8 min_brightness;
+	u8 max_brightness;
+};
+
+static const struct sabi_config sabi_configs[] = {
+	{
+		.test_string = "SECLINUX",
+
+		.main_function = 0x4c49,
+
+		.header_offsets = {
+			.port = 0x00,
+			.re_mem = 0x02,
+			.iface_func = 0x03,
+			.en_mem = 0x04,
+			.data_offset = 0x05,
+			.data_segment = 0x07,
+		},
+
+		.commands = {
+			.get_brightness = 0x00,
+			.set_brightness = 0x01,
+
+			.get_wireless_button = 0x02,
+			.set_wireless_button = 0x03,
+
+			.get_backlight = 0x04,
+			.set_backlight = 0x05,
+
+			.get_recovery_mode = 0x06,
+			.set_recovery_mode = 0x07,
+
+			.get_performance_level = 0x08,
+			.set_performance_level = 0x09,
+
+			.set_linux = 0x0a,
+		},
+
+		.performance_levels = {
+			{
+				.name = "silent",
+				.value = 0,
+			},
+			{
+				.name = "normal",
+				.value = 1,
+			},
+			{ },
+		},
+		.min_brightness = 1,
+		.max_brightness = 8,
+	},
+	{
+		.test_string = "SwSmi@",
+
+		.main_function = 0x5843,
+
+		.header_offsets = {
+			.port = 0x00,
+			.re_mem = 0x04,
+			.iface_func = 0x02,
+			.en_mem = 0x03,
+			.data_offset = 0x05,
+			.data_segment = 0x07,
+		},
+
+		.commands = {
+			.get_brightness = 0x10,
+			.set_brightness = 0x11,
+
+			.get_wireless_button = 0x12,
+			.set_wireless_button = 0x13,
+
+			.get_backlight = 0x2d,
+			.set_backlight = 0x2e,
+
+			.get_recovery_mode = 0xff,
+			.set_recovery_mode = 0xff,
+
+			.get_performance_level = 0x31,
+			.set_performance_level = 0x32,
+
+			.set_linux = 0xff,
+		},
+
+		.performance_levels = {
+			{
+				.name = "normal",
+				.value = 0,
+			},
+			{
+				.name = "silent",
+				.value = 1,
+			},
+			{
+				.name = "overclock",
+				.value = 2,
+			},
+			{ },
+		},
+		.min_brightness = 0,
+		.max_brightness = 8,
+	},
+	{ },
+};
+
+static const struct sabi_config *sabi_config;
+
+static void __iomem *sabi;
+static void __iomem *sabi_iface;
+static void __iomem *f0000_segment;
+static struct backlight_device *backlight_device;
+static struct mutex sabi_mutex;
+static struct platform_device *sdev;
+static struct rfkill *rfk;
+
+static int force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force,
+		"Disable the DMI check and forces the driver to be loaded");
+
+static int debug;
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+static int sabi_get_command(u8 command, struct sabi_retval *sretval)
+{
+	int retval = 0;
+	u16 port = readw(sabi + sabi_config->header_offsets.port);
+	u8 complete, iface_data;
+
+	mutex_lock(&sabi_mutex);
+
+	/* enable memory to be able to write to it */
+	outb(readb(sabi + sabi_config->header_offsets.en_mem), port);
+
+	/* write out the command */
+	writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN);
+	writew(command, sabi_iface + SABI_IFACE_SUB);
+	writeb(0, sabi_iface + SABI_IFACE_COMPLETE);
+	outb(readb(sabi + sabi_config->header_offsets.iface_func), port);
+
+	/* write protect memory to make it safe */
+	outb(readb(sabi + sabi_config->header_offsets.re_mem), port);
+
+	/* see if the command actually succeeded */
+	complete = readb(sabi_iface + SABI_IFACE_COMPLETE);
+	iface_data = readb(sabi_iface + SABI_IFACE_DATA);
+	if (complete != 0xaa || iface_data == 0xff) {
+		pr_warn("SABI get command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n",
+		        command, complete, iface_data);
+		retval = -EINVAL;
+		goto exit;
+	}
+	/*
+	 * Save off the data into a structure so the caller use it.
+	 * Right now we only want the first 4 bytes,
+	 * There are commands that need more, but not for the ones we
+	 * currently care about.
+	 */
+	sretval->retval[0] = readb(sabi_iface + SABI_IFACE_DATA);
+	sretval->retval[1] = readb(sabi_iface + SABI_IFACE_DATA + 1);
+	sretval->retval[2] = readb(sabi_iface + SABI_IFACE_DATA + 2);
+	sretval->retval[3] = readb(sabi_iface + SABI_IFACE_DATA + 3);
+
+exit:
+	mutex_unlock(&sabi_mutex);
+	return retval;
+
+}
+
+static int sabi_set_command(u8 command, u8 data)
+{
+	int retval = 0;
+	u16 port = readw(sabi + sabi_config->header_offsets.port);
+	u8 complete, iface_data;
+
+	mutex_lock(&sabi_mutex);
+
+	/* enable memory to be able to write to it */
+	outb(readb(sabi + sabi_config->header_offsets.en_mem), port);
+
+	/* write out the command */
+	writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN);
+	writew(command, sabi_iface + SABI_IFACE_SUB);
+	writeb(0, sabi_iface + SABI_IFACE_COMPLETE);
+	writeb(data, sabi_iface + SABI_IFACE_DATA);
+	outb(readb(sabi + sabi_config->header_offsets.iface_func), port);
+
+	/* write protect memory to make it safe */
+	outb(readb(sabi + sabi_config->header_offsets.re_mem), port);
+
+	/* see if the command actually succeeded */
+	complete = readb(sabi_iface + SABI_IFACE_COMPLETE);
+	iface_data = readb(sabi_iface + SABI_IFACE_DATA);
+	if (complete != 0xaa || iface_data == 0xff) {
+		pr_warn("SABI set command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n",
+		       command, complete, iface_data);
+		retval = -EINVAL;
+	}
+
+	mutex_unlock(&sabi_mutex);
+	return retval;
+}
+
+static void test_backlight(void)
+{
+	struct sabi_retval sretval;
+
+	sabi_get_command(sabi_config->commands.get_backlight, &sretval);
+	printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
+
+	sabi_set_command(sabi_config->commands.set_backlight, 0);
+	printk(KERN_DEBUG "backlight should be off\n");
+
+	sabi_get_command(sabi_config->commands.get_backlight, &sretval);
+	printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
+
+	msleep(1000);
+
+	sabi_set_command(sabi_config->commands.set_backlight, 1);
+	printk(KERN_DEBUG "backlight should be on\n");
+
+	sabi_get_command(sabi_config->commands.get_backlight, &sretval);
+	printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
+}
+
+static void test_wireless(void)
+{
+	struct sabi_retval sretval;
+
+	sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
+	printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
+
+	sabi_set_command(sabi_config->commands.set_wireless_button, 0);
+	printk(KERN_DEBUG "wireless led should be off\n");
+
+	sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
+	printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
+
+	msleep(1000);
+
+	sabi_set_command(sabi_config->commands.set_wireless_button, 1);
+	printk(KERN_DEBUG "wireless led should be on\n");
+
+	sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
+	printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
+}
+
+static u8 read_brightness(void)
+{
+	struct sabi_retval sretval;
+	int user_brightness = 0;
+	int retval;
+
+	retval = sabi_get_command(sabi_config->commands.get_brightness,
+				  &sretval);
+	if (!retval) {
+		user_brightness = sretval.retval[0];
+		if (user_brightness != 0)
+			user_brightness -= sabi_config->min_brightness;
+	}
+	return user_brightness;
+}
+
+static void set_brightness(u8 user_brightness)
+{
+	u8 user_level = user_brightness - sabi_config->min_brightness;
+
+	sabi_set_command(sabi_config->commands.set_brightness, user_level);
+}
+
+static int get_brightness(struct backlight_device *bd)
+{
+	return (int)read_brightness();
+}
+
+static int update_status(struct backlight_device *bd)
+{
+	set_brightness(bd->props.brightness);
+
+	if (bd->props.power == FB_BLANK_UNBLANK)
+		sabi_set_command(sabi_config->commands.set_backlight, 1);
+	else
+		sabi_set_command(sabi_config->commands.set_backlight, 0);
+	return 0;
+}
+
+static const struct backlight_ops backlight_ops = {
+	.get_brightness	= get_brightness,
+	.update_status	= update_status,
+};
+
+static int rfkill_set(void *data, bool blocked)
+{
+	/* Do something with blocked...*/
+	/*
+	 * blocked == false is on
+	 * blocked == true is off
+	 */
+	if (blocked)
+		sabi_set_command(sabi_config->commands.set_wireless_button, 0);
+	else
+		sabi_set_command(sabi_config->commands.set_wireless_button, 1);
+
+	return 0;
+}
+
+static struct rfkill_ops rfkill_ops = {
+	.set_block = rfkill_set,
+};
+
+static int init_wireless(struct platform_device *sdev)
+{
+	int retval;
+
+	rfk = rfkill_alloc("samsung-wifi", &sdev->dev, RFKILL_TYPE_WLAN,
+			   &rfkill_ops, NULL);
+	if (!rfk)
+		return -ENOMEM;
+
+	retval = rfkill_register(rfk);
+	if (retval) {
+		rfkill_destroy(rfk);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void destroy_wireless(void)
+{
+	rfkill_unregister(rfk);
+	rfkill_destroy(rfk);
+}
+
+static ssize_t get_performance_level(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct sabi_retval sretval;
+	int retval;
+	int i;
+
+	/* Read the state */
+	retval = sabi_get_command(sabi_config->commands.get_performance_level,
+				  &sretval);
+	if (retval)
+		return retval;
+
+	/* The logic is backwards, yeah, lots of fun... */
+	for (i = 0; sabi_config->performance_levels[i].name; ++i) {
+		if (sretval.retval[0] == sabi_config->performance_levels[i].value)
+			return sprintf(buf, "%s\n", sabi_config->performance_levels[i].name);
+	}
+	return sprintf(buf, "%s\n", "unknown");
+}
+
+static ssize_t set_performance_level(struct device *dev,
+				struct device_attribute *attr, const char *buf,
+				size_t count)
+{
+	if (count >= 1) {
+		int i;
+		for (i = 0; sabi_config->performance_levels[i].name; ++i) {
+			const struct sabi_performance_level *level =
+				&sabi_config->performance_levels[i];
+			if (!strncasecmp(level->name, buf, strlen(level->name))) {
+				sabi_set_command(sabi_config->commands.set_performance_level,
+						 level->value);
+				break;
+			}
+		}
+		if (!sabi_config->performance_levels[i].name)
+			return -EINVAL;
+	}
+	return count;
+}
+static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO,
+		   get_performance_level, set_performance_level);
+
+
+static int __init dmi_check_cb(const struct dmi_system_id *id)
+{
+	pr_info("found laptop model '%s'\n",
+		id->ident);
+	return 0;
+}
+
+static struct dmi_system_id __initdata samsung_dmi_table[] = {
+	{
+		.ident = "N128",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N128"),
+			DMI_MATCH(DMI_BOARD_NAME, "N128"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "N130",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N130"),
+			DMI_MATCH(DMI_BOARD_NAME, "N130"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "X125",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X125"),
+			DMI_MATCH(DMI_BOARD_NAME, "X125"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "X120/X170",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X120/X170"),
+			DMI_MATCH(DMI_BOARD_NAME, "X120/X170"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "NC10",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "NC10"),
+			DMI_MATCH(DMI_BOARD_NAME, "NC10"),
+		},
+		.callback = dmi_check_cb,
+	},
+		{
+		.ident = "NP-Q45",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"),
+			DMI_MATCH(DMI_BOARD_NAME, "SQ45S70S"),
+		},
+		.callback = dmi_check_cb,
+		},
+	{
+		.ident = "X360",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
+			DMI_MATCH(DMI_BOARD_NAME, "X360"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "R518",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "R518"),
+			DMI_MATCH(DMI_BOARD_NAME, "R518"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "R519/R719",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "R519/R719"),
+			DMI_MATCH(DMI_BOARD_NAME, "R519/R719"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "N150/N210/N220",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
+			DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "N150P/N210P/N220P",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N150P/N210P/N220P"),
+			DMI_MATCH(DMI_BOARD_NAME, "N150P/N210P/N220P"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "R530/R730",
+		.matches = {
+		      DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+		      DMI_MATCH(DMI_PRODUCT_NAME, "R530/R730"),
+		      DMI_MATCH(DMI_BOARD_NAME, "R530/R730"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "NF110/NF210/NF310",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"),
+			DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "N145P/N250P/N260P",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
+			DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "R70/R71",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "R70/R71"),
+			DMI_MATCH(DMI_BOARD_NAME, "R70/R71"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "P460",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "P460"),
+			DMI_MATCH(DMI_BOARD_NAME, "P460"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
+
+static int find_signature(void __iomem *memcheck, const char *testStr)
+{
+	int i = 0;
+	int loca;
+
+	for (loca = 0; loca < 0xffff; loca++) {
+		char temp = readb(memcheck + loca);
+
+		if (temp == testStr[i]) {
+			if (i == strlen(testStr)-1)
+				break;
+			++i;
+		} else {
+			i = 0;
+		}
+	}
+	return loca;
+}
+
+static int __init samsung_init(void)
+{
+	struct backlight_properties props;
+	struct sabi_retval sretval;
+	unsigned int ifaceP;
+	int i;
+	int loca;
+	int retval;
+
+	mutex_init(&sabi_mutex);
+
+	if (!force && !dmi_check_system(samsung_dmi_table))
+		return -ENODEV;
+
+	f0000_segment = ioremap_nocache(0xf0000, 0xffff);
+	if (!f0000_segment) {
+		pr_err("Can't map the segment at 0xf0000\n");
+		return -EINVAL;
+	}
+
+	/* Try to find one of the signatures in memory to find the header */
+	for (i = 0; sabi_configs[i].test_string != 0; ++i) {
+		sabi_config = &sabi_configs[i];
+		loca = find_signature(f0000_segment, sabi_config->test_string);
+		if (loca != 0xffff)
+			break;
+	}
+
+	if (loca == 0xffff) {
+		pr_err("This computer does not support SABI\n");
+		goto error_no_signature;
+	}
+
+	/* point to the SMI port Number */
+	loca += 1;
+	sabi = (f0000_segment + loca);
+
+	if (debug) {
+		printk(KERN_DEBUG "This computer supports SABI==%x\n",
+			loca + 0xf0000 - 6);
+		printk(KERN_DEBUG "SABI header:\n");
+		printk(KERN_DEBUG " SMI Port Number = 0x%04x\n",
+			readw(sabi + sabi_config->header_offsets.port));
+		printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n",
+			readb(sabi + sabi_config->header_offsets.iface_func));
+		printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n",
+			readb(sabi + sabi_config->header_offsets.en_mem));
+		printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n",
+			readb(sabi + sabi_config->header_offsets.re_mem));
+		printk(KERN_DEBUG " SABI data offset = 0x%04x\n",
+			readw(sabi + sabi_config->header_offsets.data_offset));
+		printk(KERN_DEBUG " SABI data segment = 0x%04x\n",
+			readw(sabi + sabi_config->header_offsets.data_segment));
+	}
+
+	/* Get a pointer to the SABI Interface */
+	ifaceP = (readw(sabi + sabi_config->header_offsets.data_segment) & 0x0ffff) << 4;
+	ifaceP += readw(sabi + sabi_config->header_offsets.data_offset) & 0x0ffff;
+	sabi_iface = ioremap_nocache(ifaceP, 16);
+	if (!sabi_iface) {
+		pr_err("Can't remap %x\n", ifaceP);
+		goto exit;
+	}
+	if (debug) {
+		printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP);
+		printk(KERN_DEBUG "sabi_iface = %p\n", sabi_iface);
+
+		test_backlight();
+		test_wireless();
+
+		retval = sabi_get_command(sabi_config->commands.get_brightness,
+					  &sretval);
+		printk(KERN_DEBUG "brightness = 0x%02x\n", sretval.retval[0]);
+	}
+
+	/* Turn on "Linux" mode in the BIOS */
+	if (sabi_config->commands.set_linux != 0xff) {
+		retval = sabi_set_command(sabi_config->commands.set_linux,
+					  0x81);
+		if (retval) {
+			pr_warn("Linux mode was not set!\n");
+			goto error_no_platform;
+		}
+	}
+
+	/* knock up a platform device to hang stuff off of */
+	sdev = platform_device_register_simple("samsung", -1, NULL, 0);
+	if (IS_ERR(sdev))
+		goto error_no_platform;
+
+	/* create a backlight device to talk to this one */
+	memset(&props, 0, sizeof(struct backlight_properties));
+	props.max_brightness = sabi_config->max_brightness;
+	backlight_device = backlight_device_register("samsung", &sdev->dev,
+						     NULL, &backlight_ops,
+						     &props);
+	if (IS_ERR(backlight_device))
+		goto error_no_backlight;
+
+	backlight_device->props.brightness = read_brightness();
+	backlight_device->props.power = FB_BLANK_UNBLANK;
+	backlight_update_status(backlight_device);
+
+	retval = init_wireless(sdev);
+	if (retval)
+		goto error_no_rfk;
+
+	retval = device_create_file(&sdev->dev, &dev_attr_performance_level);
+	if (retval)
+		goto error_file_create;
+
+exit:
+	return 0;
+
+error_file_create:
+	destroy_wireless();
+
+error_no_rfk:
+	backlight_device_unregister(backlight_device);
+
+error_no_backlight:
+	platform_device_unregister(sdev);
+
+error_no_platform:
+	iounmap(sabi_iface);
+
+error_no_signature:
+	iounmap(f0000_segment);
+	return -EINVAL;
+}
+
+static void __exit samsung_exit(void)
+{
+	/* Turn off "Linux" mode in the BIOS */
+	if (sabi_config->commands.set_linux != 0xff)
+		sabi_set_command(sabi_config->commands.set_linux, 0x80);
+
+	device_remove_file(&sdev->dev, &dev_attr_performance_level);
+	backlight_device_unregister(backlight_device);
+	destroy_wireless();
+	iounmap(sabi_iface);
+	iounmap(f0000_segment);
+	platform_device_unregister(sdev);
+}
+
+module_init(samsung_init);
+module_exit(samsung_exit);
+
+MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>");
+MODULE_DESCRIPTION("Samsung Backlight driver");
+MODULE_LICENSE("GPL");

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH] Platform: add Samsung Laptop platform driver
@ 2011-02-25 22:47 Greg KH
  0 siblings, 0 replies; 53+ messages in thread
From: Greg KH @ 2011-02-25 22:47 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: Randy Dunlap, linux-kernel, platform-driver-x86

From: Greg Kroah-Hartman <gregkh@suse.de>

This adds the samsung-laptop driver to the kernel.  It now supports
all known Samsung laptops that use the SABI interface.

Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---

 Documentation/ABI/testing/sysfs-driver-samsung-laptop |   19 
 drivers/platform/x86/Kconfig                          |   13 
 drivers/platform/x86/Makefile                         |    1 
 drivers/platform/x86/samsung-laptop.c                 |  805 ++++++++++++++++++
 4 files changed, 838 insertions(+)

Matthew, this is a copy of the latest version in the linux-next tree of the
driver.  Once it has been accepted into your tree, I'll delete the
staging driver.  Or, if you want to give your ACK, I can just move the
driver from staging into this directory in my tree, which will properly
preserve the history of the code.

I have also addressed all of the review comments you gave me previously,
and fixed a bug in the previous version that broke the driver on the
N128 laptop, as well as added support for a wide range of other laptops
thanks to many testers who sent in patches.

--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-samsung-laptop
@@ -0,0 +1,19 @@
+What:		/sys/devices/platform/samsung/performance_level
+Date:		January 1, 2010
+KernelVersion:	2.6.33
+Contact:	Greg Kroah-Hartman <gregkh@suse.de>
+Description:	Some Samsung laptops have different "performance levels"
+		that are can be modified by a function key, and by this
+		sysfs file.  These values don't always make a whole lot
+		of sense, but some users like to modify them to keep
+		their fans quiet at all costs.  Reading from this file
+		will show the current performance level.  Writing to the
+		file can change this value.
+			Valid options:
+				"silent"
+				"normal"
+				"overclock"
+		Note that not all laptops support all of these options.
+		Specifically, not all support the "overclock" option,
+		and it's still unknown if this value even changes
+		anything, other than making the user feel a bit better.
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index a59af5b..5624267 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -654,4 +654,17 @@ config XO1_RFKILL
 	  Support for enabling/disabling the WLAN interface on the OLPC XO-1
 	  laptop.
 
+config SAMSUNG_LAPTOP
+	tristate "Samsung Laptop driver"
+	depends on RFKILL && BACKLIGHT_CLASS_DEVICE && X86
+	---help---
+	  This module implements a driver for a wide range of different
+	  Samsung laptops.  It offers control over the different
+	  function keys, wireless LED, LCD backlight level, and
+	  sometimes provides a "performance_control" sysfs file to allow
+	  the performance level of the laptop to be changed.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called samsung-laptop.
+
 endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 4ec4ff8..ad2fb97 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -34,3 +34,4 @@ obj-$(CONFIG_INTEL_IPS)		+= intel_ips.o
 obj-$(CONFIG_GPIO_INTEL_PMIC)	+= intel_pmic_gpio.o
 obj-$(CONFIG_XO1_RFKILL)	+= xo1-rfkill.o
 obj-$(CONFIG_IBM_RTL)		+= ibm_rtl.o
+obj-$(CONFIG_SAMSUNG_LAPTOP)	+= samsung-laptop.o
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c
new file mode 100644
index 0000000..a8e82b8
--- /dev/null
+++ b/drivers/platform/x86/samsung-laptop.c
@@ -0,0 +1,805 @@
+/*
+ * Samsung Laptop driver
+ *
+ * Copyright (C) 2009,2011 Greg Kroah-Hartman (gregkh@suse.de)
+ * Copyright (C) 2009,2011 Novell 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.
+ *
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+#include <linux/dmi.h>
+#include <linux/platform_device.h>
+#include <linux/rfkill.h>
+
+/*
+ * This driver is needed because a number of Samsung laptops do not hook
+ * their control settings through ACPI.  So we have to poke around in the
+ * BIOS to do things like brightness values, and "special" key controls.
+ */
+
+/*
+ * We have 0 - 8 as valid brightness levels.  The specs say that level 0 should
+ * be reserved by the BIOS (which really doesn't make much sense), we tell
+ * userspace that the value is 0 - 7 and then just tell the hardware 1 - 8
+ */
+#define MAX_BRIGHT	0x07
+
+
+#define SABI_IFACE_MAIN			0x00
+#define SABI_IFACE_SUB			0x02
+#define SABI_IFACE_COMPLETE		0x04
+#define SABI_IFACE_DATA			0x05
+
+/* Structure to get data back to the calling function */
+struct sabi_retval {
+	u8 retval[20];
+};
+
+struct sabi_header_offsets {
+	u8 port;
+	u8 re_mem;
+	u8 iface_func;
+	u8 en_mem;
+	u8 data_offset;
+	u8 data_segment;
+};
+
+struct sabi_commands {
+	/*
+	 * Brightness is 0 - 8, as described above.
+	 * Value 0 is for the BIOS to use
+	 */
+	u8 get_brightness;
+	u8 set_brightness;
+
+	/*
+	 * first byte:
+	 * 0x00 - wireless is off
+	 * 0x01 - wireless is on
+	 * second byte:
+	 * 0x02 - 3G is off
+	 * 0x03 - 3G is on
+	 * TODO, verify 3G is correct, that doesn't seem right...
+	 */
+	u8 get_wireless_button;
+	u8 set_wireless_button;
+
+	/* 0 is off, 1 is on */
+	u8 get_backlight;
+	u8 set_backlight;
+
+	/*
+	 * 0x80 or 0x00 - no action
+	 * 0x81 - recovery key pressed
+	 */
+	u8 get_recovery_mode;
+	u8 set_recovery_mode;
+
+	/*
+	 * on seclinux: 0 is low, 1 is high,
+	 * on swsmi: 0 is normal, 1 is silent, 2 is turbo
+	 */
+	u8 get_performance_level;
+	u8 set_performance_level;
+
+	/*
+	 * Tell the BIOS that Linux is running on this machine.
+	 * 81 is on, 80 is off
+	 */
+	u8 set_linux;
+};
+
+struct sabi_performance_level {
+	const char *name;
+	u8 value;
+};
+
+struct sabi_config {
+	const char *test_string;
+	u16 main_function;
+	struct sabi_header_offsets header_offsets;
+	struct sabi_commands commands;
+	struct sabi_performance_level performance_levels[4];
+};
+
+static struct sabi_config sabi_configs[] = {
+	{
+		.test_string = "SECLINUX",
+
+		.main_function = 0x4c49,
+
+		.header_offsets = {
+			.port = 0x00,
+			.re_mem = 0x02,
+			.iface_func = 0x03,
+			.en_mem = 0x04,
+			.data_offset = 0x05,
+			.data_segment = 0x07,
+		},
+
+		.commands = {
+			.get_brightness = 0x00,
+			.set_brightness = 0x01,
+
+			.get_wireless_button = 0x02,
+			.set_wireless_button = 0x03,
+
+			.get_backlight = 0x04,
+			.set_backlight = 0x05,
+
+			.get_recovery_mode = 0x06,
+			.set_recovery_mode = 0x07,
+
+			.get_performance_level = 0x08,
+			.set_performance_level = 0x09,
+
+			.set_linux = 0x0a,
+		},
+
+		.performance_levels = {
+			{
+				.name = "silent",
+				.value = 0,
+			},
+			{
+				.name = "normal",
+				.value = 1,
+			},
+			{ },
+		},
+	},
+	{
+		.test_string = "SwSmi@",
+
+		.main_function = 0x5843,
+
+		.header_offsets = {
+			.port = 0x00,
+			.re_mem = 0x04,
+			.iface_func = 0x02,
+			.en_mem = 0x03,
+			.data_offset = 0x05,
+			.data_segment = 0x07,
+		},
+
+		.commands = {
+			.get_brightness = 0x10,
+			.set_brightness = 0x11,
+
+			.get_wireless_button = 0x12,
+			.set_wireless_button = 0x13,
+
+			.get_backlight = 0x2d,
+			.set_backlight = 0x2e,
+
+			.get_recovery_mode = 0xff,
+			.set_recovery_mode = 0xff,
+
+			.get_performance_level = 0x31,
+			.set_performance_level = 0x32,
+
+			.set_linux = 0xff,
+		},
+
+		.performance_levels = {
+			{
+				.name = "normal",
+				.value = 0,
+			},
+			{
+				.name = "silent",
+				.value = 1,
+			},
+			{
+				.name = "overclock",
+				.value = 2,
+			},
+			{ },
+		},
+	},
+	{ },
+};
+
+static struct sabi_config *sabi_config;
+
+static void __iomem *sabi;
+static void __iomem *sabi_iface;
+static void __iomem *f0000_segment;
+static struct backlight_device *backlight_device;
+static struct mutex sabi_mutex;
+static struct platform_device *sdev;
+static struct rfkill *rfk;
+
+static int force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force,
+		"Disable the DMI check and forces the driver to be loaded");
+
+static int debug;
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+static int sabi_get_command(u8 command, struct sabi_retval *sretval)
+{
+	int retval = 0;
+	u16 port = readw(sabi + sabi_config->header_offsets.port);
+	u8 complete, iface_data;
+
+	mutex_lock(&sabi_mutex);
+
+	/* enable memory to be able to write to it */
+	outb(readb(sabi + sabi_config->header_offsets.en_mem), port);
+
+	/* write out the command */
+	writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN);
+	writew(command, sabi_iface + SABI_IFACE_SUB);
+	writeb(0, sabi_iface + SABI_IFACE_COMPLETE);
+	outb(readb(sabi + sabi_config->header_offsets.iface_func), port);
+
+	/* write protect memory to make it safe */
+	outb(readb(sabi + sabi_config->header_offsets.re_mem), port);
+
+	/* see if the command actually succeeded */
+	complete = readb(sabi_iface + SABI_IFACE_COMPLETE);
+	iface_data = readb(sabi_iface + SABI_IFACE_DATA);
+	if (complete != 0xaa || iface_data == 0xff) {
+		pr_warn("SABI get command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n",
+		        command, complete, iface_data);
+		retval = -EINVAL;
+		goto exit;
+	}
+	/*
+	 * Save off the data into a structure so the caller use it.
+	 * Right now we only want the first 4 bytes,
+	 * There are commands that need more, but not for the ones we
+	 * currently care about.
+	 */
+	sretval->retval[0] = readb(sabi_iface + SABI_IFACE_DATA);
+	sretval->retval[1] = readb(sabi_iface + SABI_IFACE_DATA + 1);
+	sretval->retval[2] = readb(sabi_iface + SABI_IFACE_DATA + 2);
+	sretval->retval[3] = readb(sabi_iface + SABI_IFACE_DATA + 3);
+
+exit:
+	mutex_unlock(&sabi_mutex);
+	return retval;
+
+}
+
+static int sabi_set_command(u8 command, u8 data)
+{
+	int retval = 0;
+	u16 port = readw(sabi + sabi_config->header_offsets.port);
+	u8 complete, iface_data;
+
+	mutex_lock(&sabi_mutex);
+
+	/* enable memory to be able to write to it */
+	outb(readb(sabi + sabi_config->header_offsets.en_mem), port);
+
+	/* write out the command */
+	writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN);
+	writew(command, sabi_iface + SABI_IFACE_SUB);
+	writeb(0, sabi_iface + SABI_IFACE_COMPLETE);
+	writeb(data, sabi_iface + SABI_IFACE_DATA);
+	outb(readb(sabi + sabi_config->header_offsets.iface_func), port);
+
+	/* write protect memory to make it safe */
+	outb(readb(sabi + sabi_config->header_offsets.re_mem), port);
+
+	/* see if the command actually succeeded */
+	complete = readb(sabi_iface + SABI_IFACE_COMPLETE);
+	iface_data = readb(sabi_iface + SABI_IFACE_DATA);
+	if (complete != 0xaa || iface_data == 0xff) {
+		pr_warn("SABI set command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n",
+		       command, complete, iface_data);
+		retval = -EINVAL;
+	}
+
+	mutex_unlock(&sabi_mutex);
+	return retval;
+}
+
+static void test_backlight(void)
+{
+	struct sabi_retval sretval;
+
+	sabi_get_command(sabi_config->commands.get_backlight, &sretval);
+	printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
+
+	sabi_set_command(sabi_config->commands.set_backlight, 0);
+	printk(KERN_DEBUG "backlight should be off\n");
+
+	sabi_get_command(sabi_config->commands.get_backlight, &sretval);
+	printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
+
+	msleep(1000);
+
+	sabi_set_command(sabi_config->commands.set_backlight, 1);
+	printk(KERN_DEBUG "backlight should be on\n");
+
+	sabi_get_command(sabi_config->commands.get_backlight, &sretval);
+	printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
+}
+
+static void test_wireless(void)
+{
+	struct sabi_retval sretval;
+
+	sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
+	printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
+
+	sabi_set_command(sabi_config->commands.set_wireless_button, 0);
+	printk(KERN_DEBUG "wireless led should be off\n");
+
+	sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
+	printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
+
+	msleep(1000);
+
+	sabi_set_command(sabi_config->commands.set_wireless_button, 1);
+	printk(KERN_DEBUG "wireless led should be on\n");
+
+	sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
+	printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
+}
+
+static u8 read_brightness(void)
+{
+	struct sabi_retval sretval;
+	int user_brightness = 0;
+	int retval;
+
+	retval = sabi_get_command(sabi_config->commands.get_brightness,
+				  &sretval);
+	if (!retval)
+		user_brightness = sretval.retval[0];
+		if (user_brightness != 0)
+			--user_brightness;
+	return user_brightness;
+}
+
+static void set_brightness(u8 user_brightness)
+{
+	sabi_set_command(sabi_config->commands.set_brightness,
+			 user_brightness + 1);
+}
+
+static int get_brightness(struct backlight_device *bd)
+{
+	return (int)read_brightness();
+}
+
+static int update_status(struct backlight_device *bd)
+{
+	set_brightness(bd->props.brightness);
+
+	if (bd->props.power == FB_BLANK_UNBLANK)
+		sabi_set_command(sabi_config->commands.set_backlight, 1);
+	else
+		sabi_set_command(sabi_config->commands.set_backlight, 0);
+	return 0;
+}
+
+static const struct backlight_ops backlight_ops = {
+	.get_brightness	= get_brightness,
+	.update_status	= update_status,
+};
+
+static int rfkill_set(void *data, bool blocked)
+{
+	/* Do something with blocked...*/
+	/*
+	 * blocked == false is on
+	 * blocked == true is off
+	 */
+	if (blocked)
+		sabi_set_command(sabi_config->commands.set_wireless_button, 0);
+	else
+		sabi_set_command(sabi_config->commands.set_wireless_button, 1);
+
+	return 0;
+}
+
+static struct rfkill_ops rfkill_ops = {
+	.set_block = rfkill_set,
+};
+
+static int init_wireless(struct platform_device *sdev)
+{
+	int retval;
+
+	rfk = rfkill_alloc("samsung-wifi", &sdev->dev, RFKILL_TYPE_WLAN,
+			   &rfkill_ops, NULL);
+	if (!rfk)
+		return -ENOMEM;
+
+	retval = rfkill_register(rfk);
+	if (retval) {
+		rfkill_destroy(rfk);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void destroy_wireless(void)
+{
+	rfkill_unregister(rfk);
+	rfkill_destroy(rfk);
+}
+
+static ssize_t get_performance_level(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct sabi_retval sretval;
+	int retval;
+	int i;
+
+	/* Read the state */
+	retval = sabi_get_command(sabi_config->commands.get_performance_level,
+				  &sretval);
+	if (retval)
+		return retval;
+
+	/* The logic is backwards, yeah, lots of fun... */
+	for (i = 0; sabi_config->performance_levels[i].name; ++i) {
+		if (sretval.retval[0] == sabi_config->performance_levels[i].value)
+			return sprintf(buf, "%s\n", sabi_config->performance_levels[i].name);
+	}
+	return sprintf(buf, "%s\n", "unknown");
+}
+
+static ssize_t set_performance_level(struct device *dev,
+				struct device_attribute *attr, const char *buf,
+				size_t count)
+{
+	if (count >= 1) {
+		int i;
+		for (i = 0; sabi_config->performance_levels[i].name; ++i) {
+			struct sabi_performance_level *level =
+				&sabi_config->performance_levels[i];
+			if (!strncasecmp(level->name, buf, strlen(level->name))) {
+				sabi_set_command(sabi_config->commands.set_performance_level,
+						 level->value);
+				break;
+			}
+		}
+		if (!sabi_config->performance_levels[i].name)
+			return -EINVAL;
+	}
+	return count;
+}
+static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO,
+		   get_performance_level, set_performance_level);
+
+
+static int __init dmi_check_cb(const struct dmi_system_id *id)
+{
+	pr_info("found laptop model '%s'\n",
+		id->ident);
+	return 0;
+}
+
+static struct dmi_system_id __initdata samsung_dmi_table[] = {
+	{
+		.ident = "N128",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N128"),
+			DMI_MATCH(DMI_BOARD_NAME, "N128"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "N130",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N130"),
+			DMI_MATCH(DMI_BOARD_NAME, "N130"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "X125",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X125"),
+			DMI_MATCH(DMI_BOARD_NAME, "X125"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "X120/X170",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X120/X170"),
+			DMI_MATCH(DMI_BOARD_NAME, "X120/X170"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "NC10",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "NC10"),
+			DMI_MATCH(DMI_BOARD_NAME, "NC10"),
+		},
+		.callback = dmi_check_cb,
+	},
+		{
+		.ident = "NP-Q45",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"),
+			DMI_MATCH(DMI_BOARD_NAME, "SQ45S70S"),
+		},
+		.callback = dmi_check_cb,
+		},
+	{
+		.ident = "X360",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
+			DMI_MATCH(DMI_BOARD_NAME, "X360"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "R518",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "R518"),
+			DMI_MATCH(DMI_BOARD_NAME, "R518"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "R519/R719",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "R519/R719"),
+			DMI_MATCH(DMI_BOARD_NAME, "R519/R719"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "N150/N210/N220",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
+			DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "R530/R730",
+		.matches = {
+		      DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+		      DMI_MATCH(DMI_PRODUCT_NAME, "R530/R730"),
+		      DMI_MATCH(DMI_BOARD_NAME, "R530/R730"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "NF110/NF210/NF310",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"),
+			DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "N145P/N250P/N260P",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
+			DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "R70/R71",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "R70/R71"),
+			DMI_MATCH(DMI_BOARD_NAME, "R70/R71"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
+
+static int find_signature(void __iomem *memcheck, const char *testStr)
+{
+	int i = 0;
+	int loca;
+
+	for (loca = 0; loca < 0xffff; loca++) {
+		char temp = readb(memcheck + loca);
+
+		if (temp == testStr[i]) {
+			if (i == strlen(testStr)-1)
+				break;
+			++i;
+		} else {
+			i = 0;
+		}
+	}
+	return loca;
+}
+
+static int __init samsung_init(void)
+{
+	struct backlight_properties props;
+	struct sabi_retval sretval;
+	unsigned int ifaceP;
+	int i;
+	int loca;
+	int retval;
+
+	mutex_init(&sabi_mutex);
+
+	if (!force && !dmi_check_system(samsung_dmi_table))
+		return -ENODEV;
+
+	f0000_segment = ioremap(0xf0000, 0xffff);
+	if (!f0000_segment) {
+		pr_err("Can't map the segment at 0xf0000\n");
+		return -EINVAL;
+	}
+
+	/* Try to find one of the signatures in memory to find the header */
+	for (i = 0; sabi_configs[i].test_string != 0; ++i) {
+		sabi_config = &sabi_configs[i];
+		loca = find_signature(f0000_segment, sabi_config->test_string);
+		if (loca != 0xffff)
+			break;
+	}
+
+	if (loca == 0xffff) {
+		pr_err("This computer does not support SABI\n");
+		goto error_no_signature;
+	}
+
+	/* point to the SMI port Number */
+	loca += 1;
+	sabi = (f0000_segment + loca);
+
+	if (debug) {
+		printk(KERN_DEBUG "This computer supports SABI==%x\n",
+			loca + 0xf0000 - 6);
+		printk(KERN_DEBUG "SABI header:\n");
+		printk(KERN_DEBUG " SMI Port Number = 0x%04x\n",
+			readw(sabi + sabi_config->header_offsets.port));
+		printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n",
+			readb(sabi + sabi_config->header_offsets.iface_func));
+		printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n",
+			readb(sabi + sabi_config->header_offsets.en_mem));
+		printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n",
+			readb(sabi + sabi_config->header_offsets.re_mem));
+		printk(KERN_DEBUG " SABI data offset = 0x%04x\n",
+			readw(sabi + sabi_config->header_offsets.data_offset));
+		printk(KERN_DEBUG " SABI data segment = 0x%04x\n",
+			readw(sabi + sabi_config->header_offsets.data_segment));
+	}
+
+	/* Get a pointer to the SABI Interface */
+	ifaceP = (readw(sabi + sabi_config->header_offsets.data_segment) & 0x0ffff) << 4;
+	ifaceP += readw(sabi + sabi_config->header_offsets.data_offset) & 0x0ffff;
+	sabi_iface = ioremap(ifaceP, 16);
+	if (!sabi_iface) {
+		pr_err("Can't remap %x\n", ifaceP);
+		goto exit;
+	}
+	if (debug) {
+		printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP);
+		printk(KERN_DEBUG "sabi_iface = %p\n", sabi_iface);
+
+		test_backlight();
+		test_wireless();
+
+		retval = sabi_get_command(sabi_config->commands.get_brightness,
+					  &sretval);
+		printk(KERN_DEBUG "brightness = 0x%02x\n", sretval.retval[0]);
+	}
+
+	/* Turn on "Linux" mode in the BIOS */
+	if (sabi_config->commands.set_linux != 0xff) {
+		retval = sabi_set_command(sabi_config->commands.set_linux,
+					  0x81);
+		if (retval) {
+			pr_warn("Linux mode was not set!\n");
+			goto error_no_platform;
+		}
+	}
+
+	/* knock up a platform device to hang stuff off of */
+	sdev = platform_device_register_simple("samsung", -1, NULL, 0);
+	if (IS_ERR(sdev))
+		goto error_no_platform;
+
+	/* create a backlight device to talk to this one */
+	memset(&props, 0, sizeof(struct backlight_properties));
+	props.max_brightness = MAX_BRIGHT;
+	backlight_device = backlight_device_register("samsung", &sdev->dev,
+						     NULL, &backlight_ops,
+						     &props);
+	if (IS_ERR(backlight_device))
+		goto error_no_backlight;
+
+	backlight_device->props.brightness = read_brightness();
+	backlight_device->props.power = FB_BLANK_UNBLANK;
+	backlight_update_status(backlight_device);
+
+	retval = init_wireless(sdev);
+	if (retval)
+		goto error_no_rfk;
+
+	retval = device_create_file(&sdev->dev, &dev_attr_performance_level);
+	if (retval)
+		goto error_file_create;
+
+exit:
+	return 0;
+
+error_file_create:
+	destroy_wireless();
+
+error_no_rfk:
+	backlight_device_unregister(backlight_device);
+
+error_no_backlight:
+	platform_device_unregister(sdev);
+
+error_no_platform:
+	iounmap(sabi_iface);
+
+error_no_signature:
+	iounmap(f0000_segment);
+	return -EINVAL;
+}
+
+static void __exit samsung_exit(void)
+{
+	/* Turn off "Linux" mode in the BIOS */
+	if (sabi_config->commands.set_linux != 0xff)
+		sabi_set_command(sabi_config->commands.set_linux, 0x80);
+
+	device_remove_file(&sdev->dev, &dev_attr_performance_level);
+	backlight_device_unregister(backlight_device);
+	destroy_wireless();
+	iounmap(sabi_iface);
+	iounmap(f0000_segment);
+	platform_device_unregister(sdev);
+}
+
+module_init(samsung_init);
+module_exit(samsung_exit);
+
+MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>");
+MODULE_DESCRIPTION("Samsung Backlight driver");
+MODULE_LICENSE("GPL");

^ permalink raw reply	[flat|nested] 53+ messages in thread

end of thread, other threads:[~2011-06-27 21:06 UTC | newest]

Thread overview: 53+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-02-09 22:40 [PATCH] Platform: add Samsung Laptop platform driver Greg KH
2011-02-09 22:44 ` Randy Dunlap
2011-02-09 22:50   ` Greg KH
2011-02-09 22:58     ` Matthew Garrett
2011-02-09 22:50 ` Matthew Garrett
2011-02-09 23:02   ` Greg KH
2011-02-11 11:37 ` Richard Schütz
2011-02-11 15:22   ` Greg KH
2011-02-11 16:27     ` Richard Schütz
2011-02-25 21:01       ` Greg KH
2011-02-11 15:45 ` Matthew Garrett
2011-02-11 18:42   ` Greg KH
2011-02-16 10:06 ` Nikolai Kondrashov
2011-02-25 21:03   ` Greg KH
2011-02-25 21:49     ` Nikolai Kondrashov
2011-02-25 22:50       ` Greg KH
2011-03-10  7:00         ` Nikolai Kondrashov
2011-03-10 17:01           ` Greg KH
2011-03-10 17:13             ` Nikolai Kondrashov
2011-03-10 17:19               ` Greg KH
2011-03-10 17:28                 ` Nikolai Kondrashov
2011-03-10 18:09                   ` Greg KH
2011-03-10 21:05                     ` Nikolai Kondrashov
2011-03-10 21:15                       ` Greg KH
2011-03-11  7:12                         ` Nikolai Kondrashov
2011-03-11 17:03                           ` Greg KH
2011-03-11 19:07                             ` Nikolai Kondrashov
2011-03-11 19:34                               ` Greg KH
2011-03-11 20:20                                 ` Nikolai Kondrashov
2011-03-11 20:23                                   ` Nikolai Kondrashov
2011-03-11 20:35                                     ` Greg KH
2011-03-11 20:30                                   ` Greg KH
2011-03-13 10:03                                     ` Nikolai Kondrashov
2011-03-13 10:55                                       ` Richard Schütz
2011-03-13 13:02                                         ` Nikolai Kondrashov
2011-03-13 16:18                                           ` Greg KH
2011-03-13 17:49                                             ` Nikolai Kondrashov
2011-03-13 17:58                                               ` Greg KH
2011-03-13 16:17                                       ` Greg KH
2011-03-13 16:28                                         ` Matthew Garrett
2011-03-13 17:51                                           ` Nikolai Kondrashov
2011-03-13 17:50                                         ` Nikolai Kondrashov
2011-02-25 22:47 Greg KH
2011-02-27 15:36 Greg KH
2011-03-05  4:24 Greg KH
2011-03-11 17:43 ` Matthew Garrett
2011-03-11 19:35   ` Greg KH
2011-03-11 19:44     ` Matthew Garrett
2011-03-11 19:52       ` Greg KH
2011-03-11 19:55         ` Matthew Garrett
2011-03-14 15:18           ` Jörg-Volker Peetz
2011-03-11 17:57 Tommaso Massimi
2011-06-26 15:08 J Witteveen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).