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).