Commit e01af038 authored by Michael Hanselmann's avatar Michael Hanselmann Committed by Linus Torvalds
Browse files

[PATCH] powermac: Combined fixes for backlight code



This patch fixes several problems:
- pmac_backlight_key() is called under interrupt context, and therefore
  can't use mutexes or semaphores, so defer the backlight level for
  later, as it's not critical (original code by Aristeu S. Rozanski F.
  <aris@valeta.org>).
- Add exports for functions that might be called from modules
- Fix Kconfig depdencies on PMAC_BACKLIGHT.
- Fix locking issues on calls from inside the driver (reported by
  Aristeu S. Rozanski F., too)
- Fix wrong calculation of backlight values in some of the drivers
- Replace pmac_backlight_key_up/down by inline functions

[akpm@osdl.org: fix function prototypes]
Signed-off-by: default avatarMichael Hanselmann <linux-kernel@hansmi.ch>
Acked-by: default avatarAristeu S. Rozanski F. <aris@valeta.org>
Acked-by: default avatarRene Nussbaumer <linux-kernel@killerfox.forkbomb.ch>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 58d383a6
Loading
Loading
Loading
Loading
+22 −9
Original line number Diff line number Diff line
@@ -15,6 +15,15 @@

#define OLD_BACKLIGHT_MAX 15

static void pmac_backlight_key_worker(void *data);
static DECLARE_WORK(pmac_backlight_key_work, pmac_backlight_key_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
 * notice the errors that might happen.
 */
static int pmac_backlight_key_queued;

/* Protect the pmac_backlight variable */
DEFINE_MUTEX(pmac_backlight_mutex);

@@ -71,7 +80,7 @@ int pmac_backlight_curve_lookup(struct fb_info *info, int value)
	return level;
}

static void pmac_backlight_key(int direction)
static void pmac_backlight_key_worker(void *data)
{
	mutex_lock(&pmac_backlight_mutex);
	if (pmac_backlight) {
@@ -82,7 +91,8 @@ static void pmac_backlight_key(int direction)
		props = pmac_backlight->props;

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

		if (brightness < 0)
			brightness = 0;
@@ -97,14 +107,13 @@ static void pmac_backlight_key(int direction)
	mutex_unlock(&pmac_backlight_mutex);
}

void pmac_backlight_key_up()
{
	pmac_backlight_key(0);
}

void pmac_backlight_key_down()
void pmac_backlight_key(int direction)
{
	pmac_backlight_key(1);
	/* 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)
@@ -157,3 +166,7 @@ int pmac_backlight_get_legacy_brightness()

	return result;
}

EXPORT_SYMBOL_GPL(pmac_backlight);
EXPORT_SYMBOL_GPL(pmac_backlight_mutex);
EXPORT_SYMBOL_GPL(pmac_has_backlight_type);
+4 −1
Original line number Diff line number Diff line
@@ -113,7 +113,10 @@ config PMAC_MEDIABAY

config PMAC_BACKLIGHT
	bool "Backlight control for LCD screens"
	depends on ADB_PMU && (BROKEN || !PPC64)
	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
+35 −31
Original line number Diff line number Diff line
@@ -455,6 +455,7 @@ static void do_wait_for_fifo(u16 entries, struct aty128fb_par *par);
static void wait_for_fifo(u16 entries, struct aty128fb_par *par);
static void wait_for_idle(struct aty128fb_par *par);
static u32 depth_to_dst(u32 depth);
static void aty128_bl_set_power(struct fb_info *info, int power);

#define BIOS_IN8(v)  	(readb(bios + (v)))
#define BIOS_IN16(v) 	(readb(bios + (v)) | \
@@ -1257,25 +1258,11 @@ static void aty128_set_lcd_enable(struct aty128fb_par *par, int on)
		reg &= ~LVDS_DISPLAY_DIS;
		aty_st_le32(LVDS_GEN_CNTL, reg);
#ifdef CONFIG_FB_ATY128_BACKLIGHT
		mutex_lock(&info->bl_mutex);
		if (info->bl_dev) {
			down(&info->bl_dev->sem);
			info->bl_dev->props->update_status(info->bl_dev);
			up(&info->bl_dev->sem);
		}
		mutex_unlock(&info->bl_mutex);
		aty128_bl_set_power(info, FB_BLANK_UNBLANK);
#endif	
	} else {
#ifdef CONFIG_FB_ATY128_BACKLIGHT
		mutex_lock(&info->bl_mutex);
		if (info->bl_dev) {
			down(&info->bl_dev->sem);
			info->bl_dev->props->brightness = 0;
			info->bl_dev->props->power = FB_BLANK_POWERDOWN;
			info->bl_dev->props->update_status(info->bl_dev);
			up(&info->bl_dev->sem);
		}
		mutex_unlock(&info->bl_mutex);
		aty128_bl_set_power(info, FB_BLANK_POWERDOWN);
#endif	
		reg = aty_ld_le32(LVDS_GEN_CNTL);
		reg |= LVDS_DISPLAY_DIS;
@@ -1702,6 +1689,7 @@ static int __devinit aty128fb_setup(char *options)

static struct backlight_properties aty128_bl_data;

/* Call with fb_info->bl_mutex held */
static int aty128_bl_get_level_brightness(struct aty128fb_par *par,
		int level)
{
@@ -1709,10 +1697,8 @@ static int aty128_bl_get_level_brightness(struct aty128fb_par *par,
	int atylevel;

	/* Get and convert the value */
	mutex_lock(&info->bl_mutex);
	atylevel = MAX_LEVEL -
		(info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL);
	mutex_unlock(&info->bl_mutex);

	if (atylevel < 0)
		atylevel = 0;
@@ -1730,7 +1716,8 @@ static int aty128_bl_get_level_brightness(struct aty128fb_par *par,
/* That one prevents proper CRT output with LCD off */
#undef BACKLIGHT_DAC_OFF

static int aty128_bl_update_status(struct backlight_device *bd)
/* Call with fb_info->bl_mutex held */
static int __aty128_bl_update_status(struct backlight_device *bd)
{
	struct aty128fb_par *par = class_get_devdata(&bd->class_dev);
	unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
@@ -1783,6 +1770,19 @@ static int aty128_bl_update_status(struct backlight_device *bd)
	return 0;
}

static int aty128_bl_update_status(struct backlight_device *bd)
{
	struct aty128fb_par *par = class_get_devdata(&bd->class_dev);
	struct fb_info *info = pci_get_drvdata(par->pdev);
	int ret;

	mutex_lock(&info->bl_mutex);
	ret = __aty128_bl_update_status(bd);
	mutex_unlock(&info->bl_mutex);

	return ret;
}

static int aty128_bl_get_brightness(struct backlight_device *bd)
{
	return bd->props->brightness;
@@ -1795,6 +1795,16 @@ static struct backlight_properties aty128_bl_data = {
	.max_brightness	= (FB_BACKLIGHT_LEVELS - 1),
};

static void aty128_bl_set_power(struct fb_info *info, int power)
{
	mutex_lock(&info->bl_mutex);
	up(&info->bl_dev->sem);
	info->bl_dev->props->power = power;
	__aty128_bl_update_status(info->bl_dev);
	down(&info->bl_dev->sem);
	mutex_unlock(&info->bl_mutex);
}

static void aty128_bl_init(struct aty128fb_par *par)
{
	struct fb_info *info = pci_get_drvdata(par->pdev);
@@ -2197,12 +2207,8 @@ static int aty128fb_blank(int blank, struct fb_info *fb)
		return 0;

#ifdef CONFIG_FB_ATY128_BACKLIGHT
	if (machine_is(powermac) && blank) {
		down(&fb->bl_dev->sem);
		fb->bl_dev->props->power = FB_BLANK_POWERDOWN;
		fb->bl_dev->props->update_status(fb->bl_dev);
		up(&fb->bl_dev->sem);
	}
	if (machine_is(powermac) && blank)
		aty128_bl_set_power(fb, FB_BLANK_POWERDOWN);
#endif

	if (blank & FB_BLANK_VSYNC_SUSPEND)
@@ -2218,14 +2224,12 @@ static int aty128fb_blank(int blank, struct fb_info *fb)
		aty128_set_crt_enable(par, par->crt_on && !blank);
		aty128_set_lcd_enable(par, par->lcd_on && !blank);
	}

#ifdef CONFIG_FB_ATY128_BACKLIGHT
	if (machine_is(powermac) && !blank) {
		down(&fb->bl_dev->sem);
		fb->bl_dev->props->power = FB_BLANK_UNBLANK;
		fb->bl_dev->props->update_status(fb->bl_dev);
		up(&fb->bl_dev->sem);
	}
	if (machine_is(powermac) && !blank)
		aty128_bl_set_power(fb, FB_BLANK_UNBLANK);
#endif

	return 0;
}

+30 −23
Original line number Diff line number Diff line
@@ -2129,15 +2129,14 @@ static int atyfb_pci_resume(struct pci_dev *pdev)

static struct backlight_properties aty_bl_data;

/* Call with fb_info->bl_mutex held */
static int aty_bl_get_level_brightness(struct atyfb_par *par, int level)
{
	struct fb_info *info = pci_get_drvdata(par->pdev);
	int atylevel;

	/* Get and convert the value */
	mutex_lock(&info->bl_mutex);
	atylevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;
	mutex_unlock(&info->bl_mutex);

	if (atylevel < 0)
		atylevel = 0;
@@ -2147,7 +2146,8 @@ static int aty_bl_get_level_brightness(struct atyfb_par *par, int level)
	return atylevel;
}

static int aty_bl_update_status(struct backlight_device *bd)
/* Call with fb_info->bl_mutex held */
static int __aty_bl_update_status(struct backlight_device *bd)
{
	struct atyfb_par *par = class_get_devdata(&bd->class_dev);
	unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par);
@@ -2172,6 +2172,19 @@ static int aty_bl_update_status(struct backlight_device *bd)
	return 0;
}

static int aty_bl_update_status(struct backlight_device *bd)
{
	struct atyfb_par *par = class_get_devdata(&bd->class_dev);
	struct fb_info *info = pci_get_drvdata(par->pdev);
	int ret;

	mutex_lock(&info->bl_mutex);
	ret = __aty_bl_update_status(bd);
	mutex_unlock(&info->bl_mutex);

	return ret;
}

static int aty_bl_get_brightness(struct backlight_device *bd)
{
	return bd->props->brightness;
@@ -2184,6 +2197,16 @@ static struct backlight_properties aty_bl_data = {
	.max_brightness = (FB_BACKLIGHT_LEVELS - 1),
};

static void aty_bl_set_power(struct fb_info *info, int power)
{
	mutex_lock(&info->bl_mutex);
	up(&info->bl_dev->sem);
	info->bl_dev->props->power = power;
	__aty_bl_update_status(info->bl_dev);
	down(&info->bl_dev->sem);
	mutex_unlock(&info->bl_mutex);
}

static void aty_bl_init(struct atyfb_par *par)
{
	struct fb_info *info = pci_get_drvdata(par->pdev);
@@ -2790,16 +2813,8 @@ static int atyfb_blank(int blank, struct fb_info *info)
		return 0;

#ifdef CONFIG_PMAC_BACKLIGHT
	if (machine_is(powermac) && blank > FB_BLANK_NORMAL) {
		mutex_lock(&info->bl_mutex);
		if (info->bl_dev) {
			down(&info->bl_dev->sem);
			info->bl_dev->props->power = FB_BLANK_POWERDOWN;
			info->bl_dev->props->update_status(info->bl_dev);
			up(&info->bl_dev->sem);
		}
		mutex_unlock(&info->bl_mutex);
	}
	if (machine_is(powermac) && blank > FB_BLANK_NORMAL)
		aty_bl_set_power(info, FB_BLANK_POWERDOWN);
#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
	if (par->lcd_table && blank > FB_BLANK_NORMAL &&
	    (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
@@ -2830,16 +2845,8 @@ static int atyfb_blank(int blank, struct fb_info *info)
	aty_st_le32(CRTC_GEN_CNTL, gen_cntl, par);

#ifdef CONFIG_PMAC_BACKLIGHT
	if (machine_is(powermac) && blank <= FB_BLANK_NORMAL) {
		mutex_lock(&info->bl_mutex);
		if (info->bl_dev) {
			down(&info->bl_dev->sem);
			info->bl_dev->props->power = FB_BLANK_UNBLANK;
			info->bl_dev->props->update_status(info->bl_dev);
			up(&info->bl_dev->sem);
		}
		mutex_unlock(&info->bl_mutex);
	}
	if (machine_is(powermac) && blank <= FB_BLANK_NORMAL)
		aty_bl_set_power(info, FB_BLANK_UNBLANK);
#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
	if (par->lcd_table && blank <= FB_BLANK_NORMAL &&
	    (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
+1 −2
Original line number Diff line number Diff line
@@ -149,12 +149,11 @@ static int chipsfb_blank(int blank, struct fb_info *info)
	mutex_lock(&pmac_backlight_mutex);

	if (pmac_backlight) {
		down(&pmac_backlight->sem);

		/* used to disable backlight only for blank > 1, but it seems
		 * useful at blank = 1 too (saves battery, extends backlight
		 * life)
	 	 */
		down(&pmac_backlight->sem);
		if (blank)
			pmac_backlight->props->power = FB_BLANK_POWERDOWN;
		else
Loading