Author: wulf
Date: Sat Oct 31 20:25:55 2020
New Revision: 367233
URL: https://svnweb.freebsd.org/changeset/base/367233

Log:
  acpi_video(4): Add evdev support for reporting of video events.

Modified:
  head/sys/dev/acpica/acpi_video.c

Modified: head/sys/dev/acpica/acpi_video.c
==============================================================================
--- head/sys/dev/acpica/acpi_video.c    Sat Oct 31 20:14:28 2020        
(r367232)
+++ head/sys/dev/acpica/acpi_video.c    Sat Oct 31 20:25:55 2020        
(r367233)
@@ -29,6 +29,8 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include "opt_evdev.h"
+
 #include <sys/param.h>
 #include <sys/bus.h>
 #include <sys/eventhandler.h>
@@ -43,6 +45,11 @@ __FBSDID("$FreeBSD$");
 
 #include <dev/acpica/acpivar.h>
 
+#ifdef EVDEV_SUPPORT
+#include <dev/evdev/input.h>
+#include <dev/evdev/evdev.h>
+#endif
+
 /* ACPI video extension driver. */
 struct acpi_video_output {
        ACPI_HANDLE     handle;
@@ -61,6 +68,9 @@ struct acpi_video_output {
        int             *vo_levels;
        struct sysctl_ctx_list vo_sysctl_ctx;
        struct sysctl_oid *vo_sysctl_tree;
+#ifdef EVDEV_SUPPORT
+       struct evdev_dev *evdev;
+#endif
 };
 
 STAILQ_HEAD(acpi_video_output_queue, acpi_video_output);
@@ -70,6 +80,9 @@ struct acpi_video_softc {
        ACPI_HANDLE             handle;
        struct acpi_video_output_queue vid_outputs;
        eventhandler_tag        vid_pwr_evh;
+#ifdef EVDEV_SUPPORT
+       struct evdev_dev        *evdev;
+#endif
 };
 
 /* interfaces */
@@ -107,10 +120,14 @@ static void       vo_set_device_state(ACPI_HANDLE, 
UINT32);
 /* events */
 #define        VID_NOTIFY_SWITCHED     0x80
 #define        VID_NOTIFY_REPROBE      0x81
+#define        VID_NOTIFY_CYCLE_OUT    0x82
+#define        VID_NOTIFY_NEXT_OUT     0x83
+#define        VID_NOTIFY_PREV_OUT     0x84
 #define        VID_NOTIFY_CYCLE_BRN    0x85
 #define        VID_NOTIFY_INC_BRN      0x86
 #define        VID_NOTIFY_DEC_BRN      0x87
 #define        VID_NOTIFY_ZERO_BRN     0x88
+#define        VID_NOTIFY_DISP_OFF     0x89
 
 /* _DOS (Enable/Disable Output Switching) argument bits */
 #define        DOS_SWITCH_MASK         3
@@ -175,6 +192,9 @@ static devclass_t acpi_video_devclass;
 DRIVER_MODULE(acpi_video, vgapci, acpi_video_driver, acpi_video_devclass,
              acpi_video_modevent, NULL);
 MODULE_DEPEND(acpi_video, acpi, 1, 1, 1);
+#ifdef EVDEV_SUPPORT
+MODULE_DEPEND(acpi_video, evdev, 1, 1, 1);
+#endif
 
 static struct sysctl_ctx_list  acpi_video_sysctl_ctx;
 static struct sysctl_oid       *acpi_video_sysctl_tree;
@@ -190,6 +210,45 @@ ACPI_SERIAL_DECL(video, "ACPI video");
 ACPI_SERIAL_DECL(video_output, "ACPI video output");
 static MALLOC_DEFINE(M_ACPIVIDEO, "acpivideo", "ACPI video extension");
 
+#ifdef EVDEV_SUPPORT
+static const struct {
+       UINT32          notify;
+       uint16_t        key;
+} acpi_video_evdev_map[] = {
+       { VID_NOTIFY_SWITCHED,  KEY_SWITCHVIDEOMODE },
+       { VID_NOTIFY_REPROBE,   KEY_SWITCHVIDEOMODE },
+       { VID_NOTIFY_CYCLE_OUT, KEY_SWITCHVIDEOMODE },
+       { VID_NOTIFY_NEXT_OUT,  KEY_VIDEO_NEXT },
+       { VID_NOTIFY_PREV_OUT,  KEY_VIDEO_PREV },
+       { VID_NOTIFY_CYCLE_BRN, KEY_BRIGHTNESS_CYCLE },
+       { VID_NOTIFY_INC_BRN,   KEY_BRIGHTNESSUP },
+       { VID_NOTIFY_DEC_BRN,   KEY_BRIGHTNESSDOWN },
+       { VID_NOTIFY_ZERO_BRN,  KEY_BRIGHTNESS_ZERO },
+       { VID_NOTIFY_DISP_OFF,  KEY_DISPLAY_OFF },
+};
+
+static void
+acpi_video_push_evdev_event(struct evdev_dev *evdev, UINT32 notify)
+{
+       int i;
+       uint16_t key;
+
+       /* Do not allow to execute 2 instances this routine concurently */
+       ACPI_SERIAL_ASSERT(video_output);
+
+       for (i = 0; i < nitems(acpi_video_evdev_map); i++) {
+               if (acpi_video_evdev_map[i].notify == notify) {
+                       key = acpi_video_evdev_map[i].key;
+                       evdev_push_key(evdev, key, 1);
+                       evdev_sync(evdev);
+                       evdev_push_key(evdev, key, 0);
+                       evdev_sync(evdev);
+                       break;
+               }
+       }
+}
+#endif
+
 static int
 acpi_video_modevent(struct module *mod __unused, int evt, void *cookie 
__unused)
 {
@@ -247,12 +306,30 @@ acpi_video_attach(device_t dev)
 {
        struct acpi_softc *acpi_sc;
        struct acpi_video_softc *sc;
+#ifdef EVDEV_SUPPORT
+       int i;
+#endif
 
        sc = device_get_softc(dev);
 
        acpi_sc = devclass_get_softc(devclass_find("acpi"), 0);
        if (acpi_sc == NULL)
                return (ENXIO);
+
+#ifdef EVDEV_SUPPORT
+       sc->evdev = evdev_alloc();
+       evdev_set_name(sc->evdev, device_get_desc(dev));
+       evdev_set_phys(sc->evdev, device_get_nameunit(dev));
+       evdev_set_id(sc->evdev, BUS_HOST, 0, 0, 1);
+       evdev_support_event(sc->evdev, EV_SYN);
+       evdev_support_event(sc->evdev, EV_KEY);
+       for (i = 0; i < nitems(acpi_video_evdev_map); i++)
+               evdev_support_key(sc->evdev, acpi_video_evdev_map[i].key);
+
+       if (evdev_register(sc->evdev) != 0)
+               return (ENXIO);
+#endif
+
        ACPI_SERIAL_BEGIN(video);
        if (acpi_video_sysctl_tree == NULL) {
                acpi_video_sysctl_tree = SYSCTL_ADD_NODE(&acpi_video_sysctl_ctx,
@@ -306,6 +383,10 @@ acpi_video_detach(device_t dev)
        }
        ACPI_SERIAL_END(video);
 
+#ifdef EVDEV_SUPPORT
+       evdev_free(sc->evdev);
+#endif
+
        return (0);
 }
 
@@ -404,12 +485,21 @@ acpi_video_notify_handler(ACPI_HANDLE handle, UINT32 n
                }
                ACPI_SERIAL_END(video);
                break;
+       /* Next events should not appear if DOS_SWITCH_BY_OSPM policy is set */
+       case VID_NOTIFY_CYCLE_OUT:
+       case VID_NOTIFY_NEXT_OUT:
+       case VID_NOTIFY_PREV_OUT:
        default:
                device_printf(sc->device, "unknown notify event 0x%x\n",
                    notify);
        }
        AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_video_invoke_event_handler,
            (void *)(uintptr_t)notify);
+#ifdef EVDEV_SUPPORT
+       ACPI_SERIAL_BEGIN(video_output);
+       acpi_video_push_evdev_event(sc->evdev, notify);
+       ACPI_SERIAL_END(video_output);
+#endif
 }
 
 static void
@@ -454,6 +544,9 @@ acpi_video_bind_outputs_subr(ACPI_HANDLE handle, UINT3
        }
        vo = acpi_video_vo_init(adr);
        if (vo != NULL) {
+#ifdef EVDEV_SUPPORT
+               vo->evdev = sc->evdev;
+#endif
                acpi_video_vo_bind(vo, handle);
                STAILQ_INSERT_TAIL(&sc->vid_outputs, vo, vo_next);
        }
@@ -708,6 +801,7 @@ acpi_video_vo_notify_handler(ACPI_HANDLE handle, UINT3
        case VID_NOTIFY_INC_BRN:
        case VID_NOTIFY_DEC_BRN:
        case VID_NOTIFY_ZERO_BRN:
+       case VID_NOTIFY_DISP_OFF:
                if (vo->vo_levels == NULL)
                        goto out;
                level = vo_get_brightness(vo);
@@ -757,6 +851,9 @@ acpi_video_vo_notify_handler(ACPI_HANDLE handle, UINT3
                vo_set_brightness(vo, new_level);
                vo->vo_brightness = new_level;
        }
+#ifdef EVDEV_SUPPORT
+       acpi_video_push_evdev_event(vo->evdev, notify);
+#endif
 
 out:
        ACPI_SERIAL_END(video_output);
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to