Skip to content

Commit

Permalink
[PATCH] Rewritten backlight infrastructure for portable Apple computers
Browse files Browse the repository at this point in the history
This patch contains a total rewrite of the backlight infrastructure for
portable Apple computers.  Backward compatibility is retained.  A sysfs
interface allows userland to control the brightness with more steps than
before.  Userland is allowed to upload a brightness curve for different
monitors, similar to Mac OS X.

[[email protected]: add needed exports]
Signed-off-by: Michael Hanselmann <[email protected]>
Acked-by: Benjamin Herrenschmidt <[email protected]>
Cc: Richard Purdie <[email protected]>
Cc: "Antonino A. Daplas" <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Michael Hanselmann authored and Linus Torvalds committed Jun 25, 2006
1 parent 17660bd commit 5474c12
Show file tree
Hide file tree
Showing 26 changed files with 1,529 additions and 711 deletions.
15 changes: 12 additions & 3 deletions arch/powerpc/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <linux/delay.h>
#include <linux/kprobes.h>
#include <linux/kexec.h>
#include <linux/backlight.h>

#include <asm/kdebug.h>
#include <asm/pgtable.h>
Expand Down Expand Up @@ -105,10 +106,18 @@ int die(const char *str, struct pt_regs *regs, long err)
spin_lock_irq(&die_lock);
bust_spinlocks(1);
#ifdef CONFIG_PMAC_BACKLIGHT
if (machine_is(powermac)) {
set_backlight_enable(1);
set_backlight_level(BACKLIGHT_MAX);
mutex_lock(&pmac_backlight_mutex);
if (machine_is(powermac) && pmac_backlight) {
struct backlight_properties *props;

down(&pmac_backlight->sem);
props = pmac_backlight->props;
props->brightness = props->max_brightness;
props->power = FB_BLANK_UNBLANK;
props->update_status(pmac_backlight);
up(&pmac_backlight->sem);
}
mutex_unlock(&pmac_backlight_mutex);
#endif
printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter);
#ifdef CONFIG_PREEMPT
Expand Down
270 changes: 109 additions & 161 deletions arch/powerpc/platforms/powermac/backlight.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,200 +3,148 @@
* Contains support for the backlight.
*
* Copyright (C) 2000 Benjamin Herrenschmidt
* Copyright (C) 2006 Michael Hanselmann <[email protected]>
*
*/

#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/stddef.h>
#include <linux/reboot.h>
#include <linux/nvram.h>
#include <linux/console.h>
#include <asm/sections.h>
#include <asm/ptrace.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/system.h>
#include <linux/fb.h>
#include <linux/backlight.h>
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/nvram.h>
#include <asm/backlight.h>

#include <linux/adb.h>
#include <linux/pmu.h>
#define OLD_BACKLIGHT_MAX 15

static struct backlight_controller *backlighter;
static void* backlighter_data;
static int backlight_autosave;
static int backlight_level = BACKLIGHT_MAX;
static int backlight_enabled = 1;
static int backlight_req_level = -1;
static int backlight_req_enable = -1;
/* Protect the pmac_backlight variable */
DEFINE_MUTEX(pmac_backlight_mutex);

static void backlight_callback(void *);
static DECLARE_WORK(backlight_work, backlight_callback, NULL);
/* Main backlight storage
*
* Backlight drivers in this variable are required to have the "props"
* attribute set and to have an update_status function.
*
* We can only store one backlight here, but since Apple laptops have only one
* internal display, it doesn't matter. Other backlight drivers can be used
* independently.
*
* Lock ordering:
* pmac_backlight_mutex (global, main backlight)
* pmac_backlight->sem (backlight class)
*/
struct backlight_device *pmac_backlight;

void register_backlight_controller(struct backlight_controller *ctrler,
void *data, char *type)
int pmac_has_backlight_type(const char *type)
{
struct device_node* bk_node;
char *prop;
int valid = 0;

/* There's already a matching controller, bail out */
if (backlighter != NULL)
return;

bk_node = find_devices("backlight");

#ifdef CONFIG_ADB_PMU
/* Special case for the old PowerBook since I can't test on it */
backlight_autosave = machine_is_compatible("AAPL,3400/2400")
|| machine_is_compatible("AAPL,3500");
if ((backlight_autosave
|| machine_is_compatible("AAPL,PowerBook1998")
|| machine_is_compatible("PowerBook1,1"))
&& !strcmp(type, "pmu"))
valid = 1;
#endif
struct device_node* bk_node = find_devices("backlight");

if (bk_node) {
prop = get_property(bk_node, "backlight-control", NULL);
if (prop && !strncmp(prop, type, strlen(type)))
valid = 1;
}
if (!valid)
return;
backlighter = ctrler;
backlighter_data = data;

if (bk_node && !backlight_autosave)
prop = get_property(bk_node, "bklt", NULL);
else
prop = NULL;
if (prop) {
backlight_level = ((*prop)+1) >> 1;
if (backlight_level > BACKLIGHT_MAX)
backlight_level = BACKLIGHT_MAX;
char *prop = get_property(bk_node, "backlight-control", NULL);
if (prop && strncmp(prop, type, strlen(type)) == 0)
return 1;
}

#ifdef CONFIG_ADB_PMU
if (backlight_autosave) {
struct adb_request req;
pmu_request(&req, NULL, 2, 0xd9, 0);
while (!req.complete)
pmu_poll();
backlight_level = req.reply[0] >> 4;
}
#endif
acquire_console_sem();
if (!backlighter->set_enable(1, backlight_level, data))
backlight_enabled = 1;
release_console_sem();

printk(KERN_INFO "Registered \"%s\" backlight controller,"
"level: %d/15\n", type, backlight_level);
return 0;
}
EXPORT_SYMBOL(register_backlight_controller);

void unregister_backlight_controller(struct backlight_controller
*ctrler, void *data)
int pmac_backlight_curve_lookup(struct fb_info *info, int value)
{
/* We keep the current backlight level (for now) */
if (ctrler == backlighter && data == backlighter_data)
backlighter = NULL;
int level = (FB_BACKLIGHT_LEVELS - 1);

if (info && info->bl_dev) {
int i, max = 0;

/* Look for biggest value */
for (i = 0; i < FB_BACKLIGHT_LEVELS; i++)
max = max((int)info->bl_curve[i], max);

/* Look for nearest value */
for (i = 0; i < FB_BACKLIGHT_LEVELS; i++) {
int diff = abs(info->bl_curve[i] - value);
if (diff < max) {
max = diff;
level = i;
}
}

}

return level;
}
EXPORT_SYMBOL(unregister_backlight_controller);

static int __set_backlight_enable(int enable)
static void pmac_backlight_key(int direction)
{
int rc;

if (!backlighter)
return -ENODEV;
acquire_console_sem();
rc = backlighter->set_enable(enable, backlight_level,
backlighter_data);
if (!rc)
backlight_enabled = enable;
release_console_sem();
return rc;
mutex_lock(&pmac_backlight_mutex);
if (pmac_backlight) {
struct backlight_properties *props;
int brightness;

down(&pmac_backlight->sem);
props = pmac_backlight->props;

brightness = props->brightness +
((direction?-1:1) * (props->max_brightness / 15));

if (brightness < 0)
brightness = 0;
else if (brightness > props->max_brightness)
brightness = props->max_brightness;

props->brightness = brightness;
props->update_status(pmac_backlight);

up(&pmac_backlight->sem);
}
mutex_unlock(&pmac_backlight_mutex);
}
int set_backlight_enable(int enable)

void pmac_backlight_key_up()
{
if (!backlighter)
return -ENODEV;
backlight_req_enable = enable;
schedule_work(&backlight_work);
return 0;
pmac_backlight_key(0);
}

EXPORT_SYMBOL(set_backlight_enable);

int get_backlight_enable(void)
void pmac_backlight_key_down()
{
if (!backlighter)
return -ENODEV;
return backlight_enabled;
pmac_backlight_key(1);
}
EXPORT_SYMBOL(get_backlight_enable);

static int __set_backlight_level(int level)
int pmac_backlight_set_legacy_brightness(int brightness)
{
int rc = 0;

if (!backlighter)
return -ENODEV;
if (level < BACKLIGHT_MIN)
level = BACKLIGHT_OFF;
if (level > BACKLIGHT_MAX)
level = BACKLIGHT_MAX;
acquire_console_sem();
if (backlight_enabled)
rc = backlighter->set_level(level, backlighter_data);
if (!rc)
backlight_level = level;
release_console_sem();
if (!rc && !backlight_autosave) {
level <<=1;
if (level & 0x10)
level |= 0x01;
// -- todo: save to property "bklt"
int error = -ENXIO;

mutex_lock(&pmac_backlight_mutex);
if (pmac_backlight) {
struct backlight_properties *props;

down(&pmac_backlight->sem);
props = pmac_backlight->props;
props->brightness = brightness *
props->max_brightness / OLD_BACKLIGHT_MAX;
props->update_status(pmac_backlight);
up(&pmac_backlight->sem);

error = 0;
}
return rc;
mutex_unlock(&pmac_backlight_mutex);

return error;
}
int set_backlight_level(int level)

int pmac_backlight_get_legacy_brightness()
{
if (!backlighter)
return -ENODEV;
backlight_req_level = level;
schedule_work(&backlight_work);
return 0;
}
int result = -ENXIO;

EXPORT_SYMBOL(set_backlight_level);
mutex_lock(&pmac_backlight_mutex);
if (pmac_backlight) {
struct backlight_properties *props;

int get_backlight_level(void)
{
if (!backlighter)
return -ENODEV;
return backlight_level;
}
EXPORT_SYMBOL(get_backlight_level);
down(&pmac_backlight->sem);
props = pmac_backlight->props;
result = props->brightness *
OLD_BACKLIGHT_MAX / props->max_brightness;
up(&pmac_backlight->sem);
}
mutex_unlock(&pmac_backlight_mutex);

static void backlight_callback(void *dummy)
{
int level, enable;

do {
level = backlight_req_level;
enable = backlight_req_enable;
mb();

if (level >= 0)
__set_backlight_level(level);
if (enable >= 0)
__set_backlight_enable(enable);
} while(cmpxchg(&backlight_req_level, level, -1) != level ||
cmpxchg(&backlight_req_enable, enable, -1) != enable);
return result;
}
3 changes: 0 additions & 3 deletions arch/powerpc/xmon/xmon.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/xmon.h>
#ifdef CONFIG_PMAC_BACKLIGHT
#include <asm/backlight.h>
#endif
#include <asm/processor.h>
#include <asm/pgtable.h>
#include <asm/mmu.h>
Expand Down
19 changes: 12 additions & 7 deletions drivers/macintosh/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -99,17 +99,22 @@ config PMAC_MEDIABAY
devices are not fully supported in the bay as I never had one to
try with

# made a separate option since backlight may end up beeing used
# on non-powerbook machines (but only on PMU based ones AFAIK)
config PMAC_BACKLIGHT
bool "Backlight control for LCD screens"
depends on ADB_PMU && (BROKEN || !PPC64)
help
Say Y here to build in code to manage the LCD backlight on a
Macintosh PowerBook. With this code, the backlight will be turned
on and off appropriately on power-management and lid-open/lid-closed
events; also, the PowerBook button device will be enabled so you can
change the screen brightness.
Say Y here to enable Macintosh specific extensions of the generic
backlight code. With this enabled, the brightness keys on older
PowerBooks will be enabled so you can change the screen brightness.
Newer models should use an userspace daemon like pbbuttonsd.

config PMAC_BACKLIGHT_LEGACY
bool "Provide legacy ioctl's on /dev/pmu for the backlight"
depends on PMAC_BACKLIGHT && (BROKEN || !PPC64)
help
Say Y if you want to enable legacy ioctl's on /dev/pmu. This is for
programs which use this old interface. New and updated programs
should use the backlight classes in sysfs.

config ADB_MACIO
bool "Include MacIO (CHRP) ADB driver"
Expand Down
1 change: 1 addition & 0 deletions drivers/macintosh/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ obj-$(CONFIG_INPUT_ADBHID) += adbhid.o
obj-$(CONFIG_ANSLCD) += ans-lcd.o

obj-$(CONFIG_ADB_PMU) += via-pmu.o
obj-$(CONFIG_PMAC_BACKLIGHT) += via-pmu-backlight.o
obj-$(CONFIG_ADB_CUDA) += via-cuda.o
obj-$(CONFIG_PMAC_APM_EMU) += apm_emu.o
obj-$(CONFIG_PMAC_SMU) += smu.o
Expand Down
Loading

0 comments on commit 5474c12

Please sign in to comment.