diff options
-rw-r--r-- | src/i810_reg.h | 13 | ||||
-rw-r--r-- | src/i830_lvds.c | 124 | ||||
-rw-r--r-- | src/i830_randr.c | 21 | ||||
-rw-r--r-- | src/i830_xf86Crtc.h | 15 |
4 files changed, 156 insertions, 17 deletions
diff --git a/src/i810_reg.h b/src/i810_reg.h index c2eb8546..33b059d6 100644 --- a/src/i810_reg.h +++ b/src/i810_reg.h @@ -937,8 +937,21 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define BLC_PWM_CTL 0x61254 #define BACKLIGHT_MODULATION_FREQ_SHIFT (17) +/** + * This is the most significant 15 bits of the number of backlight cycles in a + * complete cycle of the modulated backlight control. + * + * The actual value is this field multiplied by two. + */ #define BACKLIGHT_MODULATION_FREQ_MASK (0x7fff << 17) #define BLM_LEGACY_MODE (1 << 16) +/** + * This is the number of cycles out of the backlight modulation cycle for which + * the backlight is on. + * + * This field must be no greater than the number of cycles in the complete + * backlight modulation cycle. + */ #define BACKLIGHT_DUTY_CYCLE_SHIFT (0) #define BACKLIGHT_DUTY_CYCLE_MASK (0xffff) diff --git a/src/i830_lvds.c b/src/i830_lvds.c index 18ac76bf..223c6ab9 100644 --- a/src/i830_lvds.c +++ b/src/i830_lvds.c @@ -32,6 +32,34 @@ #include "xf86.h" #include "i830.h" #include "i830_bios.h" +#include "X11/Xatom.h" + +/** + * Sets the backlight level. + * + * \param level backlight level, from 0 to i830_lvds_get_max_backlight(). + */ +static void +i830_lvds_set_backlight(ScrnInfoPtr pScrn, int level) +{ + I830Ptr pI830 = I830PTR(pScrn); + CARD32 blc_pwm_ctl; + + blc_pwm_ctl = INREG(BLC_PWM_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; + OUTREG(BLC_PWM_CTL, blc_pwm_ctl | (level << BACKLIGHT_DUTY_CYCLE_SHIFT)); +} + +/** + * Returns the maximum level of the backlight duty cycle field. + */ +static CARD32 +i830_lvds_get_max_backlight(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + return ((INREG(BLC_PWM_CTL) & BACKLIGHT_MODULATION_FREQ_MASK) >> + BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; +} /** * Sets the power state for the panel. @@ -41,25 +69,16 @@ i830SetLVDSPanelPower(ScrnInfoPtr pScrn, Bool on) { I830Ptr pI830 = I830PTR(pScrn); CARD32 pp_status; - CARD32 blc_pwm_ctl; - int backlight_duty_cycle; - - blc_pwm_ctl = INREG (BLC_PWM_CTL); - backlight_duty_cycle = blc_pwm_ctl & BACKLIGHT_DUTY_CYCLE_MASK; - if (backlight_duty_cycle) - pI830->backlight_duty_cycle = backlight_duty_cycle; if (on) { OUTREG(PP_CONTROL, INREG(PP_CONTROL) | POWER_TARGET_ON); do { pp_status = INREG(PP_STATUS); } while ((pp_status & PP_ON) == 0); - OUTREG(BLC_PWM_CTL, - (blc_pwm_ctl & ~BACKLIGHT_DUTY_CYCLE_MASK) | - pI830->backlight_duty_cycle); + + i830_lvds_set_backlight(pScrn, pI830->backlight_duty_cycle); } else { - OUTREG(BLC_PWM_CTL, - (blc_pwm_ctl & ~BACKLIGHT_DUTY_CYCLE_MASK)); + i830_lvds_set_backlight(pScrn, 0); OUTREG(PP_CONTROL, INREG(PP_CONTROL) & ~POWER_TARGET_ON); do { @@ -99,11 +118,8 @@ i830_lvds_save (xf86OutputPtr output) /* * If the light is off at server startup, just make it full brightness */ - if (pI830->backlight_duty_cycle == 0) { - pI830->backlight_duty_cycle = - (pI830->saveBLC_PWM_CTL & BACKLIGHT_MODULATION_FREQ_MASK) >> - BACKLIGHT_MODULATION_FREQ_SHIFT; - } + if (pI830->backlight_duty_cycle == 0) + pI830->backlight_duty_cycle = i830_lvds_get_max_backlight(pScrn); } static void @@ -294,7 +310,80 @@ i830_lvds_destroy (xf86OutputPtr output) xfree (intel_output); } +#ifdef RANDR_12_INTERFACE +#define BACKLIGHT_NAME "BACKLIGHT" +static Atom backlight_atom; +#endif /* RANDR_12_INTERFACE */ + +static void +i830_lvds_create_resources(xf86OutputPtr output) +{ +#ifdef RANDR_12_INTERFACE + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + INT32 range[2]; + int data, err; + + /* Set up the backlight property, which takes effect immediately + * and accepts values only within the range. + * + * XXX: Currently, RandR doesn't verify that properties set are + * within the range. + */ + backlight_atom = MakeAtom(BACKLIGHT_NAME, sizeof(BACKLIGHT_NAME) - 1, + TRUE); + + range[0] = 0; + range[1] = i830_lvds_get_max_backlight(pScrn); + err = RRConfigureOutputProperty(output->randr_output, backlight_atom, + FALSE, TRUE, FALSE, 2, range); + if (err != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + } + /* Set the current value of the backlight property */ + data = pI830->backlight_duty_cycle; + err = RRChangeOutputProperty(output->randr_output, backlight_atom, + XA_INTEGER, 32, PropModeReplace, 4, &data, + FALSE); + if (err != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + } + +#endif /* RANDR_12_INTERFACE */ +} + +static Bool +i830_lvds_set_property(xf86OutputPtr output, Atom property, + RRPropertyValuePtr value) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + + if (property == backlight_atom) { + INT32 val; + + if (value->type != XA_INTEGER || value->format != 32 || + value->size != 1) + { + return FALSE; + } + + val = *(INT32 *)value->data; + if (val < 0 || val > i830_lvds_get_max_backlight(pScrn)) + return FALSE; + + i830_lvds_set_backlight(pScrn, val); + pI830->backlight_duty_cycle = val; + return TRUE; + } + + return TRUE; +} + static const xf86OutputFuncsRec i830_lvds_output_funcs = { + .create_resources = i830_lvds_create_resources, .dpms = i830_lvds_dpms, .save = i830_lvds_save, .restore = i830_lvds_restore, @@ -303,6 +392,7 @@ static const xf86OutputFuncsRec i830_lvds_output_funcs = { .mode_set = i830_lvds_mode_set, .detect = i830_lvds_detect, .get_modes = i830_lvds_get_modes, + .set_property = i830_lvds_set_property, .destroy = i830_lvds_destroy }; diff --git a/src/i830_randr.c b/src/i830_randr.c index 18f84c49..63888494 100644 --- a/src/i830_randr.c +++ b/src/i830_randr.c @@ -672,6 +672,23 @@ xf86RandR12CrtcSetGamma (ScreenPtr pScreen, return TRUE; } +static Bool +xf86RandR12OutputSetProperty (ScreenPtr pScreen, + RROutputPtr randr_output, + Atom property, + RRPropertyValuePtr value) +{ + xf86OutputPtr output = randr_output->devPrivate; + + /* If we don't have any property handler, then we don't care what the + * user is setting properties to. + */ + if (output->funcs->set_property == NULL) + return TRUE; + + return output->funcs->set_property(output, property, value); +} + /** * Given a list of xf86 modes and a RandR Output object, construct * RandR modes and assign them to the output @@ -861,6 +878,9 @@ xf86RandR12CreateObjects12 (ScreenPtr pScreen) strlen (output->name), output); RROutputAttachScreen (output->randr_output, pScreen); + + if (output->funcs->create_resources != NULL) + output->funcs->create_resources(output); } return TRUE; } @@ -897,6 +917,7 @@ xf86RandR12Init12 (ScreenPtr pScreen) rp->rrScreenSetSize = xf86RandR12ScreenSetSize; rp->rrCrtcSet = xf86RandR12CrtcSet; rp->rrCrtcSetGamma = xf86RandR12CrtcSetGamma; + rp->rrOutputSetProperty = xf86RandR12OutputSetProperty; rp->rrSetConfig = NULL; pScrn->PointerMoved = xf86RandR12PointerMoved; if (!xf86RandR12CreateObjects12 (pScreen)) diff --git a/src/i830_xf86Crtc.h b/src/i830_xf86Crtc.h index 8fea162e..b5f2fc20 100644 --- a/src/i830_xf86Crtc.h +++ b/src/i830_xf86Crtc.h @@ -171,6 +171,13 @@ struct _xf86Crtc { typedef struct _xf86OutputFuncs { /** + * Called to allow the output a chance to create properties after the + * RandR objects have been created. + */ + void + (*create_resources)(xf86OutputPtr output); + + /** * Turns the output on/off, or sets intermediate power levels if available. * * Unsupported intermediate modes drop to the lower power setting. If the @@ -246,6 +253,14 @@ typedef struct _xf86OutputFuncs { (*get_modes)(xf86OutputPtr output); /** + * Callback when an output's property has changed. + */ + Bool + (*set_property)(xf86OutputPtr output, + Atom property, + RRPropertyValuePtr value); + + /** * Clean up driver-specific bits of the output */ void |