Message ID | 20090821233704.GA27715@kroah.com (mailing list archive) |
---|---|
State | Not Applicable |
Headers | show |
2009/8/22 Greg KH <greg@kroah.com>: > On Sat, Aug 15, 2009 at 01:33:13PM +0100, Mike Lothian wrote: >> This is great news guys, hopefully I'll finally be able to control the >> screen brightness of my GM45 in my Samsung R510 > > Ok, as the testing with you and Jesse proved, your BIOS really is > reporting that you shouldn't be mucking around with "raw" pci config > read/write. > > I've now rewritten the Samsung driver to talk through the BIOS, thanks > to some information that someone has forwarded on to me. > > It would be great if you could test this patch out to see if it works > for your machine or not. > > You will need to load the driver with the force=1 setting set, as it > does not have your DMI values in it. > > If you do: >     modprobe samsung-laptop force=1 > and let me know what the kernel log reports, that would be wonderful. > > thanks, > > greg k-h > > --------------- > > From: Greg Kroah-Hartman <gregkh@suse.de> > Subject: Samsung laptop driver > > This driver implements backlight controls for Samsung laptops that > currently do not have ACPI support for this control. > > It has been tested on the N130 laptop and properly works there. > > Many thanks to Dmitry Torokhov <dmitry.torokhov@gmail.com> for cleanups > and other suggestions on how to make the driver simpler. > > Cc: Soeren Sonnenburg <bugreports@nn7.de> > Cc: Jérémie Huchet <jeremie@lamah.info> > Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com> > Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> > > --- >  drivers/platform/x86/Kconfig      |  12 >  drivers/platform/x86/Makefile     |   1 >  drivers/platform/x86/samsung-laptop.c |  420 ++++++++++++++++++++++++++++++++++ >  3 files changed, 433 insertions(+) > > --- a/drivers/platform/x86/Kconfig > +++ b/drivers/platform/x86/Kconfig > @@ -425,4 +425,16 @@ config ACPI_TOSHIBA > >      If you have a legacy free Toshiba laptop (such as the Libretto L1 >      series), say Y. > + > +config SAMSUNG_LAPTOP > +    tristate "Samsung Laptop driver" > +    depends on BACKLIGHT_CLASS_DEVICE > +    depends on DMI > +    ---help--- > +     This driver adds support to control the backlight on a number of > +     Samsung laptops, like the N130, and control for some of the LEDs > + > +     It will only be loaded on laptops that properly need it, so it is > +     safe to say Y here. > + >  endif # X86_PLATFORM_DEVICES > --- a/drivers/platform/x86/Makefile > +++ b/drivers/platform/x86/Makefile > @@ -20,3 +20,4 @@ obj-$(CONFIG_INTEL_MENLOW)   += intel_menl >  obj-$(CONFIG_ACPI_WMI)     += wmi.o >  obj-$(CONFIG_ACPI_ASUS)         += asus_acpi.o >  obj-$(CONFIG_ACPI_TOSHIBA)   += toshiba_acpi.o > +obj-$(CONFIG_SAMSUNG_LAPTOP)  += samsung-laptop.o > --- /dev/null > +++ b/drivers/platform/x86/samsung-laptop.c > @@ -0,0 +1,420 @@ > +/* > + * Samsung N130 and NC120 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/pci.h> > +#include <linux/backlight.h> > +#include <linux/fb.h> > +#include <linux/dmi.h> > +#include <linux/platform_device.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 > + > +/* get model returns 4 characters that describe the model of the laptop */ > +#define SABI_GET_MODEL         0x04 > + > +/* Brightness is 0 - 8, as described above.  Value 0 is for the BIOS to use */ > +#define SABI_GET_BRIGHTNESS       0x10 > +#define SABI_SET_BRIGHTNESS       0x11 > + > +/* 0 is off, 1 is on, and 2 is a second user-defined key? */ > +#define SABI_GET_WIRELESS_BUTTON    0x12 > +#define SABI_SET_WIRELESS_BUTTON    0x13 > + > +/* Temperature is returned in degress Celsius from what I can guess. */ > +#define SABI_GET_CPU_TEMP        0x29 > + > +/* 0 is off, 1 is on.  Doesn't seem to work on a N130 for some reason */ > +#define SABI_GET_BACKLIGHT       0x2d > +#define SABI_SET_BACKLIGHT       0x2e > + > +/* > + * This is different > + * There is 3 different modes here: > + *  0 - off > + *  1 - on > + *  2 - max performance mode > + * off is "normal" mode. > + * on means that whatever the bios setting for etiquette mode, is enabled.  It > + * seems that the BIOS can set either "auto" mode, or "slow" mode.  If "slow" > + * mode is set, the fan turns off, and the cpu is throttled down to not cause > + * the fan to turn on if at all possible. > + * max performance means that the processor can be overclocked and run faster > + * then is physically possible.  Ok, maybe not physically possible, but it is > + * overclocked.  Funny that the system has a setting for this... > + */ > +#define SABI_GET_ETIQUETTE_MODE         0x31 > +#define SABI_SET_ETIQUETTE_MODE         0x32 > + > +/* > + * I imagine that on some laptops there is a bluetooth switch, but I don't know > + * what that looks like, or where it is in the BIOS address space > + */ > + > + > +/* > + * SABI HEADER in low memory (f0000) > + * We need to poke through memory to find a signature in order to find the > + * exact location of this structure. > + */ > +struct sabi_header { > +    u16 portNo; > +    u8 ifaceFunc; > +    u8 enMem; > +    u8 reMem; > +    u16 dataOffset; > +    u16 dataSegment; > +    u8 BIOSifver; > +    u8 LauncherString; > +} __attribute__((packed)); > + > +/* > + * The SABI interface that we use to write and read values from the system. > + * It is found by looking at the dataOffset and dataSegment values in the sabi > + * header structure > + */ > +struct sabi_interface { > +    u16 mainfunc; > +    u16 subfunc; > +    u8 complete; > +    u8 retval[20]; > +} __attribute__((packed)); > + > +/* Structure to get data back to the calling function */ > +struct sabi_retval { > +    u8 retval[20]; > +}; > + > +static struct sabi_header __iomem *sabi; > +static struct sabi_interface __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 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; > + > +    mutex_lock(&sabi_mutex); > + > +    /* enable memory to be able to write to it */ > +    outb(readb(&sabi->enMem), readw(&sabi->portNo)); > + > +    /* write out the command */ > +    writew(0x5843, &sabi_iface->mainfunc); > +    writew(command, &sabi_iface->subfunc); > +    writeb(0, &sabi_iface->complete); > +    outb(readb(&sabi->ifaceFunc), readw(&sabi->portNo)); > + > +    /* sleep for a bit to let the command complete */ > +    msleep(100); > + > +    /* write protect memory to make it safe */ > +    outb(readb(&sabi->reMem), readw(&sabi->portNo)); > + > +    /* see if the command actually succeeded */ > +    if (readb(&sabi_iface->complete) == 0xaa && > +      readb(&sabi_iface->retval[0]) != 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->retval[0]); > +        sretval->retval[1] = readb(&sabi_iface->retval[1]); > +        sretval->retval[2] = readb(&sabi_iface->retval[2]); > +        sretval->retval[3] = readb(&sabi_iface->retval[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->complete), > +        readb(&sabi_iface->retval[0])); > +    retval = -EINVAL; > +exit: > +    mutex_unlock(&sabi_mutex); > +    return retval; > + > +} > + > +static int sabi_set_command(u8 command, u8 data) > +{ > +    int retval = 0; > + > +    mutex_lock(&sabi_mutex); > + > +    /* enable memory to be able to write to it */ > +    outb(readb(&sabi->enMem), readw(&sabi->portNo)); > + > +    /* write out the command */ > +    writew(0x5843, &sabi_iface->mainfunc); > +    writew(command, &sabi_iface->subfunc); > +    writeb(0, &sabi_iface->complete); > +    writeb(data, &sabi_iface->retval[0]); > +    outb(readb(&sabi->ifaceFunc), readw(&sabi->portNo)); > + > +    /* sleep for a bit to let the command complete */ > +    msleep(100); > + > +    /* write protect memory to make it safe */ > +    outb(readb(&sabi->reMem), readw(&sabi->portNo)); > + > +    /* see if the command actually succeeded */ > +    if (readb(&sabi_iface->complete) == 0xaa && > +      readb(&sabi_iface->retval[0]) != 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->complete), > +        readb(&sabi_iface->retval[0])); > +    retval = -EINVAL; > +exit: > +    mutex_unlock(&sabi_mutex); > +    return retval; > +} > + > +static u8 read_brightness(void) > +{ > +    struct sabi_retval sretval; > +    int user_brightness = 0; > +    int retval; > + > +    retval = sabi_get_command(SABI_GET_BACKLIGHT, &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_SET_BRIGHTNESS, user_brightness + 1); > +} > + > +static int get_brightness(struct backlight_device *bd) > +{ > +    return bd->props.brightness; > +} > + > +static int update_status(struct backlight_device *bd) > +{ > +    set_brightness(bd->props.brightness); > +    return 0; > +} > + > +static struct backlight_ops backlight_ops = { > +    .get_brightness = get_brightness, > +    .update_status  = update_status, > +}; > + > +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 = "N120", > +        .matches = { > +            DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), > +            DMI_MATCH(DMI_PRODUCT_NAME, "N120"), > +            DMI_MATCH(DMI_BOARD_NAME, "N120"), > +        }, > +        .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, > +    }, > +    { }, > +}; > + > + > +static int __init samsung_init(void) > +{ > +    struct sabi_retval sretval; > +    const char *testStr = "SwSmi@"; > +    void __iomem *memcheck; > +    unsigned int ifaceP; > +    int pStr; > +    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 the signature "SwSmi@" in memory to find the header */ > +    pStr = 0; > +    memcheck = f0000_segment; > +    for (loca = 0; loca < 0xffff; loca++) { > +        char temp = readb(memcheck + loca); > + > +        if (temp == testStr[pStr]) { > +            if (pStr == 5) > +                break; > +            ++pStr; > +        } else { > +            pStr = 0; > +        } > +    } > +    if (loca == 0xffff) { > +        printk(KERN_INFO "This computer does not support SABI\n"); > +        goto error_no_signature; > +        } > + > +    /* point to the SMI port Number */ > +    loca += 1; > +    sabi = (struct sabi_header __iomem *)(loca + memcheck); > +    if (!sabi) { > +        printk(KERN_ERR "Can't remap %p\n", loca + memcheck); > +        goto exit; > +    } > + > +    printk(KERN_INFO "This computer supports SABI==%x\n", loca + 0xf0000 - 6); > +    printk(KERN_INFO "SABI header:\n"); > +    printk(KERN_INFO " SMI Port Number = 0x%04x\n", readw(&sabi->portNo)); > +    printk(KERN_INFO " SMI Interface Function = 0x%02x\n", readb(&sabi->ifaceFunc)); > +    printk(KERN_INFO " SMI enable memory buffer = 0x%02x\n", readb(&sabi->enMem)); > +    printk(KERN_INFO " SMI restore memory buffer = 0x%02x\n", readb(&sabi->reMem)); > +    printk(KERN_INFO " SABI data offset = 0x%04x\n", readw(&sabi->dataOffset)); > +    printk(KERN_INFO " SABI data segment = 0x%04x\n", readw(&sabi->dataSegment)); > +    printk(KERN_INFO " BIOS interface version = 0x%02x\n", readb(&sabi->BIOSifver)); > +    printk(KERN_INFO " KBD Launcher string = 0x%02x\n", readb(&sabi->LauncherString)); > + > +    /* Get a pointer to the SABI Interface */ > +    ifaceP = (readw(&sabi->dataSegment) & 0x0ffff) << 4; > +    ifaceP += readw(&sabi->dataOffset) & 0x0ffff; > +    sabi_iface = (struct sabi_interface __iomem *)ioremap(ifaceP, 16); > +    if (!sabi_iface) { > +        printk(KERN_ERR "Can't remap %x\n", ifaceP); > +        goto exit; > +    } > +    printk(KERN_INFO "SABI Interface = %p\n", sabi_iface); > + > +    retval = sabi_get_command(SABI_GET_MODEL, &sretval); > +    if (!retval) { > +        printk(KERN_INFO "Model Name %c%c%c%c\n", > +            sretval.retval[0], > +            sretval.retval[1], > +            sretval.retval[2], > +            sretval.retval[3]); > +    } > + > +    retval = sabi_get_command(SABI_GET_BACKLIGHT, &sretval); > +    if (!retval) > +        printk("backlight = 0x%02x\n", sretval.retval[0]); > + > +    retval = sabi_get_command(SABI_GET_WIRELESS_BUTTON, &sretval); > +    if (!retval) > +        printk("wireless button = 0x%02x\n", sretval.retval[0]); > + > +    retval = sabi_get_command(SABI_GET_BRIGHTNESS, &sretval); > +    if (!retval) > +        printk("brightness = 0x%02x\n", sretval.retval[0]); > + > +    retval = sabi_get_command(SABI_GET_ETIQUETTE_MODE, &sretval); > +    if (!retval) > +        printk("etiquette mode = 0x%02x\n", sretval.retval[0]); > +    retval = sabi_get_command(SABI_GET_CPU_TEMP, &sretval); > +    if (!retval) > +        printk("cpu temp = 0x%02x\n", sretval.retval[0]); > + > +    /* 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 */ > +    backlight_device = backlight_device_register("samsung", &sdev->dev, > +                           NULL, &backlight_ops); > +    if (IS_ERR(backlight_device)) > +        goto error_no_backlight; > + > +    backlight_device->props.max_brightness = MAX_BRIGHT; > +    backlight_device->props.brightness = read_brightness(); > +    backlight_device->props.power = FB_BLANK_UNBLANK; > +    backlight_update_status(backlight_device); > + > +exit: > +    return 0; > + > +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) > +{ > +    backlight_device_unregister(backlight_device); > +    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"); > +MODULE_ALIAS("dmi:*:svnSAMSUNGELECTRONICSCO.,LTD.:pnN120:*:rnN120:*"); > +MODULE_ALIAS("dmi:*:svnSAMSUNGELECTRONICSCO.,LTD.:pnN130:*:rnN130:*"); > I can confirm that it works however it does have different behaviour At the lowest setting the backlight is still on and the screen even though dull is still readable with the previous patch the screen was black This is what it says in my dmesg: This computer supports SABI==f494d 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 BIOS interface version = 0x32 KBD Launcher string = 0x53 SABI Interface = ffff8800000dff10 Model Name R510 backlight = 0x01 wireless button = 0x01 brightness = 0x08 etiquette mode = 0x00 cpu temp = 0x45 Do you have any idea why my brightness buttons aren't working correctly? Thanks for you help with this Mike
2009/8/22 Greg KH <greg@kroah.com>: > On Sat, Aug 15, 2009 at 01:33:13PM +0100, Mike Lothian wrote: >> This is great news guys, hopefully I'll finally be able to control the >> screen brightness of my GM45 in my Samsung R510 > > Ok, as the testing with you and Jesse proved, your BIOS really is > reporting that you shouldn't be mucking around with "raw" pci config > read/write. > > I've now rewritten the Samsung driver to talk through the BIOS, thanks > to some information that someone has forwarded on to me. > > It would be great if you could test this patch out to see if it works > for your machine or not. > > You will need to load the driver with the force=1 setting set, as it > does not have your DMI values in it. > > If you do: >     modprobe samsung-laptop force=1 > and let me know what the kernel log reports, that would be wonderful. > > thanks, > > greg k-h > > --------------- > > From: Greg Kroah-Hartman <gregkh@suse.de> > Subject: Samsung laptop driver > > This driver implements backlight controls for Samsung laptops that > currently do not have ACPI support for this control. > > It has been tested on the N130 laptop and properly works there. > > Many thanks to Dmitry Torokhov <dmitry.torokhov@gmail.com> for cleanups > and other suggestions on how to make the driver simpler. > > Cc: Soeren Sonnenburg <bugreports@nn7.de> > Cc: Jérémie Huchet <jeremie@lamah.info> > Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com> > Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> > > --- >  drivers/platform/x86/Kconfig      |  12 >  drivers/platform/x86/Makefile     |   1 >  drivers/platform/x86/samsung-laptop.c |  420 ++++++++++++++++++++++++++++++++++ >  3 files changed, 433 insertions(+) > > --- a/drivers/platform/x86/Kconfig > +++ b/drivers/platform/x86/Kconfig > @@ -425,4 +425,16 @@ config ACPI_TOSHIBA > >      If you have a legacy free Toshiba laptop (such as the Libretto L1 >      series), say Y. > + > +config SAMSUNG_LAPTOP > +    tristate "Samsung Laptop driver" > +    depends on BACKLIGHT_CLASS_DEVICE > +    depends on DMI > +    ---help--- > +     This driver adds support to control the backlight on a number of > +     Samsung laptops, like the N130, and control for some of the LEDs > + > +     It will only be loaded on laptops that properly need it, so it is > +     safe to say Y here. > + >  endif # X86_PLATFORM_DEVICES > --- a/drivers/platform/x86/Makefile > +++ b/drivers/platform/x86/Makefile > @@ -20,3 +20,4 @@ obj-$(CONFIG_INTEL_MENLOW)   += intel_menl >  obj-$(CONFIG_ACPI_WMI)     += wmi.o >  obj-$(CONFIG_ACPI_ASUS)         += asus_acpi.o >  obj-$(CONFIG_ACPI_TOSHIBA)   += toshiba_acpi.o > +obj-$(CONFIG_SAMSUNG_LAPTOP)  += samsung-laptop.o > --- /dev/null > +++ b/drivers/platform/x86/samsung-laptop.c > @@ -0,0 +1,420 @@ > +/* > + * Samsung N130 and NC120 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/pci.h> > +#include <linux/backlight.h> > +#include <linux/fb.h> > +#include <linux/dmi.h> > +#include <linux/platform_device.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 > + > +/* get model returns 4 characters that describe the model of the laptop */ > +#define SABI_GET_MODEL         0x04 > + > +/* Brightness is 0 - 8, as described above.  Value 0 is for the BIOS to use */ > +#define SABI_GET_BRIGHTNESS       0x10 > +#define SABI_SET_BRIGHTNESS       0x11 > + > +/* 0 is off, 1 is on, and 2 is a second user-defined key? */ > +#define SABI_GET_WIRELESS_BUTTON    0x12 > +#define SABI_SET_WIRELESS_BUTTON    0x13 > + > +/* Temperature is returned in degress Celsius from what I can guess. */ > +#define SABI_GET_CPU_TEMP        0x29 > + > +/* 0 is off, 1 is on.  Doesn't seem to work on a N130 for some reason */ > +#define SABI_GET_BACKLIGHT       0x2d > +#define SABI_SET_BACKLIGHT       0x2e > + > +/* > + * This is different > + * There is 3 different modes here: > + *  0 - off > + *  1 - on > + *  2 - max performance mode > + * off is "normal" mode. > + * on means that whatever the bios setting for etiquette mode, is enabled.  It > + * seems that the BIOS can set either "auto" mode, or "slow" mode.  If "slow" > + * mode is set, the fan turns off, and the cpu is throttled down to not cause > + * the fan to turn on if at all possible. > + * max performance means that the processor can be overclocked and run faster > + * then is physically possible.  Ok, maybe not physically possible, but it is > + * overclocked.  Funny that the system has a setting for this... > + */ > +#define SABI_GET_ETIQUETTE_MODE         0x31 > +#define SABI_SET_ETIQUETTE_MODE         0x32 > + > +/* > + * I imagine that on some laptops there is a bluetooth switch, but I don't know > + * what that looks like, or where it is in the BIOS address space > + */ > + > + > +/* > + * SABI HEADER in low memory (f0000) > + * We need to poke through memory to find a signature in order to find the > + * exact location of this structure. > + */ > +struct sabi_header { > +    u16 portNo; > +    u8 ifaceFunc; > +    u8 enMem; > +    u8 reMem; > +    u16 dataOffset; > +    u16 dataSegment; > +    u8 BIOSifver; > +    u8 LauncherString; > +} __attribute__((packed)); > + > +/* > + * The SABI interface that we use to write and read values from the system. > + * It is found by looking at the dataOffset and dataSegment values in the sabi > + * header structure > + */ > +struct sabi_interface { > +    u16 mainfunc; > +    u16 subfunc; > +    u8 complete; > +    u8 retval[20]; > +} __attribute__((packed)); > + > +/* Structure to get data back to the calling function */ > +struct sabi_retval { > +    u8 retval[20]; > +}; > + > +static struct sabi_header __iomem *sabi; > +static struct sabi_interface __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 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; > + > +    mutex_lock(&sabi_mutex); > + > +    /* enable memory to be able to write to it */ > +    outb(readb(&sabi->enMem), readw(&sabi->portNo)); > + > +    /* write out the command */ > +    writew(0x5843, &sabi_iface->mainfunc); > +    writew(command, &sabi_iface->subfunc); > +    writeb(0, &sabi_iface->complete); > +    outb(readb(&sabi->ifaceFunc), readw(&sabi->portNo)); > + > +    /* sleep for a bit to let the command complete */ > +    msleep(100); > + > +    /* write protect memory to make it safe */ > +    outb(readb(&sabi->reMem), readw(&sabi->portNo)); > + > +    /* see if the command actually succeeded */ > +    if (readb(&sabi_iface->complete) == 0xaa && > +      readb(&sabi_iface->retval[0]) != 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->retval[0]); > +        sretval->retval[1] = readb(&sabi_iface->retval[1]); > +        sretval->retval[2] = readb(&sabi_iface->retval[2]); > +        sretval->retval[3] = readb(&sabi_iface->retval[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->complete), > +        readb(&sabi_iface->retval[0])); > +    retval = -EINVAL; > +exit: > +    mutex_unlock(&sabi_mutex); > +    return retval; > + > +} > + > +static int sabi_set_command(u8 command, u8 data) > +{ > +    int retval = 0; > + > +    mutex_lock(&sabi_mutex); > + > +    /* enable memory to be able to write to it */ > +    outb(readb(&sabi->enMem), readw(&sabi->portNo)); > + > +    /* write out the command */ > +    writew(0x5843, &sabi_iface->mainfunc); > +    writew(command, &sabi_iface->subfunc); > +    writeb(0, &sabi_iface->complete); > +    writeb(data, &sabi_iface->retval[0]); > +    outb(readb(&sabi->ifaceFunc), readw(&sabi->portNo)); > + > +    /* sleep for a bit to let the command complete */ > +    msleep(100); > + > +    /* write protect memory to make it safe */ > +    outb(readb(&sabi->reMem), readw(&sabi->portNo)); > + > +    /* see if the command actually succeeded */ > +    if (readb(&sabi_iface->complete) == 0xaa && > +      readb(&sabi_iface->retval[0]) != 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->complete), > +        readb(&sabi_iface->retval[0])); > +    retval = -EINVAL; > +exit: > +    mutex_unlock(&sabi_mutex); > +    return retval; > +} > + > +static u8 read_brightness(void) > +{ > +    struct sabi_retval sretval; > +    int user_brightness = 0; > +    int retval; > + > +    retval = sabi_get_command(SABI_GET_BACKLIGHT, &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_SET_BRIGHTNESS, user_brightness + 1); > +} > + > +static int get_brightness(struct backlight_device *bd) > +{ > +    return bd->props.brightness; > +} > + > +static int update_status(struct backlight_device *bd) > +{ > +    set_brightness(bd->props.brightness); > +    return 0; > +} > + > +static struct backlight_ops backlight_ops = { > +    .get_brightness = get_brightness, > +    .update_status  = update_status, > +}; > + > +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 = "N120", > +        .matches = { > +            DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), > +            DMI_MATCH(DMI_PRODUCT_NAME, "N120"), > +            DMI_MATCH(DMI_BOARD_NAME, "N120"), > +        }, > +        .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, > +    }, > +    { }, > +}; > + > + > +static int __init samsung_init(void) > +{ > +    struct sabi_retval sretval; > +    const char *testStr = "SwSmi@"; > +    void __iomem *memcheck; > +    unsigned int ifaceP; > +    int pStr; > +    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 the signature "SwSmi@" in memory to find the header */ > +    pStr = 0; > +    memcheck = f0000_segment; > +    for (loca = 0; loca < 0xffff; loca++) { > +        char temp = readb(memcheck + loca); > + > +        if (temp == testStr[pStr]) { > +            if (pStr == 5) > +                break; > +            ++pStr; > +        } else { > +            pStr = 0; > +        } > +    } > +    if (loca == 0xffff) { > +        printk(KERN_INFO "This computer does not support SABI\n"); > +        goto error_no_signature; > +        } > + > +    /* point to the SMI port Number */ > +    loca += 1; > +    sabi = (struct sabi_header __iomem *)(loca + memcheck); > +    if (!sabi) { > +        printk(KERN_ERR "Can't remap %p\n", loca + memcheck); > +        goto exit; > +    } > + > +    printk(KERN_INFO "This computer supports SABI==%x\n", loca + 0xf0000 - 6); > +    printk(KERN_INFO "SABI header:\n"); > +    printk(KERN_INFO " SMI Port Number = 0x%04x\n", readw(&sabi->portNo)); > +    printk(KERN_INFO " SMI Interface Function = 0x%02x\n", readb(&sabi->ifaceFunc)); > +    printk(KERN_INFO " SMI enable memory buffer = 0x%02x\n", readb(&sabi->enMem)); > +    printk(KERN_INFO " SMI restore memory buffer = 0x%02x\n", readb(&sabi->reMem)); > +    printk(KERN_INFO " SABI data offset = 0x%04x\n", readw(&sabi->dataOffset)); > +    printk(KERN_INFO " SABI data segment = 0x%04x\n", readw(&sabi->dataSegment)); > +    printk(KERN_INFO " BIOS interface version = 0x%02x\n", readb(&sabi->BIOSifver)); > +    printk(KERN_INFO " KBD Launcher string = 0x%02x\n", readb(&sabi->LauncherString)); > + > +    /* Get a pointer to the SABI Interface */ > +    ifaceP = (readw(&sabi->dataSegment) & 0x0ffff) << 4; > +    ifaceP += readw(&sabi->dataOffset) & 0x0ffff; > +    sabi_iface = (struct sabi_interface __iomem *)ioremap(ifaceP, 16); > +    if (!sabi_iface) { > +        printk(KERN_ERR "Can't remap %x\n", ifaceP); > +        goto exit; > +    } > +    printk(KERN_INFO "SABI Interface = %p\n", sabi_iface); > + > +    retval = sabi_get_command(SABI_GET_MODEL, &sretval); > +    if (!retval) { > +        printk(KERN_INFO "Model Name %c%c%c%c\n", > +            sretval.retval[0], > +            sretval.retval[1], > +            sretval.retval[2], > +            sretval.retval[3]); > +    } > + > +    retval = sabi_get_command(SABI_GET_BACKLIGHT, &sretval); > +    if (!retval) > +        printk("backlight = 0x%02x\n", sretval.retval[0]); > + > +    retval = sabi_get_command(SABI_GET_WIRELESS_BUTTON, &sretval); > +    if (!retval) > +        printk("wireless button = 0x%02x\n", sretval.retval[0]); > + > +    retval = sabi_get_command(SABI_GET_BRIGHTNESS, &sretval); > +    if (!retval) > +        printk("brightness = 0x%02x\n", sretval.retval[0]); > + > +    retval = sabi_get_command(SABI_GET_ETIQUETTE_MODE, &sretval); > +    if (!retval) > +        printk("etiquette mode = 0x%02x\n", sretval.retval[0]); > +    retval = sabi_get_command(SABI_GET_CPU_TEMP, &sretval); > +    if (!retval) > +        printk("cpu temp = 0x%02x\n", sretval.retval[0]); > + > +    /* 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 */ > +    backlight_device = backlight_device_register("samsung", &sdev->dev, > +                           NULL, &backlight_ops); > +    if (IS_ERR(backlight_device)) > +        goto error_no_backlight; > + > +    backlight_device->props.max_brightness = MAX_BRIGHT; > +    backlight_device->props.brightness = read_brightness(); > +    backlight_device->props.power = FB_BLANK_UNBLANK; > +    backlight_update_status(backlight_device); > + > +exit: > +    return 0; > + > +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) > +{ > +    backlight_device_unregister(backlight_device); > +    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"); > +MODULE_ALIAS("dmi:*:svnSAMSUNGELECTRONICSCO.,LTD.:pnN120:*:rnN120:*"); > +MODULE_ALIAS("dmi:*:svnSAMSUNGELECTRONICSCO.,LTD.:pnN130:*:rnN130:*"); > Also the previous driver felt like it had finer grained control I also think the maximum brightness setting was brighter too I'll play around some more and see if this is the case Mike
On Sat, Aug 22, 2009 at 10:27:58AM +0100, Mike Lothian wrote:
> Do you have any idea why my brightness buttons aren't working correctly?
The previous code would have let you set the brightness to the entire
range supported by the GPU, which may be outside the specs of your
backlight. The new one limits it to the range that the hardware is
designed to use.
2009/8/24 Matthew Garrett <mjg59@srcf.ucam.org>: > On Sat, Aug 22, 2009 at 10:27:58AM +0100, Mike Lothian wrote: > >> Do you have any idea why my brightness buttons aren't working correctly? > > The previous code would have let you set the brightness to the entire > range supported by the GPU, which may be outside the specs of your > backlight. The new one limits it to the range that the hardware is > designed to use. > > -- > Matthew Garrett | mjg59@srcf.ucam.org > If it's the BIOS that's telling the driver what's the limits are, we've already established my BIOS is garbage, perhaps this isn't the most reliable source of information Now for the line I cringe at - under Vista 32bit (the only OS to control the backlight before your patches) has full control of the backlight from it's brightest setting to switched off Being able to switch the backlight off through this control has a lot of power saving advantages I'd be greatful for a better solution in this case or at a worse case scenario including both drivers Cheers Mike
On Sat, Aug 22, 2009 at 10:41:15AM +0100, Mike Lothian wrote: > > Also the previous driver felt like it had finer grained control I also > think the maximum brightness setting was brighter too Yes, it did have finer granularity (0-255), vs. 0-7. The brightest value should be identical, but 0 will not turn off the light, that is on purpose. Turns out that people don't like their screens to be turned off when booting :) thanks, greg k-h
On Sat, Aug 22, 2009 at 10:27:58AM +0100, Mike Lothian wrote: > I can confirm that it works however it does have different behaviour > > At the lowest setting the backlight is still on and the screen even > though dull is still readable with the previous patch the screen was > black > > This is what it says in my dmesg: > > This computer supports SABI==f494d > 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 > BIOS interface version = 0x32 > KBD Launcher string = 0x53 > SABI Interface = ffff8800000dff10 > Model Name R510 > backlight = 0x01 > wireless button = 0x01 > brightness = 0x08 > etiquette mode = 0x00 > cpu temp = 0x45 Thanks. Can you provide me the output of: grep . /sys/class/dmi/id/* So I can add this laptop to the driver? > Do you have any idea why my brightness buttons aren't working correctly? See the other responses, they are working "correctly" now, a 0 setting will not turn off the light, as it is not supposed to. thanks, greg k-h
On Wed, Aug 26, 2009 at 08:34:10AM +0100, Mike Lothian wrote: > 2009/8/24 Matthew Garrett <mjg59@srcf.ucam.org>: > > On Sat, Aug 22, 2009 at 10:27:58AM +0100, Mike Lothian wrote: > > > >> Do you have any idea why my brightness buttons aren't working correctly? > > > > The previous code would have let you set the brightness to the entire > > range supported by the GPU, which may be outside the specs of your > > backlight. The new one limits it to the range that the hardware is > > designed to use. > > > > -- > > Matthew Garrett | mjg59@srcf.ucam.org > > > > If it's the BIOS that's telling the driver what's the limits are, > we've already established my BIOS is garbage, perhaps this isn't the > most reliable source of information > > Now for the line I cringe at - under Vista 32bit (the only OS to > control the backlight before your patches) has full control of the > backlight from it's brightest setting to switched off > > Being able to switch the backlight off through this control has a lot > of power saving advantages Yes, I need to figure out how to turn the light off "properly", am still working on that. Windows is _heavily_ patched by Samsung to use this interface (you will notice a sabi.dll somewhere on that box that handles all of this "magic"). Maybe someday Samsung will switch to using ACPI for this kind of thing, which is the correct solution. thanks, greg k-h
tau / # grep . /sys/class/dmi/id/* /sys/class/dmi/id/bios_date:09/26/2008 /sys/class/dmi/id/bios_vendor:Phoenix Technologies Ltd. /sys/class/dmi/id/bios_version:07LI.MP00.20080926.SCY /sys/class/dmi/id/board_name:R510/P510 /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.:bvr07LI.MP00.20080926.SCY:bd09/26/2008:svnSAMSUNGELECTRONICSCO.,LTD.:pnR510/P510:pvrNotApplicable:rvnSAMSUNGELECTRONICSCO.,LTD.:rnR510/P510:rvrNotApplicable:cvnSAMSUNGELECTRONICSCO.,LTD.:ct10:cvrN/A: /sys/class/dmi/id/product_name:R510/P510 /sys/class/dmi/id/product_serial:EJ1893DQ700599 /sys/class/dmi/id/product_uuid:60B6C327-D21D-B211-8000-B5CE02D5709F /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.:bvr07LI.MP00.20080926.SCY:bd09/26/2008:svnSAMSUNGELECTRONICSCO.,LTD.:pnR510/P510:pvrNotApplicable:rvnSAMSUNGELECTRONICSCO.,LTD.:rnR510/P510:rvrNotApplicable:cvnSAMSUNGELECTRONICSCO.,LTD.:ct10:cvrN/A: This is the info you requested I've sent it before Is there a way to make the brightness more finer controlled using this interface? Regards Mike 2009/8/26 Greg KH <greg@kroah.com>: > On Sat, Aug 22, 2009 at 10:27:58AM +0100, Mike Lothian wrote: >> I can confirm that it works however it does have different behaviour >> >> At the lowest setting the backlight is still on and the screen even >> though dull is still readable with the previous patch the screen was >> black >> >> This is what it says in my dmesg: >> >> This computer supports SABI==f494d >> 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 >> Â BIOS interface version = 0x32 >> Â KBD Launcher string = 0x53 >> SABI Interface = ffff8800000dff10 >> Model Name R510 >> backlight = 0x01 >> wireless button = 0x01 >> brightness = 0x08 >> etiquette mode = 0x00 >> cpu temp = 0x45 > > Thanks. > > Can you provide me the output of: > Â Â Â Â grep . /sys/class/dmi/id/* > > So I can add this laptop to the driver? > >> Do you have any idea why my brightness buttons aren't working correctly? > > See the other responses, they are working "correctly" now, a 0 setting > will not turn off the light, as it is not supposed to. > > thanks, > > greg k-h >
2009/8/26 Greg KH <greg@kroah.com>: > On Sat, Aug 22, 2009 at 10:27:58AM +0100, Mike Lothian wrote > >> Do you have any idea why my brightness buttons aren't working correctly? > > See the other responses, they are working "correctly" now, a 0 setting > will not turn off the light, as it is not supposed to. What other responses?
2009/8/26 Mike Lothian <mike@fireburn.co.uk>: > 2009/8/26 Greg KH <greg@kroah.com>: >> On Sat, Aug 22, 2009 at 10:27:58AM +0100, Mike Lothian wrote >> >>> Do you have any idea why my brightness buttons aren't working correctly? >> >> See the other responses, they are working "correctly" now, a 0 setting >> will not turn off the light, as it is not supposed to. > > What other responses? > I think the problem maybe due to the intel KMS driver not exporting BACKLIGHT information via Xrandr ie xbacklight doesn't work Also using the previous patch the one with 255 settings, once the brightness goes low enough to switch of the backlight the backlight refuses to come back on no matter what is value is then set Regards Mike
On Sat, Aug 29, 2009 at 10:16:54PM +0100, Mike Lothian wrote: > 2009/8/26 Mike Lothian <mike@fireburn.co.uk>: > > 2009/8/26 Greg KH <greg@kroah.com>: > >> On Sat, Aug 22, 2009 at 10:27:58AM +0100, Mike Lothian wrote > >> > >>> Do you have any idea why my brightness buttons aren't working correctly? > >> > >> See the other responses, they are working "correctly" now, a 0 setting > >> will not turn off the light, as it is not supposed to. > > > > What other responses? > > > > I think the problem maybe due to the intel KMS driver not exporting > BACKLIGHT information via Xrandr ie xbacklight doesn't work > > Also using the previous patch the one with 255 settings, once the > brightness goes low enough to switch of the backlight the backlight > refuses to come back on no matter what is value is then set Yes, this is because poking the PCI config register is not the "proper" way to do this for this hardware platform. thanks, greg k-h
On Wed, Aug 26, 2009 at 10:53:46PM +0100, Mike Lothian wrote: > tau / # grep . /sys/class/dmi/id/* > /sys/class/dmi/id/bios_date:09/26/2008 > /sys/class/dmi/id/bios_vendor:Phoenix Technologies Ltd. > /sys/class/dmi/id/bios_version:07LI.MP00.20080926.SCY > /sys/class/dmi/id/board_name:R510/P510 > /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.:bvr07LI.MP00.20080926.SCY:bd09/26/2008:svnSAMSUNGELECTRONICSCO.,LTD.:pnR510/P510:pvrNotApplicable:rvnSAMSUNGELECTRONICSCO.,LTD.:rnR510/P510:rvrNotApplicable:cvnSAMSUNGELECTRONICSCO.,LTD.:ct10:cvrN/A: > /sys/class/dmi/id/product_name:R510/P510 > /sys/class/dmi/id/product_serial:EJ1893DQ700599 > /sys/class/dmi/id/product_uuid:60B6C327-D21D-B211-8000-B5CE02D5709F > /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.:bvr07LI.MP00.20080926.SCY:bd09/26/2008:svnSAMSUNGELECTRONICSCO.,LTD.:pnR510/P510:pvrNotApplicable:rvnSAMSUNGELECTRONICSCO.,LTD.:rnR510/P510:rvrNotApplicable:cvnSAMSUNGELECTRONICSCO.,LTD.:ct10:cvrN/A: > > This is the info you requested Thanks, I've added it to the driver now. > I've sent it before Ick, sorry, I must have missed that. > Is there a way to make the brightness more finer controlled using this > interface? Not that I know of, sorry, it looks like the hardware is only allowing this to be changed in 8 levels of increments. Windows should work this same way, right? thanks, greg k-h
On Aug 31, 09 10:54:29 -0700, Greg KH wrote: > > Is there a way to make the brightness more finer controlled using this > > interface? > Not that I know of, sorry, it looks like the hardware is only allowing > this to be changed in 8 levels of increments. Windows should work this > same way, right? AFAIR at one point you deliberately decided to expose only 8 levels to the user - while the hardware was capable of more levels (I think it was something about some user land tool expecting something like that). But I may be utterly wrong. I'd love to have more fine grained control on my NC10 as well. Thanks for the work so far Matthias
On Aug 29, 09 22:16:54 +0100, Mike Lothian wrote: > I think the problem maybe due to the intel KMS driver not exporting > BACKLIGHT information via Xrandr ie xbacklight doesn't work That is fixed in git master. It's also called "Backlight" now (according to RandR style guides), with BACKLIGHT as a fallback. Matthias
On Tue, Sep 08, 2009 at 06:05:03PM +0200, Matthias Hopf wrote: > On Aug 31, 09 10:54:29 -0700, Greg KH wrote: > > > Is there a way to make the brightness more finer controlled using this > > > interface? > > Not that I know of, sorry, it looks like the hardware is only allowing > > this to be changed in 8 levels of increments. Windows should work this > > same way, right? > > AFAIR at one point you deliberately decided to expose only 8 levels to > the user - while the hardware was capable of more levels (I think it was > something about some user land tool expecting something like that). > But I may be utterly wrong. Yes, that was when we were blindly poking in the PCI config space. We aren't supposed to be doing that :) > I'd love to have more fine grained control on my NC10 as well. I have reports that Windows also only supports 8 levels, so that is what this hardware controller is possible of supporting, sorry. thanks, greg k-h
2009/9/8 Matthias Hopf <mhopf@suse.de>: > On Aug 29, 09 22:16:54 +0100, Mike Lothian wrote: >> I think the problem maybe due to the intel KMS driver not exporting >> BACKLIGHT information via Xrandr ie xbacklight doesn't work > > That is fixed in git master. It's also called "Backlight" now (according > to RandR style guides), with BACKLIGHT as a fallback. > I'm using the latest git however the backlight property isn't exported in either case. I'm using a GM45 if this is significant Cheers Mike
On Sep 08, 09 09:31:24 -0700, Greg KH wrote: > > AFAIR at one point you deliberately decided to expose only 8 levels to > > the user - while the hardware was capable of more levels (I think it was > > something about some user land tool expecting something like that). > > But I may be utterly wrong. > > Yes, that was when we were blindly poking in the PCI config space. We > aren't supposed to be doing that :) > > > I'd love to have more fine grained control on my NC10 as well. > > I have reports that Windows also only supports 8 levels, so that is what > this hardware controller is possible of supporting, sorry. Hm. This is contradicting. On the one hand the hardware is capable of more levels. On the other it isn't *reporting* more levels. I wouldn't rely on anything what Windows supports. There can be arbitrary limitations in the driver. Matthias
On Wed, Sep 09, 2009 at 01:04:15PM +0200, Matthias Hopf wrote: > On Sep 08, 09 09:31:24 -0700, Greg KH wrote: > > > AFAIR at one point you deliberately decided to expose only 8 levels to > > > the user - while the hardware was capable of more levels (I think it was > > > something about some user land tool expecting something like that). > > > But I may be utterly wrong. > > > > Yes, that was when we were blindly poking in the PCI config space. We > > aren't supposed to be doing that :) > > > > > I'd love to have more fine grained control on my NC10 as well. > > > > I have reports that Windows also only supports 8 levels, so that is what > > this hardware controller is possible of supporting, sorry. > > Hm. This is contradicting. On the one hand the hardware is capable of > more levels. On the other it isn't *reporting* more levels. > > I wouldn't rely on anything what Windows supports. There can be > arbitrary limitations in the driver. The hardware seems to allow multiple levels if you poke a raw value into a random PCI config location. However, this is not the correct way to control this hardware, a SMI call needs to be made instead. And for that call, only 8 levels are available. So it's not a limitation in the Windows driver, it is a limitation in the BIOS provided by the manufacturer. thanks, greg k-h
2009/9/9 Matthias Hopf <mhopf@suse.de>: > On Sep 08, 09 22:51:11 +0100, Mike Lothian wrote: >> 2009/9/8 Matthias Hopf <mhopf@suse.de>: >> > On Aug 29, 09 22:16:54 +0100, Mike Lothian wrote: >> >> I think the problem maybe due to the intel KMS driver not exporting >> >> BACKLIGHT information via Xrandr ie xbacklight doesn't work >> > >> > That is fixed in git master. It's also called "Backlight" now (according >> > to RandR style guides), with BACKLIGHT as a fallback. >> >> I'm using the latest git however the backlight property isn't exported >> in either case. I'm using a GM45 if this is significant > > Can you check whether you have any backlight controlling module loaded? > Just check whether you have anything in /sys/class/backlight. > > If there isn't, try loading the samsung module with force=1, and if that > works ask GregKH to add your pci ids to the driver. > > Matthias > > -- > Matthias Hopf <mhopf@suse.de>    __     __  __ > Maxfeldstr. 5 / 90409 Nuernberg  (_  | |  (_  |__      mat@mshopf.de > Phone +49-911-74053-715      __)  |_|  __)  |__  R & D  www.mshopf.de > Hi Yes I have: /sys/class/backlight/samsung/* Regards Mike
2009/9/9 Greg KH <greg@kroah.com>: > On Wed, Sep 09, 2009 at 01:04:15PM +0200, Matthias Hopf wrote: >> On Sep 08, 09 09:31:24 -0700, Greg KH wrote: >> > > AFAIR at one point you deliberately decided to expose only 8 levels to >> > > the user - while the hardware was capable of more levels (I think it was >> > > something about some user land tool expecting something like that). >> > > But I may be utterly wrong. >> > >> > Yes, that was when we were blindly poking in the PCI config space. Â We >> > aren't supposed to be doing that :) >> > >> > > I'd love to have more fine grained control on my NC10 as well. >> > >> > I have reports that Windows also only supports 8 levels, so that is what >> > this hardware controller is possible of supporting, sorry. >> >> Hm. This is contradicting. On the one hand the hardware is capable of >> more levels. On the other it isn't *reporting* more levels. >> >> I wouldn't rely on anything what Windows supports. There can be >> arbitrary limitations in the driver. > > The hardware seems to allow multiple levels if you poke a raw value into > a random PCI config location. > > However, this is not the correct way to control this hardware, a SMI > call needs to be made instead. Â And for that call, only 8 levels are > available. > > So it's not a limitation in the Windows driver, it is a limitation in > the BIOS provided by the manufacturer. > > thanks, > > greg k-h > Who's the best person to talk to about getting my laptop added to drivers/input/keyboard/atkbd.c To stop the stuck keys Cheers Mike
On Fri, Sep 11, 2009 at 03:14:46AM +0100, Mike Lothian wrote: > 2009/9/9 Greg KH <greg@kroah.com>: > > On Wed, Sep 09, 2009 at 01:04:15PM +0200, Matthias Hopf wrote: > >> On Sep 08, 09 09:31:24 -0700, Greg KH wrote: > >> > > AFAIR at one point you deliberately decided to expose only 8 levels to > >> > > the user - while the hardware was capable of more levels (I think it was > >> > > something about some user land tool expecting something like that). > >> > > But I may be utterly wrong. > >> > > >> > Yes, that was when we were blindly poking in the PCI config space. Â We > >> > aren't supposed to be doing that :) > >> > > >> > > I'd love to have more fine grained control on my NC10 as well. > >> > > >> > I have reports that Windows also only supports 8 levels, so that is what > >> > this hardware controller is possible of supporting, sorry. > >> > >> Hm. This is contradicting. On the one hand the hardware is capable of > >> more levels. On the other it isn't *reporting* more levels. > >> > >> I wouldn't rely on anything what Windows supports. There can be > >> arbitrary limitations in the driver. > > > > The hardware seems to allow multiple levels if you poke a raw value into > > a random PCI config location. > > > > However, this is not the correct way to control this hardware, a SMI > > call needs to be made instead. Â And for that call, only 8 levels are > > available. > > > > So it's not a limitation in the Windows driver, it is a limitation in > > the BIOS provided by the manufacturer. > > > > thanks, > > > > greg k-h > > > > Who's the best person to talk to about getting my laptop added to > > drivers/input/keyboard/atkbd.c > > To stop the stuck keys The input maintainer and developers as found in the kernel MAINTAINERS file?
2009/9/11 Mike Lothian <mike@fireburn.co.uk>: > 2009/9/11 Matthias Hopf <mhopf@suse.de>: >> On Sep 11, 09 03:12:27 +0100, Mike Lothian wrote: >>> > Can you check whether you have any backlight controlling module loaded? >>> > Just check whether you have anything in /sys/class/backlight. >>> Yes I have: >>> /sys/class/backlight/samsung/* >>efbcf29dd1a1ca058b7a2a93f0685102c06c9369 > >> And your X driver still doesn't export the Backlight property? That's >> weird... >> Please check the git version number of the X driver. >> >> Matthias >> >> -- >> Matthias Hopf <mhopf@suse.de>    __     __  __ >> Maxfeldstr. 5 / 90409 Nuernberg  (_  | |  (_  |__      mat@mshopf.de >> Phone +49-911-74053-715      __)  |_|  __)  |__  R & D  www.mshopf.de >> > > I'm at git commit efbcf29dd1a1ca058b7a2a93f0685102c06c9369 of the master branch > > II) Loading /usr/lib64/xorg/modules/drivers/intel_drv.so > (II) Module intel: vendor="X.Org Foundation" >     compiled for 1.6.99.900, module version = 2.8.99 >     Module class: X.Org Video Driver >     ABI class: X.Org Video Driver, version 6.0 > (II) intel: Driver for Intel Integrated Graphics Chipsets: i810, >     i810-dc100, i810e, i815, i830M, 845G, 852GM/855GM, 865G, 915G, >     E7221 (i915), 915GM, 945G, 945GM, 945GME, Pineview GM, Pineview G, >     965G, G35, 965Q, 946GZ, 965GM, 965GME/GLE, G33, Q35, Q33, GM45, >     4 Series, G45/G43, Q45/Q43, G41, B43, Clarkdale, Arrandale >
On Sep 13, 09 17:28:27 +0100, Mike Lothian wrote: > >>> > Can you check whether you have any backlight controlling module loaded? > >>> > Just check whether you have anything in /sys/class/backlight. > >>> Yes I have: > >>> /sys/class/backlight/samsung/* > > > >> And your X driver still doesn't export the Backlight property? That's > >> weird... > >> Please check the git version number of the X driver. > > > > I'm at git commit efbcf29dd1a1ca058b7a2a93f0685102c06c9369 of the master branch Sorry for the late answer. It turned out that I didn't commit the name of the samsung backlight driver to the intel video driver (*blush*) - mainly because GregKH and I weren't on the same level what the final name of the driver will be (I supposed something more general, as it probably won't be samsung centric). Now that the name presumably stays fixed as "samsung" I finally committed the name to the intel driver. It's commit #7e7db7a. CU Matthias
2009/9/22 Matthias Hopf <mhopf@suse.de>: > On Sep 13, 09 17:28:27 +0100, Mike Lothian wrote: >> >>> > Can you check whether you have any backlight controlling module loaded? >> >>> > Just check whether you have anything in /sys/class/backlight. >> >>> Yes I have: >> >>> /sys/class/backlight/samsung/* >> > >> >> And your X driver still doesn't export the Backlight property? That's >> >> weird... >> >> Please check the git version number of the X driver. >> > >> > I'm at git commit efbcf29dd1a1ca058b7a2a93f0685102c06c9369 of the master branch > > Sorry for the late answer. > > It turned out that I didn't commit the name of the samsung backlight > driver to the intel video driver (*blush*) - mainly because GregKH and I > weren't on the same level what the final name of the driver will be (I > supposed something more general, as it probably won't be samsung > centric). > > Now that the name presumably stays fixed as "samsung" I finally > committed the name to the intel driver. It's commit #7e7db7a. > > CU > > Matthias > > -- > Matthias Hopf <mhopf@suse.de>    __     __  __ > Maxfeldstr. 5 / 90409 Nuernberg  (_  | |  (_  |__      mat@mshopf.de > Phone +49-911-74053-715      __)  |_|  __)  |__  R & D  www.mshopf.de > Yip I think that's fixed it thanks Looks like this laptop is now 100% linux compatible (apart from having to force it to use only 3 gigs of ram with MEM=4g boot parm) Cheers Mike
--- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -425,4 +425,16 @@ config ACPI_TOSHIBA If you have a legacy free Toshiba laptop (such as the Libretto L1 series), say Y. + +config SAMSUNG_LAPTOP + tristate "Samsung Laptop driver" + depends on BACKLIGHT_CLASS_DEVICE + depends on DMI + ---help--- + This driver adds support to control the backlight on a number of + Samsung laptops, like the N130, and control for some of the LEDs + + It will only be loaded on laptops that properly need it, so it is + safe to say Y here. + endif # X86_PLATFORM_DEVICES --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -20,3 +20,4 @@ obj-$(CONFIG_INTEL_MENLOW) += intel_menl obj-$(CONFIG_ACPI_WMI) += wmi.o obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o +obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop.o --- /dev/null +++ b/drivers/platform/x86/samsung-laptop.c @@ -0,0 +1,420 @@ +/* + * Samsung N130 and NC120 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/pci.h> +#include <linux/backlight.h> +#include <linux/fb.h> +#include <linux/dmi.h> +#include <linux/platform_device.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 + +/* get model returns 4 characters that describe the model of the laptop */ +#define SABI_GET_MODEL 0x04 + +/* Brightness is 0 - 8, as described above. Value 0 is for the BIOS to use */ +#define SABI_GET_BRIGHTNESS 0x10 +#define SABI_SET_BRIGHTNESS 0x11 + +/* 0 is off, 1 is on, and 2 is a second user-defined key? */ +#define SABI_GET_WIRELESS_BUTTON 0x12 +#define SABI_SET_WIRELESS_BUTTON 0x13 + +/* Temperature is returned in degress Celsius from what I can guess. */ +#define SABI_GET_CPU_TEMP 0x29 + +/* 0 is off, 1 is on. Doesn't seem to work on a N130 for some reason */ +#define SABI_GET_BACKLIGHT 0x2d +#define SABI_SET_BACKLIGHT 0x2e + +/* + * This is different + * There is 3 different modes here: + * 0 - off + * 1 - on + * 2 - max performance mode + * off is "normal" mode. + * on means that whatever the bios setting for etiquette mode, is enabled. It + * seems that the BIOS can set either "auto" mode, or "slow" mode. If "slow" + * mode is set, the fan turns off, and the cpu is throttled down to not cause + * the fan to turn on if at all possible. + * max performance means that the processor can be overclocked and run faster + * then is physically possible. Ok, maybe not physically possible, but it is + * overclocked. Funny that the system has a setting for this... + */ +#define SABI_GET_ETIQUETTE_MODE 0x31 +#define SABI_SET_ETIQUETTE_MODE 0x32 + +/* + * I imagine that on some laptops there is a bluetooth switch, but I don't know + * what that looks like, or where it is in the BIOS address space + */ + + +/* + * SABI HEADER in low memory (f0000) + * We need to poke through memory to find a signature in order to find the + * exact location of this structure. + */ +struct sabi_header { + u16 portNo; + u8 ifaceFunc; + u8 enMem; + u8 reMem; + u16 dataOffset; + u16 dataSegment; + u8 BIOSifver; + u8 LauncherString; +} __attribute__((packed)); + +/* + * The SABI interface that we use to write and read values from the system. + * It is found by looking at the dataOffset and dataSegment values in the sabi + * header structure + */ +struct sabi_interface { + u16 mainfunc; + u16 subfunc; + u8 complete; + u8 retval[20]; +} __attribute__((packed)); + +/* Structure to get data back to the calling function */ +struct sabi_retval { + u8 retval[20]; +}; + +static struct sabi_header __iomem *sabi; +static struct sabi_interface __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 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; + + mutex_lock(&sabi_mutex); + + /* enable memory to be able to write to it */ + outb(readb(&sabi->enMem), readw(&sabi->portNo)); + + /* write out the command */ + writew(0x5843, &sabi_iface->mainfunc); + writew(command, &sabi_iface->subfunc); + writeb(0, &sabi_iface->complete); + outb(readb(&sabi->ifaceFunc), readw(&sabi->portNo)); + + /* sleep for a bit to let the command complete */ + msleep(100); + + /* write protect memory to make it safe */ + outb(readb(&sabi->reMem), readw(&sabi->portNo)); + + /* see if the command actually succeeded */ + if (readb(&sabi_iface->complete) == 0xaa && + readb(&sabi_iface->retval[0]) != 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->retval[0]); + sretval->retval[1] = readb(&sabi_iface->retval[1]); + sretval->retval[2] = readb(&sabi_iface->retval[2]); + sretval->retval[3] = readb(&sabi_iface->retval[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->complete), + readb(&sabi_iface->retval[0])); + retval = -EINVAL; +exit: + mutex_unlock(&sabi_mutex); + return retval; + +} + +static int sabi_set_command(u8 command, u8 data) +{ + int retval = 0; + + mutex_lock(&sabi_mutex); + + /* enable memory to be able to write to it */ + outb(readb(&sabi->enMem), readw(&sabi->portNo)); + + /* write out the command */ + writew(0x5843, &sabi_iface->mainfunc); + writew(command, &sabi_iface->subfunc); + writeb(0, &sabi_iface->complete); + writeb(data, &sabi_iface->retval[0]); + outb(readb(&sabi->ifaceFunc), readw(&sabi->portNo)); + + /* sleep for a bit to let the command complete */ + msleep(100); + + /* write protect memory to make it safe */ + outb(readb(&sabi->reMem), readw(&sabi->portNo)); + + /* see if the command actually succeeded */ + if (readb(&sabi_iface->complete) == 0xaa && + readb(&sabi_iface->retval[0]) != 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->complete), + readb(&sabi_iface->retval[0])); + retval = -EINVAL; +exit: + mutex_unlock(&sabi_mutex); + return retval; +} + +static u8 read_brightness(void) +{ + struct sabi_retval sretval; + int user_brightness = 0; + int retval; + + retval = sabi_get_command(SABI_GET_BACKLIGHT, &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_SET_BRIGHTNESS, user_brightness + 1); +} + +static int get_brightness(struct backlight_device *bd) +{ + return bd->props.brightness; +} + +static int update_status(struct backlight_device *bd) +{ + set_brightness(bd->props.brightness); + return 0; +} + +static struct backlight_ops backlight_ops = { + .get_brightness = get_brightness, + .update_status = update_status, +}; + +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 = "N120", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "N120"), + DMI_MATCH(DMI_BOARD_NAME, "N120"), + }, + .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, + }, + { }, +}; + + +static int __init samsung_init(void) +{ + struct sabi_retval sretval; + const char *testStr = "SwSmi@"; + void __iomem *memcheck; + unsigned int ifaceP; + int pStr; + 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 the signature "SwSmi@" in memory to find the header */ + pStr = 0; + memcheck = f0000_segment; + for (loca = 0; loca < 0xffff; loca++) { + char temp = readb(memcheck + loca); + + if (temp == testStr[pStr]) { + if (pStr == 5) + break; + ++pStr; + } else { + pStr = 0; + } + } + if (loca == 0xffff) { + printk(KERN_INFO "This computer does not support SABI\n"); + goto error_no_signature; + } + + /* point to the SMI port Number */ + loca += 1; + sabi = (struct sabi_header __iomem *)(loca + memcheck); + if (!sabi) { + printk(KERN_ERR "Can't remap %p\n", loca + memcheck); + goto exit; + } + + printk(KERN_INFO "This computer supports SABI==%x\n", loca + 0xf0000 - 6); + printk(KERN_INFO "SABI header:\n"); + printk(KERN_INFO " SMI Port Number = 0x%04x\n", readw(&sabi->portNo)); + printk(KERN_INFO " SMI Interface Function = 0x%02x\n", readb(&sabi->ifaceFunc)); + printk(KERN_INFO " SMI enable memory buffer = 0x%02x\n", readb(&sabi->enMem)); + printk(KERN_INFO " SMI restore memory buffer = 0x%02x\n", readb(&sabi->reMem)); + printk(KERN_INFO " SABI data offset = 0x%04x\n", readw(&sabi->dataOffset)); + printk(KERN_INFO " SABI data segment = 0x%04x\n", readw(&sabi->dataSegment)); + printk(KERN_INFO " BIOS interface version = 0x%02x\n", readb(&sabi->BIOSifver)); + printk(KERN_INFO " KBD Launcher string = 0x%02x\n", readb(&sabi->LauncherString)); + + /* Get a pointer to the SABI Interface */ + ifaceP = (readw(&sabi->dataSegment) & 0x0ffff) << 4; + ifaceP += readw(&sabi->dataOffset) & 0x0ffff; + sabi_iface = (struct sabi_interface __iomem *)ioremap(ifaceP, 16); + if (!sabi_iface) { + printk(KERN_ERR "Can't remap %x\n", ifaceP); + goto exit; + } + printk(KERN_INFO "SABI Interface = %p\n", sabi_iface); + + retval = sabi_get_command(SABI_GET_MODEL, &sretval); + if (!retval) { + printk(KERN_INFO "Model Name %c%c%c%c\n", + sretval.retval[0], + sretval.retval[1], + sretval.retval[2], + sretval.retval[3]); + } + + retval = sabi_get_command(SABI_GET_BACKLIGHT, &sretval); + if (!retval) + printk("backlight = 0x%02x\n", sretval.retval[0]); + + retval = sabi_get_command(SABI_GET_WIRELESS_BUTTON, &sretval); + if (!retval) + printk("wireless button = 0x%02x\n", sretval.retval[0]); + + retval = sabi_get_command(SABI_GET_BRIGHTNESS, &sretval); + if (!retval) + printk("brightness = 0x%02x\n", sretval.retval[0]); + + retval = sabi_get_command(SABI_GET_ETIQUETTE_MODE, &sretval); + if (!retval) + printk("etiquette mode = 0x%02x\n", sretval.retval[0]); + retval = sabi_get_command(SABI_GET_CPU_TEMP, &sretval); + if (!retval) + printk("cpu temp = 0x%02x\n", sretval.retval[0]); + + /* 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 */ + backlight_device = backlight_device_register("samsung", &sdev->dev, + NULL, &backlight_ops); + if (IS_ERR(backlight_device)) + goto error_no_backlight; + + backlight_device->props.max_brightness = MAX_BRIGHT; + backlight_device->props.brightness = read_brightness(); + backlight_device->props.power = FB_BLANK_UNBLANK; + backlight_update_status(backlight_device); + +exit: + return 0; + +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) +{ + backlight_device_unregister(backlight_device); + 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"); +MODULE_ALIAS("dmi:*:svnSAMSUNGELECTRONICSCO.,LTD.:pnN120:*:rnN120:*"); +MODULE_ALIAS("dmi:*:svnSAMSUNGELECTRONICSCO.,LTD.:pnN130:*:rnN130:*");