Skip to content

Commit

Permalink
[PATCH] powermac: More powermac backlight fixes
Browse files Browse the repository at this point in the history
This patch fixes several problems:
- The legacy backlight value might be set at interrupt time. Introduced
  a worker to prevent it from directly calling the backlight code.
- via-pmu allows the backlight to be grabbed, in which case we need to
  prevent other kernel code from changing the brightness.
- Don't send PMU requests in via-pmu-backlight when the machine is about
  to sleep or waking up.
- More Kconfig fixes.

Signed-off-by: Michael Hanselmann <[email protected]>
Cc: Benjamin Herrenschmidt <[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 Jul 31, 2006
1 parent 994aad2 commit 4b75599
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 76 deletions.
58 changes: 55 additions & 3 deletions arch/powerpc/platforms/powermac/backlight.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,32 @@
#include <linux/kernel.h>
#include <linux/fb.h>
#include <linux/backlight.h>
#include <linux/adb.h>
#include <linux/pmu.h>
#include <asm/atomic.h>
#include <asm/prom.h>
#include <asm/backlight.h>

#define OLD_BACKLIGHT_MAX 15

static void pmac_backlight_key_worker(void *data);
static void pmac_backlight_set_legacy_worker(void *data);

static DECLARE_WORK(pmac_backlight_key_work, pmac_backlight_key_worker, NULL);
static DECLARE_WORK(pmac_backlight_set_legacy_work, pmac_backlight_set_legacy_worker, NULL);

/* Although this variable is used in interrupt context, it makes no sense to
* protect it. No user is able to produce enough key events per second and
/* Although these variables are used in interrupt context, it makes no sense to
* protect them. No user is able to produce enough key events per second and
* notice the errors that might happen.
*/
static int pmac_backlight_key_queued;
static int pmac_backlight_set_legacy_queued;

/* The via-pmu code allows the backlight to be grabbed, in which case the
* in-kernel control of the brightness needs to be disabled. This should
* only be used by really old PowerBooks.
*/
static atomic_t kernel_backlight_disabled = ATOMIC_INIT(0);

/* Protect the pmac_backlight variable */
DEFINE_MUTEX(pmac_backlight_mutex);
Expand Down Expand Up @@ -82,6 +95,9 @@ int pmac_backlight_curve_lookup(struct fb_info *info, int value)

static void pmac_backlight_key_worker(void *data)
{
if (atomic_read(&kernel_backlight_disabled))
return;

mutex_lock(&pmac_backlight_mutex);
if (pmac_backlight) {
struct backlight_properties *props;
Expand All @@ -107,16 +123,20 @@ static void pmac_backlight_key_worker(void *data)
mutex_unlock(&pmac_backlight_mutex);
}

/* This function is called in interrupt context */
void pmac_backlight_key(int direction)
{
if (atomic_read(&kernel_backlight_disabled))
return;

/* we can receive multiple interrupts here, but the scheduled work
* will run only once, with the last value
*/
pmac_backlight_key_queued = direction;
schedule_work(&pmac_backlight_key_work);
}

int pmac_backlight_set_legacy_brightness(int brightness)
static int __pmac_backlight_set_legacy_brightness(int brightness)
{
int error = -ENXIO;

Expand Down Expand Up @@ -145,6 +165,28 @@ int pmac_backlight_set_legacy_brightness(int brightness)
return error;
}

static void pmac_backlight_set_legacy_worker(void *data)
{
if (atomic_read(&kernel_backlight_disabled))
return;

__pmac_backlight_set_legacy_brightness(pmac_backlight_set_legacy_queued);
}

/* This function is called in interrupt context */
void pmac_backlight_set_legacy_brightness_pmu(int brightness) {
if (atomic_read(&kernel_backlight_disabled))
return;

pmac_backlight_set_legacy_queued = brightness;
schedule_work(&pmac_backlight_set_legacy_work);
}

int pmac_backlight_set_legacy_brightness(int brightness)
{
return __pmac_backlight_set_legacy_brightness(brightness);
}

int pmac_backlight_get_legacy_brightness()
{
int result = -ENXIO;
Expand All @@ -167,6 +209,16 @@ int pmac_backlight_get_legacy_brightness()
return result;
}

void pmac_backlight_disable()
{
atomic_inc(&kernel_backlight_disabled);
}

void pmac_backlight_enable()
{
atomic_dec(&kernel_backlight_disabled);
}

EXPORT_SYMBOL_GPL(pmac_backlight);
EXPORT_SYMBOL_GPL(pmac_backlight_mutex);
EXPORT_SYMBOL_GPL(pmac_has_backlight_type);
2 changes: 0 additions & 2 deletions drivers/macintosh/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,6 @@ config PMAC_BACKLIGHT
bool "Backlight control for LCD screens"
depends on ADB_PMU && FB = y && (BROKEN || !PPC64)
select FB_BACKLIGHT
select BACKLIGHT_CLASS_DEVICE
select BACKLIGHT_LCD_SUPPORT
help
Say Y here to enable Macintosh specific extensions of the generic
backlight code. With this enabled, the brightness keys on older
Expand Down
14 changes: 3 additions & 11 deletions drivers/macintosh/adbhid.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,11 @@
#include <linux/pmu.h>

#include <asm/machdep.h>
#include <asm/backlight.h>
#ifdef CONFIG_PPC_PMAC
#include <asm/pmac_feature.h>
#endif

#ifdef CONFIG_PMAC_BACKLIGHT
#include <asm/backlight.h>
#endif

MODULE_AUTHOR("Franz Sirl <[email protected]>");

#define KEYB_KEYREG 0 /* register # for key up/down data */
Expand Down Expand Up @@ -237,11 +234,6 @@ static struct adb_ids keyboard_ids;
static struct adb_ids mouse_ids;
static struct adb_ids buttons_ids;

#ifdef CONFIG_PMAC_BACKLIGHT
/* Exported to via-pmu.c */
int disable_kernel_backlight = 0;
#endif /* CONFIG_PMAC_BACKLIGHT */

/* Kind of keyboard, see Apple technote 1152 */
#define ADB_KEYBOARD_UNKNOWN 0
#define ADB_KEYBOARD_ANSI 0x0100
Expand Down Expand Up @@ -527,15 +519,15 @@ 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 && down)
if (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 && down)
if (down)
pmac_backlight_key_up();
#endif
input_report_key(adbhid[id]->input, KEY_BRIGHTNESSUP, down);
Expand Down
68 changes: 55 additions & 13 deletions drivers/macintosh/via-pmu-backlight.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@

#define MAX_PMU_LEVEL 0xFF

static struct device_node *vias;
static struct backlight_properties pmu_backlight_data;
static spinlock_t pmu_backlight_lock;
static int sleeping;

static int pmu_backlight_get_level_brightness(struct fb_info *info,
int level)
Expand All @@ -40,23 +41,36 @@ 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;
unsigned long flags;
int level = bd->props->brightness;

if (vias == NULL)
return -ENODEV;
spin_lock_irqsave(&pmu_backlight_lock, flags);

/* Don't update brightness when sleeping */
if (sleeping)
goto out;

if (bd->props->power != FB_BLANK_UNBLANK ||
bd->props->fb_blank != FB_BLANK_UNBLANK)
level = 0;

pmulevel = pmu_backlight_get_level_brightness(info, level);
if (level > 0) {
int 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_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);
pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
PMU_POW_BACKLIGHT | PMU_POW_ON);
pmu_wait_complete(&req);
} else {
pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
PMU_POW_BACKLIGHT | PMU_POW_OFF);
pmu_wait_complete(&req);
}

out:
spin_unlock_irqrestore(&pmu_backlight_lock, flags);

return 0;
}
Expand All @@ -73,15 +87,39 @@ static struct backlight_properties pmu_backlight_data = {
.max_brightness = (FB_BACKLIGHT_LEVELS - 1),
};

void __init pmu_backlight_init(struct device_node *in_vias)
#ifdef CONFIG_PM
static int pmu_backlight_sleep_call(struct pmu_sleep_notifier *self, int when)
{
unsigned long flags;

spin_lock_irqsave(&pmu_backlight_lock, flags);

switch (when) {
case PBOOK_SLEEP_REQUEST:
sleeping = 1;
break;
case PBOOK_WAKE:
sleeping = 0;
break;
}

spin_unlock_irqrestore(&pmu_backlight_lock, flags);

return PBOOK_SLEEP_OK;
}

static struct pmu_sleep_notifier pmu_backlight_sleep_notif = {
.notifier_call = pmu_backlight_sleep_call,
};
#endif

void __init pmu_backlight_init()
{
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") ||
Expand Down Expand Up @@ -141,6 +179,10 @@ void __init pmu_backlight_init(struct device_node *in_vias)
pmac_backlight = bd;
mutex_unlock(&pmac_backlight_mutex);

#ifdef CONFIG_PM
pmu_register_sleep_notifier(&pmu_backlight_sleep_notif);
#endif

printk("pmubl: Backlight initialized (%s)\n", name);

return;
Expand Down
39 changes: 14 additions & 25 deletions drivers/macintosh/via-pmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
* a sleep or a freq. switch
* - Move sleep code out of here to pmac_pm, merge into new
* common PM infrastructure
* - Move backlight code out as well
* - Save/Restore PCI space properly
*
*/
Expand Down Expand Up @@ -60,9 +59,7 @@
#include <asm/mmu_context.h>
#include <asm/cputable.h>
#include <asm/time.h>
#ifdef CONFIG_PMAC_BACKLIGHT
#include <asm/backlight.h>
#endif

#include "via-pmu-event.h"

Expand Down Expand Up @@ -177,10 +174,6 @@ static int query_batt_timer = BATTERY_POLLING_COUNT;
static struct adb_request batt_req;
static struct proc_dir_entry *proc_pmu_batt[PMU_MAX_BATTERIES];

#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
extern int disable_kernel_backlight;
#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */

int __fake_sleep;
int asleep;
BLOCKING_NOTIFIER_HEAD(sleep_notifier_list);
Expand Down Expand Up @@ -466,7 +459,7 @@ static int __init via_pmu_dev_init(void)

#ifdef CONFIG_PMAC_BACKLIGHT
/* Initialize backlight */
pmu_backlight_init(vias);
pmu_backlight_init();
#endif

#ifdef CONFIG_PPC32
Expand Down Expand Up @@ -1403,11 +1396,8 @@ pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
else if ((1 << pirq) & PMU_INT_SNDBRT) {
#ifdef CONFIG_PMAC_BACKLIGHT
if (len == 3)
#ifdef CONFIG_INPUT_ADBHID
if (!disable_kernel_backlight)
#endif /* CONFIG_INPUT_ADBHID */
pmac_backlight_set_legacy_brightness(data[1] >> 4);
#endif /* CONFIG_PMAC_BACKLIGHT */
pmac_backlight_set_legacy_brightness_pmu(data[1] >> 4);
#endif
}
/* Tick interrupt */
else if ((1 << pirq) & PMU_INT_TICK) {
Expand Down Expand Up @@ -2414,7 +2404,7 @@ struct pmu_private {
spinlock_t lock;
#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
int backlight_locker;
#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */
#endif
};

static LIST_HEAD(all_pmu_pvt);
Expand Down Expand Up @@ -2464,7 +2454,7 @@ pmu_open(struct inode *inode, struct file *file)
spin_lock_irqsave(&all_pvt_lock, flags);
#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
pp->backlight_locker = 0;
#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */
#endif
list_add(&pp->list, &all_pmu_pvt);
spin_unlock_irqrestore(&all_pvt_lock, flags);
file->private_data = pp;
Expand Down Expand Up @@ -2559,13 +2549,12 @@ pmu_release(struct inode *inode, struct file *file)
spin_lock_irqsave(&all_pvt_lock, flags);
list_del(&pp->list);
spin_unlock_irqrestore(&all_pvt_lock, flags);

#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
if (pp->backlight_locker) {
spin_lock_irqsave(&pmu_lock, flags);
disable_kernel_backlight--;
spin_unlock_irqrestore(&pmu_lock, flags);
}
#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */
if (pp->backlight_locker)
pmac_backlight_enable();
#endif

kfree(pp);
}
unlock_kernel();
Expand Down Expand Up @@ -2642,18 +2631,18 @@ pmu_ioctl(struct inode * inode, struct file *filp,
#ifdef CONFIG_INPUT_ADBHID
case PMU_IOC_GRAB_BACKLIGHT: {
struct pmu_private *pp = filp->private_data;
unsigned long flags;

if (pp->backlight_locker)
return 0;

pp->backlight_locker = 1;
spin_lock_irqsave(&pmu_lock, flags);
disable_kernel_backlight++;
spin_unlock_irqrestore(&pmu_lock, flags);
pmac_backlight_disable();

return 0;
}
#endif /* CONFIG_INPUT_ADBHID */
#endif /* CONFIG_PMAC_BACKLIGHT_LEGACY */

case PMU_IOC_GET_MODEL:
return put_user(pmu_kind, argp);
case PMU_IOC_HAS_ADB:
Expand Down
Loading

0 comments on commit 4b75599

Please sign in to comment.