svn commit: r367233 - head/sys/dev/acpica

Vladimir Kondratyev wulf at FreeBSD.org
Sat Oct 31 20:25:56 UTC 2020


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);


More information about the svn-src-head mailing list