From: Greg Kroah-Hartman <[email protected]>
This adds the samsung-laptop driver to the kernel. It now supports
all known Samsung laptops.
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
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 <[email protected]>
+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 ([email protected])
+ * 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 <[email protected]>");
+MODULE_DESCRIPTION("Samsung Backlight driver");
+MODULE_LICENSE("GPL");
On Wed, 9 Feb 2011 14:40:06 -0800 Greg KH wrote:
> From: Greg Kroah-Hartman <[email protected]>
>
> This adds the samsung-laptop driver to the kernel. It now supports
> all known Samsung laptops.
>
> Signed-off-by: Greg Kroah-Hartman <[email protected]>
> ---
> 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 ***
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 <[email protected]>
> >
> > This adds the samsung-laptop driver to the kernel. It now supports
> > all known Samsung laptops.
> >
> > Signed-off-by: Greg Kroah-Hartman <[email protected]>
> > ---
> > 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
\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 | [email protected]
Nah, I'll fix that up.
--
Matthew Garrett | [email protected]
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
> +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
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
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 | [email protected]
Add DMI data for Samsung N145P/N250P/N260P
Signed-off-by: Richard Sch?tz <[email protected]>
---
> 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
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
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
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 <[email protected]>
> ---
>
> >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
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
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
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 <[email protected]>
+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 ([email protected])
+ * 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 <[email protected]>");
+MODULE_DESCRIPTION("Samsung Backlight driver");
+MODULE_LICENSE("GPL");
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
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
Hi Greg,
On Thu, Mar 10, 2011 at 7:01 PM, Greg KH <[email protected]> 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
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 <[email protected]> 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
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
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
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
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
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
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
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 <[email protected]>
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
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 <[email protected]>
> 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
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
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
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
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
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
> 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
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
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
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
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 | [email protected]
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
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
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
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