Diff below publishes a "Backlight" property that can be used to get and set the backlight associated with a particular output. This property can easily be exported by the X11 graphics drivers trough the RandR protocol. A future diff will let the "modesetting" driver do this and make xbacklight(1) work.
The diff is a it tricky because tjere are some locking issues that need to be worked around. That is why the backlight is updated asynchronously, and "raw" backlight devices return the cached value instead of querying the hardware. ok? Index: dev/pci/drm/drm_crtc.c =================================================================== RCS file: /cvs/src/sys/dev/pci/drm/drm_crtc.c,v retrieving revision 1.25 diff -u -p -r1.25 drm_crtc.c --- dev/pci/drm/drm_crtc.c 1 Jul 2017 16:00:25 -0000 1.25 +++ dev/pci/drm/drm_crtc.c 9 Jul 2017 21:32:53 -0000 @@ -4049,6 +4049,23 @@ int drm_object_property_get_value(struct { int i; +#ifdef __OpenBSD__ + if (obj->type == DRM_MODE_OBJECT_CONNECTOR) { + struct drm_connector *connector = obj_to_connector(obj); + + if (property == connector->backlight_property) { + struct backlight_device *bd = + connector->backlight_device; + + if (bd->props.type == BACKLIGHT_FIRMWARE) + *val = bd->ops->get_brightness(bd); + else + *val = bd->props.brightness; + return 0; + } + } +#endif + /* read-only properties bypass atomic mechanism and still store * their value in obj->properties->values[].. mostly to avoid * having to deal w/ EDID and similar props in atomic paths: @@ -4840,6 +4857,12 @@ static int drm_mode_connector_set_obj_pr ret = 0; if (connector->funcs->dpms) ret = (*connector->funcs->dpms)(connector, (int)value); +#ifdef __OpenBSD__ + } else if (property == connector->backlight_property) { + ret = 0; + connector->backlight_device->props.brightness = value; + backlight_schedule_update_status(connector->backlight_device); +#endif } else if (connector->funcs->set_property) ret = connector->funcs->set_property(connector, property, value); Index: dev/pci/drm/drm_crtc.h =================================================================== RCS file: /cvs/src/sys/dev/pci/drm/drm_crtc.h,v retrieving revision 1.10 diff -u -p -r1.10 drm_crtc.h --- dev/pci/drm/drm_crtc.h 1 Jul 2017 16:00:25 -0000 1.10 +++ dev/pci/drm/drm_crtc.h 9 Jul 2017 21:32:54 -0000 @@ -741,6 +741,11 @@ struct drm_connector { uint8_t num_h_tile, num_v_tile; uint8_t tile_h_loc, tile_v_loc; uint16_t tile_h_size, tile_v_size; + +#ifdef __OpenBSD__ + struct backlight_device *backlight_device; + struct drm_property *backlight_property; +#endif }; /** Index: dev/pci/drm/drm_linux.c =================================================================== RCS file: /cvs/src/sys/dev/pci/drm/drm_linux.c,v retrieving revision 1.14 diff -u -p -r1.14 drm_linux.c --- dev/pci/drm/drm_linux.c 5 Jul 2017 20:30:13 -0000 1.14 +++ dev/pci/drm/drm_linux.c 9 Jul 2017 21:32:54 -0000 @@ -697,6 +697,12 @@ acpi_get_table_with_size(const char *sig #endif +void +backlight_do_update_status(void *arg) +{ + backlight_update_status(arg); +} + struct backlight_device * backlight_device_register(const char *name, void *kdev, void *data, const struct backlight_ops *ops, struct backlight_properties *props) @@ -707,6 +713,8 @@ backlight_device_register(const char *na bd->ops = ops; bd->props = *props; bd->data = data; + + task_set(&bd->task, backlight_do_update_status, bd); return bd; } @@ -715,4 +723,10 @@ void backlight_device_unregister(struct backlight_device *bd) { free(bd, M_DRM, sizeof(*bd)); +} + +void +backlight_schedule_update_status(struct backlight_device *bd) +{ + task_add(systq, &bd->task); } Index: dev/pci/drm/drm_linux.h =================================================================== RCS file: /cvs/src/sys/dev/pci/drm/drm_linux.h,v retrieving revision 1.53 diff -u -p -r1.53 drm_linux.h --- dev/pci/drm/drm_linux.h 5 Jul 2017 20:30:13 -0000 1.53 +++ dev/pci/drm/drm_linux.h 9 Jul 2017 21:32:54 -0000 @@ -1917,12 +1917,14 @@ struct backlight_ops { struct backlight_device { const struct backlight_ops *ops; struct backlight_properties props; + struct task task; void *data; }; #define bl_get_data(bd) (bd)->data -#define BACKLIGHT_RAW 0 +#define BACKLIGHT_RAW 0 +#define BACKLIGHT_FIRMWARE 1 struct backlight_device *backlight_device_register(const char *, void *, void *, const struct backlight_ops *, struct backlight_properties *); @@ -1932,7 +1934,9 @@ static inline void backlight_update_status(struct backlight_device *bd) { bd->ops->update_status(bd); -}; +} + +void backlight_schedule_update_status(struct backlight_device *); #define MIPI_DSI_V_SYNC_START 0x01 #define MIPI_DSI_V_SYNC_END 0x11 Index: dev/pci/drm/i915/i915_drv.c =================================================================== RCS file: /cvs/src/sys/dev/pci/drm/i915/i915_drv.c,v retrieving revision 1.104 diff -u -p -r1.104 i915_drv.c --- dev/pci/drm/i915/i915_drv.c 5 Jul 2017 20:30:13 -0000 1.104 +++ dev/pci/drm/i915/i915_drv.c 9 Jul 2017 21:32:54 -0000 @@ -2092,6 +2092,32 @@ inteldrm_burner_cb(void *arg1) drm_fb_helper_blank(dev_priv->burner_fblank, helper->fbdev); } +int +inteldrm_backlight_update_status(struct backlight_device *bd) +{ + struct wsdisplay_param dp; + + dp.param = WSDISPLAYIO_PARAM_BRIGHTNESS; + dp.curval = bd->props.brightness; + ws_set_param(&dp); + return 0; +} + +int +inteldrm_backlight_get_brightness(struct backlight_device *bd) +{ + struct wsdisplay_param dp; + + dp.param = WSDISPLAYIO_PARAM_BRIGHTNESS; + ws_get_param(&dp); + return dp.curval; +} + +const struct backlight_ops inteldrm_backlight_ops = { + .update_status = inteldrm_backlight_update_status, + .get_brightness = inteldrm_backlight_get_brightness +}; + int inteldrm_match(struct device *, void *, void *); void inteldrm_attach(struct device *, struct device *, void *); int inteldrm_detach(struct device *, int); @@ -2106,6 +2132,7 @@ struct cfdriver inteldrm_cd = { 0, "inteldrm", DV_DULL }; +void inteldrm_init_backlight(struct inteldrm_softc *); int inteldrm_intr(void *); int @@ -2126,7 +2153,6 @@ inteldrm_attach(struct device *parent, s struct pci_attach_args *pa = aux; const struct drm_pcidev *id; struct intel_device_info *info, *device_info; - struct intel_connector *intel_connector; struct rasops_info *ri = &dev_priv->ro; struct wsemuldisplaydev_attach_args aa; extern int vga_console_attached; @@ -2242,18 +2268,7 @@ inteldrm_attach(struct device *parent, s intel_fbdev_restore_mode(dev); - /* Grab backlight from the first connector that has one. */ - drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); - list_for_each_entry(intel_connector, &dev->mode_config.connector_list, - base.head) { - struct intel_panel *panel = &intel_connector->panel; - - if (panel->backlight.present) { - dev_priv->backlight = panel->backlight.device; - break; - } - } - drm_modeset_unlock(&dev->mode_config.connection_mutex); + inteldrm_init_backlight(dev_priv); ri->ri_flg = RI_CENTER | RI_WRONLY | RI_VCONS | RI_CLEAR; ri->ri_hw = dev_priv; @@ -2327,6 +2342,85 @@ inteldrm_activate(struct device *self, i } return (rv); +} + +void +inteldrm_native_backlight(struct inteldrm_softc *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct intel_connector *intel_connector; + + list_for_each_entry(intel_connector, + &dev->mode_config.connector_list, base.head) { + struct drm_connector *connector = &intel_connector->base; + struct intel_panel *panel = &intel_connector->panel; + struct backlight_device *bd = panel->backlight.device; + + if (!panel->backlight.present) + continue; + + connector->backlight_device = bd; + connector->backlight_property = drm_property_create_range(dev, + 0, "Backlight", 0, bd->props.max_brightness); + drm_object_attach_property(&connector->base, + connector->backlight_property, bd->props.brightness); + + /* + * Use backlight from the first connector that has one + * for wscons(4). + */ + if (dev_priv->backlight == NULL) + dev_priv->backlight = bd; + } +} + +void +inteldrm_firmware_backlight(struct inteldrm_softc *dev_priv, + struct wsdisplay_param *dp) +{ + struct drm_device *dev = dev_priv->dev; + struct intel_connector *intel_connector; + struct backlight_properties props; + struct backlight_device *bd; + + memset(&props, 0, sizeof(props)); + props.type = BACKLIGHT_FIRMWARE; + props.brightness = dp->curval; + bd = backlight_device_register(dev->device.dv_xname, NULL, NULL, + &inteldrm_backlight_ops, &props); + + list_for_each_entry(intel_connector, + &dev->mode_config.connector_list, base.head) { + struct drm_connector *connector = &intel_connector->base; + + if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS && + connector->connector_type != DRM_MODE_CONNECTOR_eDP && + connector->connector_type != DRM_MODE_CONNECTOR_DSI) + continue; + + connector->backlight_device = bd; + connector->backlight_property = drm_property_create_range(dev, + 0, "Backlight", dp->min, dp->max); + drm_object_attach_property(&connector->base, + connector->backlight_property, dp->curval); + } +} + +void +inteldrm_init_backlight(struct inteldrm_softc *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct wsdisplay_param dp; + + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); + + dp.param = WSDISPLAYIO_PARAM_BRIGHTNESS; + if (ws_get_param && ws_get_param(&dp) == 0) + inteldrm_firmware_backlight(dev_priv, &dp); + else + inteldrm_native_backlight(dev_priv); + + drm_modeset_unlock(&dev->mode_config.connection_mutex); } int