summaryrefslogtreecommitdiffstats
path: root/drivers/macintosh
diff options
context:
space:
mode:
authorMichael Hanselmann <linux-kernel@hansmi.ch>2006-06-25 14:47:08 +0200
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-25 19:00:59 +0200
commit5474c120aafe78ca54bf272f7a01107c42da2b21 (patch)
treec1b002a27703ce92c816bfb9844752186e33d403 /drivers/macintosh
parent[PATCH] uml: remove dead declaration (diff)
downloadlinux-5474c120aafe78ca54bf272f7a01107c42da2b21.tar.xz
linux-5474c120aafe78ca54bf272f7a01107c42da2b21.zip
[PATCH] Rewritten backlight infrastructure for portable Apple computers
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. [akpm@osdl.org: add needed exports] Signed-off-by: Michael Hanselmann <linux-kernel@hansmi.ch> Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Richard Purdie <rpurdie@rpsys.net> Cc: "Antonino A. Daplas" <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/macintosh')
-rw-r--r--drivers/macintosh/Kconfig19
-rw-r--r--drivers/macintosh/Makefile1
-rw-r--r--drivers/macintosh/adbhid.c28
-rw-r--r--drivers/macintosh/via-pmu-backlight.c150
-rw-r--r--drivers/macintosh/via-pmu.c120
5 files changed, 199 insertions, 119 deletions
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index ccf5df44cde4..37cd6ee4586b 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -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"
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
index 6081acdea404..8972e53d2dcb 100644
--- a/drivers/macintosh/Makefile
+++ b/drivers/macintosh/Makefile
@@ -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
diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c
index 394334ec5765..c26e1236b275 100644
--- a/drivers/macintosh/adbhid.c
+++ b/drivers/macintosh/adbhid.c
@@ -503,9 +503,7 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto
case 0x1f: /* Powerbook button device */
{
int down = (data[1] == (data[1] & 0xf));
-#ifdef CONFIG_PMAC_BACKLIGHT
- int backlight = get_backlight_level();
-#endif
+
/*
* XXX: Where is the contrast control for the passive?
* -- Cort
@@ -530,29 +528,17 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto
case 0xa: /* brightness decrease */
#ifdef CONFIG_PMAC_BACKLIGHT
- if (!disable_kernel_backlight) {
- if (down && backlight >= 0) {
- if (backlight > BACKLIGHT_OFF)
- set_backlight_level(backlight-1);
- else
- set_backlight_level(BACKLIGHT_OFF);
- }
- }
-#endif /* CONFIG_PMAC_BACKLIGHT */
+ if (!disable_kernel_backlight && down)
+ pmac_backlight_key_down();
+#endif
input_report_key(adbhid[id]->input, KEY_BRIGHTNESSDOWN, down);
break;
case 0x9: /* brightness increase */
#ifdef CONFIG_PMAC_BACKLIGHT
- if (!disable_kernel_backlight) {
- if (down && backlight >= 0) {
- if (backlight < BACKLIGHT_MAX)
- set_backlight_level(backlight+1);
- else
- set_backlight_level(BACKLIGHT_MAX);
- }
- }
-#endif /* CONFIG_PMAC_BACKLIGHT */
+ if (!disable_kernel_backlight && down)
+ pmac_backlight_key_up();
+#endif
input_report_key(adbhid[id]->input, KEY_BRIGHTNESSUP, down);
break;
diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c
new file mode 100644
index 000000000000..b42d05f2aaff
--- /dev/null
+++ b/drivers/macintosh/via-pmu-backlight.c
@@ -0,0 +1,150 @@
+/*
+ * Backlight code for via-pmu
+ *
+ * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi.
+ * Copyright (C) 2001-2002 Benjamin Herrenschmidt
+ * Copyright (C) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
+ *
+ */
+
+#include <asm/ptrace.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <asm/backlight.h>
+#include <asm/prom.h>
+
+#define MAX_PMU_LEVEL 0xFF
+
+static struct device_node *vias;
+static struct backlight_properties pmu_backlight_data;
+
+static int pmu_backlight_get_level_brightness(struct fb_info *info,
+ int level)
+{
+ int pmulevel;
+
+ /* Get and convert the value */
+ mutex_lock(&info->bl_mutex);
+ pmulevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_PMU_LEVEL;
+ mutex_unlock(&info->bl_mutex);
+
+ if (pmulevel < 0)
+ pmulevel = 0;
+ else if (pmulevel > MAX_PMU_LEVEL)
+ pmulevel = MAX_PMU_LEVEL;
+
+ return pmulevel;
+}
+
+static int pmu_backlight_update_status(struct backlight_device *bd)
+{
+ struct fb_info *info = class_get_devdata(&bd->class_dev);
+ struct adb_request req;
+ int pmulevel, level = bd->props->brightness;
+
+ if (vias == NULL)
+ return -ENODEV;
+
+ if (bd->props->power != FB_BLANK_UNBLANK ||
+ bd->props->fb_blank != FB_BLANK_UNBLANK)
+ level = 0;
+
+ pmulevel = pmu_backlight_get_level_brightness(info, level);
+
+ pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, pmulevel);
+ pmu_wait_complete(&req);
+
+ pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
+ PMU_POW_BACKLIGHT | (level > 0 ? PMU_POW_ON : PMU_POW_OFF));
+ pmu_wait_complete(&req);
+
+ return 0;
+}
+
+static int pmu_backlight_get_brightness(struct backlight_device *bd)
+{
+ return bd->props->brightness;
+}
+
+static struct backlight_properties pmu_backlight_data = {
+ .owner = THIS_MODULE,
+ .get_brightness = pmu_backlight_get_brightness,
+ .update_status = pmu_backlight_update_status,
+ .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
+};
+
+void __init pmu_backlight_init(struct device_node *in_vias)
+{
+ struct backlight_device *bd;
+ struct fb_info *info;
+ char name[10];
+ int level, autosave;
+
+ vias = in_vias;
+
+ /* Special case for the old PowerBook since I can't test on it */
+ autosave =
+ machine_is_compatible("AAPL,3400/2400") ||
+ machine_is_compatible("AAPL,3500");
+
+ if (!autosave &&
+ !pmac_has_backlight_type("pmu") &&
+ !machine_is_compatible("AAPL,PowerBook1998") &&
+ !machine_is_compatible("PowerBook1,1"))
+ return;
+
+ /* Actually, this is a hack, but I don't know of a better way
+ * to get the first framebuffer device.
+ */
+ info = registered_fb[0];
+ if (!info) {
+ printk("pmubl: No framebuffer found\n");
+ goto error;
+ }
+
+ snprintf(name, sizeof(name), "pmubl%d", info->node);
+
+ bd = backlight_device_register(name, info, &pmu_backlight_data);
+ if (IS_ERR(bd)) {
+ printk("pmubl: Backlight registration failed\n");
+ goto error;
+ }
+
+ mutex_lock(&info->bl_mutex);
+ info->bl_dev = bd;
+ fb_bl_default_curve(info, 0x7F, 0x46, 0x0E);
+ mutex_unlock(&info->bl_mutex);
+
+ level = pmu_backlight_data.max_brightness;
+
+ if (autosave) {
+ /* read autosaved value if available */
+ struct adb_request req;
+ pmu_request(&req, NULL, 2, 0xd9, 0);
+ pmu_wait_complete(&req);
+
+ mutex_lock(&info->bl_mutex);
+ level = pmac_backlight_curve_lookup(info,
+ (req.reply[0] >> 4) *
+ pmu_backlight_data.max_brightness / 15);
+ mutex_unlock(&info->bl_mutex);
+ }
+
+ up(&bd->sem);
+ bd->props->brightness = level;
+ bd->props->power = FB_BLANK_UNBLANK;
+ bd->props->update_status(bd);
+ down(&bd->sem);
+
+ mutex_lock(&pmac_backlight_mutex);
+ if (!pmac_backlight)
+ pmac_backlight = bd;
+ mutex_unlock(&pmac_backlight_mutex);
+
+ printk("pmubl: Backlight initialized (%s)\n", name);
+
+ return;
+
+error:
+ return;
+}
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index c63d4e7984be..2a355ae59562 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -144,7 +144,6 @@ static int data_index;
static int data_len;
static volatile int adb_int_pending;
static volatile int disable_poll;
-static struct adb_request bright_req_1, bright_req_2;
static struct device_node *vias;
static int pmu_kind = PMU_UNKNOWN;
static int pmu_fully_inited = 0;
@@ -161,7 +160,7 @@ static int drop_interrupts;
#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
static int option_lid_wakeup = 1;
#endif /* CONFIG_PM && CONFIG_PPC32 */
-#if (defined(CONFIG_PM)&&defined(CONFIG_PPC32))||defined(CONFIG_PMAC_BACKLIGHT)
+#if (defined(CONFIG_PM)&&defined(CONFIG_PPC32))||defined(CONFIG_PMAC_BACKLIGHT_LEGACY)
static int sleep_in_progress;
#endif
static unsigned long async_req_locks;
@@ -208,10 +207,6 @@ static int proc_get_info(char *page, char **start, off_t off,
int count, int *eof, void *data);
static int proc_get_irqstats(char *page, char **start, off_t off,
int count, int *eof, void *data);
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int pmu_set_backlight_level(int level, void* data);
-static int pmu_set_backlight_enable(int on, int level, void* data);
-#endif /* CONFIG_PMAC_BACKLIGHT */
static void pmu_pass_intr(unsigned char *data, int len);
static int proc_get_batt(char *page, char **start, off_t off,
int count, int *eof, void *data);
@@ -292,13 +287,6 @@ static char *pbook_type[] = {
"Core99"
};
-#ifdef CONFIG_PMAC_BACKLIGHT
-static struct backlight_controller pmu_backlight_controller = {
- pmu_set_backlight_enable,
- pmu_set_backlight_level
-};
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
int __init find_via_pmu(void)
{
u64 taddr;
@@ -417,8 +405,6 @@ static int __init via_pmu_start(void)
if (vias == NULL)
return -ENODEV;
- bright_req_1.complete = 1;
- bright_req_2.complete = 1;
batt_req.complete = 1;
#ifndef CONFIG_PPC_MERGE
@@ -483,9 +469,9 @@ static int __init via_pmu_dev_init(void)
return -ENODEV;
#ifdef CONFIG_PMAC_BACKLIGHT
- /* Enable backlight */
- register_backlight_controller(&pmu_backlight_controller, NULL, "pmu");
-#endif /* CONFIG_PMAC_BACKLIGHT */
+ /* Initialize backlight */
+ pmu_backlight_init(vias);
+#endif
#ifdef CONFIG_PPC32
if (machine_is_compatible("AAPL,3400/2400") ||
@@ -1424,7 +1410,7 @@ next:
#ifdef CONFIG_INPUT_ADBHID
if (!disable_kernel_backlight)
#endif /* CONFIG_INPUT_ADBHID */
- set_backlight_level(data[1] >> 4);
+ pmac_backlight_set_legacy_brightness(data[1] >> 4);
#endif /* CONFIG_PMAC_BACKLIGHT */
}
/* Tick interrupt */
@@ -1674,61 +1660,6 @@ gpio1_interrupt(int irq, void *arg, struct pt_regs *regs)
return IRQ_NONE;
}
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int backlight_to_bright[] = {
- 0x7f, 0x46, 0x42, 0x3e, 0x3a, 0x36, 0x32, 0x2e,
- 0x2a, 0x26, 0x22, 0x1e, 0x1a, 0x16, 0x12, 0x0e
-};
-
-static int
-pmu_set_backlight_enable(int on, int level, void* data)
-{
- struct adb_request req;
-
- if (vias == NULL)
- return -ENODEV;
-
- if (on) {
- pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT,
- backlight_to_bright[level]);
- pmu_wait_complete(&req);
- }
- pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
- PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF));
- pmu_wait_complete(&req);
-
- return 0;
-}
-
-static void
-pmu_bright_complete(struct adb_request *req)
-{
- if (req == &bright_req_1)
- clear_bit(1, &async_req_locks);
- if (req == &bright_req_2)
- clear_bit(2, &async_req_locks);
-}
-
-static int
-pmu_set_backlight_level(int level, void* data)
-{
- if (vias == NULL)
- return -ENODEV;
-
- if (test_and_set_bit(1, &async_req_locks))
- return -EAGAIN;
- pmu_request(&bright_req_1, pmu_bright_complete, 2, PMU_BACKLIGHT_BRIGHT,
- backlight_to_bright[level]);
- if (test_and_set_bit(2, &async_req_locks))
- return -EAGAIN;
- pmu_request(&bright_req_2, pmu_bright_complete, 2, PMU_POWER_CTRL,
- PMU_POW_BACKLIGHT | (level > BACKLIGHT_OFF ?
- PMU_POW_ON : PMU_POW_OFF));
-
- return 0;
-}
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
void
pmu_enable_irled(int on)
{
@@ -2145,9 +2076,8 @@ pmac_suspend_devices(void)
return -EBUSY;
}
- /* Wait for completion of async backlight requests */
- while (!bright_req_1.complete || !bright_req_2.complete ||
- !batt_req.complete)
+ /* Wait for completion of async requests */
+ while (!batt_req.complete)
pmu_poll();
/* Giveup the lazy FPU & vec so we don't have to back them
@@ -2678,26 +2608,34 @@ pmu_ioctl(struct inode * inode, struct file *filp,
return put_user(1, argp);
#endif /* CONFIG_PM && CONFIG_PPC32 */
-#ifdef CONFIG_PMAC_BACKLIGHT
- /* Backlight should have its own device or go via
- * the fbdev
- */
+#ifdef CONFIG_PMAC_BACKLIGHT_LEGACY
+ /* Compatibility ioctl's for backlight */
case PMU_IOC_GET_BACKLIGHT:
+ {
+ int brightness;
+
if (sleep_in_progress)
return -EBUSY;
- error = get_backlight_level();
- if (error < 0)
- return error;
- return put_user(error, argp);
+
+ brightness = pmac_backlight_get_legacy_brightness();
+ if (brightness < 0)
+ return brightness;
+ else
+ return put_user(brightness, argp);
+
+ }
case PMU_IOC_SET_BACKLIGHT:
{
- __u32 value;
+ int brightness;
+
if (sleep_in_progress)
return -EBUSY;
- error = get_user(value, argp);
- if (!error)
- error = set_backlight_level(value);
- break;
+
+ error = get_user(brightness, argp);
+ if (error)
+ return error;
+
+ return pmac_backlight_set_legacy_brightness(brightness);
}
#ifdef CONFIG_INPUT_ADBHID
case PMU_IOC_GRAB_BACKLIGHT: {
@@ -2713,7 +2651,7 @@ pmu_ioctl(struct inode * inode, struct file *filp,
return 0;
}
#endif /* CONFIG_INPUT_ADBHID */
-#endif /* CONFIG_PMAC_BACKLIGHT */
+#endif /* CONFIG_PMAC_BACKLIGHT_LEGACY */
case PMU_IOC_GET_MODEL:
return put_user(pmu_kind, argp);
case PMU_IOC_HAS_ADB: