svn commit: r237602 - stable/9/sys/dev/acpi_support

Mitsuru IWASAKI iwasaki at FreeBSD.org
Tue Jun 26 15:29:39 UTC 2012


Author: iwasaki
Date: Tue Jun 26 15:29:38 2012
New Revision: 237602
URL: http://svn.freebsd.org/changeset/base/237602

Log:
  MFC 237493:
  
  - Add in-driver event handler.

Modified:
  stable/9/sys/dev/acpi_support/acpi_ibm.c
Directory Properties:
  stable/9/sys/   (props changed)
  stable/9/sys/dev/   (props changed)

Modified: stable/9/sys/dev/acpi_support/acpi_ibm.c
==============================================================================
--- stable/9/sys/dev/acpi_support/acpi_ibm.c	Tue Jun 26 14:51:35 2012	(r237601)
+++ stable/9/sys/dev/acpi_support/acpi_ibm.c	Tue Jun 26 15:29:38 2012	(r237602)
@@ -50,6 +50,8 @@ __FBSDID("$FreeBSD$");
 #include <sys/module.h>
 #include <dev/acpica/acpivar.h>
 #include <dev/led/led.h>
+#include <sys/power.h>
+#include <sys/sbuf.h>
 #include <sys/sysctl.h>
 #include <isa/rtc.h>
 
@@ -70,6 +72,7 @@ ACPI_MODULE_NAME("IBM")
 #define ACPI_IBM_METHOD_FANLEVEL	11
 #define ACPI_IBM_METHOD_FANSTATUS	12
 #define ACPI_IBM_METHOD_THERMAL		13
+#define ACPI_IBM_METHOD_HANDLEREVENTS	14
 
 /* Hotkeys/Buttons */
 #define IBM_RTC_HOTKEY1			0x64
@@ -126,6 +129,21 @@ ACPI_MODULE_NAME("IBM")
 #define IBM_NAME_EVENTS_GET		"MHKP"
 #define IBM_NAME_EVENTS_AVAILMASK	"MHKA"
 
+/* Event Code */
+#define IBM_EVENT_LCD_BACKLIGHT		0x03
+#define IBM_EVENT_SUSPEND_TO_RAM	0x04
+#define IBM_EVENT_BLUETOOTH		0x05
+#define IBM_EVENT_SCREEN_EXPAND		0x07
+#define IBM_EVENT_SUSPEND_TO_DISK	0x0c
+#define IBM_EVENT_BRIGHTNESS_UP		0x10
+#define IBM_EVENT_BRIGHTNESS_DOWN	0x11
+#define IBM_EVENT_THINKLIGHT		0x12
+#define IBM_EVENT_ZOOM			0x14
+#define IBM_EVENT_VOLUME_UP		0x15
+#define IBM_EVENT_VOLUME_DOWN		0x16
+#define IBM_EVENT_MUTE			0x17
+#define IBM_EVENT_ACCESS_IBM_BUTTON	0x18
+
 #define ABS(x) (((x) < 0)? -(x) : (x))
 
 struct acpi_ibm_softc {
@@ -164,6 +182,8 @@ struct acpi_ibm_softc {
 	int		events_mask_supported;
 	int		events_enable;
 
+	unsigned int	handler_events;
+
 	struct sysctl_ctx_list	*sysctl_ctx;
 	struct sysctl_oid	*sysctl_tree;
 };
@@ -267,8 +287,15 @@ static int	acpi_ibm_sysctl_set(struct ac
 
 static int	acpi_ibm_eventmask_set(struct acpi_ibm_softc *sc, int val);
 static int	acpi_ibm_thermal_sysctl(SYSCTL_HANDLER_ARGS);
+static int	acpi_ibm_handlerevents_sysctl(SYSCTL_HANDLER_ARGS);
 static void	acpi_ibm_notify(ACPI_HANDLE h, UINT32 notify, void *context);
 
+static int	acpi_ibm_brightness_set(struct acpi_ibm_softc *sc, int arg);
+static int	acpi_ibm_bluetooth_set(struct acpi_ibm_softc *sc, int arg);
+static int	acpi_ibm_thinklight_set(struct acpi_ibm_softc *sc, int arg);
+static int	acpi_ibm_volume_set(struct acpi_ibm_softc *sc, int arg);
+static int	acpi_ibm_mute_set(struct acpi_ibm_softc *sc, int arg);
+
 static device_method_t acpi_ibm_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe, acpi_ibm_probe),
@@ -404,6 +431,15 @@ acpi_ibm_attach(device_t dev)
 		    "Thermal zones");
 	}
 
+	/* Hook up handlerevents node */
+	if (acpi_ibm_sysctl_init(sc, ACPI_IBM_METHOD_HANDLEREVENTS)) {
+		SYSCTL_ADD_PROC(sc->sysctl_ctx,
+		    SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
+		    "handlerevents", CTLTYPE_STRING | CTLFLAG_RW,
+		    sc, 0, acpi_ibm_handlerevents_sysctl, "I",
+		    "devd(8) events handled by acpi_ibm");
+	}
+
 	/* Handle notifies */
 	AcpiInstallNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY,
 	    acpi_ibm_notify, dev);
@@ -656,10 +692,8 @@ acpi_ibm_sysctl_get(struct acpi_ibm_soft
 static int
 acpi_ibm_sysctl_set(struct acpi_ibm_softc *sc, int method, int arg)
 {
-	int			val, step;
+	int			val;
 	UINT64			val_ec;
-	ACPI_OBJECT		Arg;
-	ACPI_OBJECT_LIST	Args;
 	ACPI_STATUS		status;
 
 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
@@ -683,101 +717,23 @@ acpi_ibm_sysctl_set(struct acpi_ibm_soft
 		break;
 
 	case ACPI_IBM_METHOD_BRIGHTNESS:
-		if (arg < 0 || arg > 7)
-			return (EINVAL);
-
-		if (sc->cmos_handle) {
-			/* Read the current brightness */
-			status = ACPI_EC_READ(sc->ec_dev, IBM_EC_BRIGHTNESS, &val_ec, 1);
-			if (ACPI_FAILURE(status))
-				return (status);
-			val = val_ec & IBM_EC_MASK_BRI;
-
-			Args.Count = 1;
-			Args.Pointer = &Arg;
-			Arg.Type = ACPI_TYPE_INTEGER;
-			Arg.Integer.Value = (arg > val) ? IBM_CMOS_BRIGHTNESS_UP : IBM_CMOS_BRIGHTNESS_DOWN;
-
-			step = (arg > val) ? 1 : -1;
-			for (int i = val; i != arg; i += step) {
-				status = AcpiEvaluateObject(sc->cmos_handle, NULL, &Args, NULL);
-				if (ACPI_FAILURE(status))
-					break;
-			}
-		}
-		return ACPI_EC_WRITE(sc->ec_dev, IBM_EC_BRIGHTNESS, arg, 1);
+		return acpi_ibm_brightness_set(sc, arg);
 		break;
 
 	case ACPI_IBM_METHOD_VOLUME:
-		if (arg < 0 || arg > 14)
-			return (EINVAL);
-
-		status = ACPI_EC_READ(sc->ec_dev, IBM_EC_VOLUME, &val_ec, 1);
-		if (ACPI_FAILURE(status))
-			return (status);
-
-		if (sc->cmos_handle) {
-			val = val_ec & IBM_EC_MASK_VOL;
-
-			Args.Count = 1;
-			Args.Pointer = &Arg;
-			Arg.Type = ACPI_TYPE_INTEGER;
-			Arg.Integer.Value = (arg > val) ? IBM_CMOS_VOLUME_UP : IBM_CMOS_VOLUME_DOWN;
-
-			step = (arg > val) ? 1 : -1;
-			for (int i = val; i != arg; i += step) {
-				status = AcpiEvaluateObject(sc->cmos_handle, NULL, &Args, NULL);
-				if (ACPI_FAILURE(status))
-					break;
-			}
-		}
-		return ACPI_EC_WRITE(sc->ec_dev, IBM_EC_VOLUME, arg + (val_ec & (~IBM_EC_MASK_VOL)), 1);
+		return acpi_ibm_volume_set(sc, arg);
 		break;
 
 	case ACPI_IBM_METHOD_MUTE:
-		if (arg < 0 || arg > 1)
-			return (EINVAL);
-
-		status = ACPI_EC_READ(sc->ec_dev, IBM_EC_VOLUME, &val_ec, 1);
-		if (ACPI_FAILURE(status))
-			return (status);
-
-		if (sc->cmos_handle) {
-			Args.Count = 1;
-			Args.Pointer = &Arg;
-			Arg.Type = ACPI_TYPE_INTEGER;
-			Arg.Integer.Value = IBM_CMOS_VOLUME_MUTE;
-
-			status = AcpiEvaluateObject(sc->cmos_handle, NULL, &Args, NULL);
-			if (ACPI_FAILURE(status))
-				break;
-		}
-		return ACPI_EC_WRITE(sc->ec_dev, IBM_EC_VOLUME, (arg==1) ? val_ec | IBM_EC_MASK_MUTE : val_ec & (~IBM_EC_MASK_MUTE), 1);
+		return acpi_ibm_mute_set(sc, arg);
 		break;
 
 	case ACPI_IBM_METHOD_THINKLIGHT:
-		if (arg < 0 || arg > 1)
-			return (EINVAL);
-
-		if (sc->light_set_supported) {
-			Args.Count = 1;
-			Args.Pointer = &Arg;
-			Arg.Type = ACPI_TYPE_INTEGER;
-			Arg.Integer.Value = arg ? sc->light_cmd_on : sc->light_cmd_off;
-
-			status = AcpiEvaluateObject(sc->light_handle, NULL, &Args, NULL);
-			if (ACPI_SUCCESS(status))
-				sc->light_val = arg;
-			return (status);
-		}
+		return acpi_ibm_thinklight_set(sc, arg);
 		break;
 
 	case ACPI_IBM_METHOD_BLUETOOTH:
-		if (arg < 0 || arg > 1)
-			return (EINVAL);
-
-		val = (arg == 1) ? sc->wlan_bt_flags | IBM_NAME_MASK_BT : sc->wlan_bt_flags & (~IBM_NAME_MASK_BT);
-		return acpi_SetInteger(sc->handle, IBM_NAME_WLAN_BT_SET, val);
+		return acpi_ibm_bluetooth_set(sc, arg);
 		break;
 
 	case ACPI_IBM_METHOD_FANLEVEL:
@@ -898,6 +854,9 @@ acpi_ibm_sysctl_init(struct acpi_ibm_sof
 			return (TRUE);
 		}
 		return (FALSE);
+
+	case ACPI_IBM_METHOD_HANDLEREVENTS:
+		return (TRUE);
 	}
 	return (FALSE);
 }
@@ -937,6 +896,328 @@ acpi_ibm_thermal_sysctl(SYSCTL_HANDLER_A
 	return (error);
 }
 
+static int
+acpi_ibm_handlerevents_sysctl(SYSCTL_HANDLER_ARGS)
+{
+	struct acpi_ibm_softc	*sc;
+	int			error = 0;
+	struct sbuf		sb;
+	char			*cp, *ep;
+	int			l, val;
+	unsigned int		handler_events;
+
+	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+	sc = (struct acpi_ibm_softc *)oidp->oid_arg1;
+
+	if (sbuf_new(&sb, NULL, 128, SBUF_AUTOEXTEND) == NULL)
+		return (ENOMEM);
+
+	ACPI_SERIAL_BEGIN(ibm);
+
+	/* Get old values if this is a get request. */
+	if (req->newptr == NULL) {
+		for (int i = 0; i < 8 * sizeof(sc->handler_events); i++)
+			if (sc->handler_events & (1 << i))
+				sbuf_printf(&sb, "0x%02x ", i + 1);
+		if (sbuf_len(&sb) == 0)
+			sbuf_printf(&sb, "NONE");
+	}
+
+	sbuf_trim(&sb);
+	sbuf_finish(&sb);
+
+	/* Copy out the old values to the user. */
+	error = SYSCTL_OUT(req, sbuf_data(&sb), sbuf_len(&sb));
+	sbuf_delete(&sb);
+
+	if (error != 0 || req->newptr == NULL)
+		goto out;
+
+	/* If the user is setting a string, parse it. */
+	handler_events = 0;
+	cp = (char *)req->newptr;
+	while (*cp) {
+		if (isspace(*cp)) {
+			cp++;
+			continue;
+		}
+
+		ep = cp;
+
+		while (*ep && !isspace(*ep))
+			ep++;
+
+		l = ep - cp;
+		if (l == 0)
+			break;
+
+		if (strncmp(cp, "NONE", 4) == 0) {
+			cp = ep;
+			continue;
+		}
+
+		if (l >= 3 && cp[0] == '0' && (cp[1] == 'X' || cp[1] == 'x'))
+			val = strtoul(cp, &ep, 16);
+		else
+			val = strtoul(cp, &ep, 10);
+
+		if (val == 0 || ep == cp || val >= 8 * sizeof(handler_events)) {
+			cp[l] = '\0';
+			device_printf(sc->dev, "invalid event code: %s\n", cp);
+			error = EINVAL;
+			goto out;
+		}
+
+		handler_events |= 1 << (val - 1);
+
+		cp = ep;
+	}
+
+	sc->handler_events = handler_events;
+out:
+	ACPI_SERIAL_END(ibm);
+	return (error);
+}
+
+static int
+acpi_ibm_brightness_set(struct acpi_ibm_softc *sc, int arg)
+{
+	int			val, step;
+	UINT64			val_ec;
+	ACPI_OBJECT		Arg;
+	ACPI_OBJECT_LIST	Args;
+	ACPI_STATUS		status;
+
+	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+	ACPI_SERIAL_ASSERT(ibm);
+
+	if (arg < 0 || arg > 7)
+		return (EINVAL);
+
+	/* Read the current brightness */
+	status = ACPI_EC_READ(sc->ec_dev, IBM_EC_BRIGHTNESS, &val_ec, 1);
+	if (ACPI_FAILURE(status))
+		return (status);
+
+	if (sc->cmos_handle) {
+		val = val_ec & IBM_EC_MASK_BRI;
+
+		Args.Count = 1;
+		Args.Pointer = &Arg;
+		Arg.Type = ACPI_TYPE_INTEGER;
+		Arg.Integer.Value = (arg > val) ? IBM_CMOS_BRIGHTNESS_UP :
+						  IBM_CMOS_BRIGHTNESS_DOWN;
+
+		step = (arg > val) ? 1 : -1;
+		for (int i = val; i != arg; i += step) {
+			status = AcpiEvaluateObject(sc->cmos_handle, NULL,
+						    &Args, NULL);
+			if (ACPI_FAILURE(status)) {
+				/* Record the last value */
+				if (i != val) {
+					ACPI_EC_WRITE(sc->ec_dev,
+					    IBM_EC_BRIGHTNESS, i - step, 1);
+				}
+				return (status);
+			}
+		}
+	}
+
+	return ACPI_EC_WRITE(sc->ec_dev, IBM_EC_BRIGHTNESS, arg, 1);
+}
+
+static int
+acpi_ibm_bluetooth_set(struct acpi_ibm_softc *sc, int arg)
+{
+	int			val;
+
+	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+	ACPI_SERIAL_ASSERT(ibm);
+
+	if (arg < 0 || arg > 1)
+		return (EINVAL);
+
+	val = (arg == 1) ? sc->wlan_bt_flags | IBM_NAME_MASK_BT :
+			   sc->wlan_bt_flags & (~IBM_NAME_MASK_BT);
+	return acpi_SetInteger(sc->handle, IBM_NAME_WLAN_BT_SET, val);
+}
+
+static int
+acpi_ibm_thinklight_set(struct acpi_ibm_softc *sc, int arg)
+{
+	ACPI_OBJECT		Arg;
+	ACPI_OBJECT_LIST	Args;
+	ACPI_STATUS		status;
+
+	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+	ACPI_SERIAL_ASSERT(ibm);
+
+	if (arg < 0 || arg > 1)
+		return (EINVAL);
+
+	if (sc->light_set_supported) {
+		Args.Count = 1;
+		Args.Pointer = &Arg;
+		Arg.Type = ACPI_TYPE_INTEGER;
+		Arg.Integer.Value = arg ? sc->light_cmd_on : sc->light_cmd_off;
+
+		status = AcpiEvaluateObject(sc->light_handle, NULL,
+					    &Args, NULL);
+		if (ACPI_SUCCESS(status))
+			sc->light_val = arg;
+		return (status);
+	}
+
+	return (0);
+}
+
+static int
+acpi_ibm_volume_set(struct acpi_ibm_softc *sc, int arg)
+{
+	int			val, step;
+	UINT64			val_ec;
+	ACPI_OBJECT		Arg;
+	ACPI_OBJECT_LIST	Args;
+	ACPI_STATUS		status;
+
+	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+	ACPI_SERIAL_ASSERT(ibm);
+
+	if (arg < 0 || arg > 14)
+		return (EINVAL);
+
+	/* Read the current volume */
+	status = ACPI_EC_READ(sc->ec_dev, IBM_EC_VOLUME, &val_ec, 1);
+	if (ACPI_FAILURE(status))
+		return (status);
+
+	if (sc->cmos_handle) {
+		val = val_ec & IBM_EC_MASK_VOL;
+
+		Args.Count = 1;
+		Args.Pointer = &Arg;
+		Arg.Type = ACPI_TYPE_INTEGER;
+		Arg.Integer.Value = (arg > val) ? IBM_CMOS_VOLUME_UP :
+						  IBM_CMOS_VOLUME_DOWN;
+
+		step = (arg > val) ? 1 : -1;
+		for (int i = val; i != arg; i += step) {
+			status = AcpiEvaluateObject(sc->cmos_handle, NULL,
+						    &Args, NULL);
+			if (ACPI_FAILURE(status)) {
+				/* Record the last value */
+				if (i != val) {
+					val_ec = i - step +
+						 (val_ec & (~IBM_EC_MASK_VOL));
+					ACPI_EC_WRITE(sc->ec_dev, IBM_EC_VOLUME,
+						      val_ec, 1);
+				}
+				return (status);
+			}
+		}
+	}
+
+	val_ec = arg + (val_ec & (~IBM_EC_MASK_VOL));
+	return ACPI_EC_WRITE(sc->ec_dev, IBM_EC_VOLUME, val_ec, 1);
+}
+
+static int
+acpi_ibm_mute_set(struct acpi_ibm_softc *sc, int arg)
+{
+	UINT64			val_ec;
+	ACPI_OBJECT		Arg;
+	ACPI_OBJECT_LIST	Args;
+	ACPI_STATUS		status;
+
+	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+	ACPI_SERIAL_ASSERT(ibm);
+
+	if (arg < 0 || arg > 1)
+		return (EINVAL);
+
+	status = ACPI_EC_READ(sc->ec_dev, IBM_EC_VOLUME, &val_ec, 1);
+	if (ACPI_FAILURE(status))
+		return (status);
+
+	if (sc->cmos_handle) {
+		Args.Count = 1;
+		Args.Pointer = &Arg;
+		Arg.Type = ACPI_TYPE_INTEGER;
+		Arg.Integer.Value = IBM_CMOS_VOLUME_MUTE;
+
+		status = AcpiEvaluateObject(sc->cmos_handle, NULL, &Args, NULL);
+		if (ACPI_FAILURE(status))
+			return (status);
+	}
+
+	val_ec = (arg == 1) ? val_ec | IBM_EC_MASK_MUTE :
+			      val_ec & (~IBM_EC_MASK_MUTE);
+	return ACPI_EC_WRITE(sc->ec_dev, IBM_EC_VOLUME, val_ec, 1);
+}
+
+static void
+acpi_ibm_eventhandler(struct acpi_ibm_softc *sc, int arg)
+{
+	int			val;
+	UINT64			val_ec;
+	ACPI_STATUS		status;
+
+	ACPI_SERIAL_BEGIN(ibm);
+	switch (arg) {
+	case IBM_EVENT_SUSPEND_TO_RAM:
+		power_pm_suspend(POWER_SLEEP_STATE_SUSPEND);
+		break;
+
+	case IBM_EVENT_BLUETOOTH:
+		acpi_ibm_bluetooth_set(sc, (sc->wlan_bt_flags == 0));
+		break;
+
+	case IBM_EVENT_BRIGHTNESS_UP:
+	case IBM_EVENT_BRIGHTNESS_DOWN:
+		/* Read the current brightness */
+		status = ACPI_EC_READ(sc->ec_dev, IBM_EC_BRIGHTNESS,
+				      &val_ec, 1);
+		if (ACPI_FAILURE(status))
+			return;
+
+		val = val_ec & IBM_EC_MASK_BRI;
+		val = (arg == IBM_EVENT_BRIGHTNESS_UP) ? val + 1 : val - 1;
+		acpi_ibm_brightness_set(sc, val);
+		break;
+
+	case IBM_EVENT_THINKLIGHT:
+		acpi_ibm_thinklight_set(sc, (sc->light_val == 0));
+		break;
+
+	case IBM_EVENT_VOLUME_UP:
+	case IBM_EVENT_VOLUME_DOWN:
+		/* Read the current volume */
+		status = ACPI_EC_READ(sc->ec_dev, IBM_EC_VOLUME, &val_ec, 1);
+		if (ACPI_FAILURE(status))
+			return;
+
+		val = val_ec & IBM_EC_MASK_VOL;
+		val = (arg == IBM_EVENT_VOLUME_UP) ? val + 1 : val - 1;
+		acpi_ibm_volume_set(sc, val);
+		break;
+
+	case IBM_EVENT_MUTE:
+		/* Read the current value */
+		status = ACPI_EC_READ(sc->ec_dev, IBM_EC_VOLUME, &val_ec, 1);
+		if (ACPI_FAILURE(status))
+			return;
+
+		val = ((val_ec & IBM_EC_MASK_MUTE) == IBM_EC_MASK_MUTE);
+		acpi_ibm_mute_set(sc, (val == 0));
+		break;
+
+	default:
+		break;
+	}
+	ACPI_SERIAL_END(ibm);
+}
+
 static void
 acpi_ibm_notify(ACPI_HANDLE h, UINT32 notify, void *context)
 {
@@ -965,6 +1246,10 @@ acpi_ibm_notify(ACPI_HANDLE h, UINT32 no
 				break;
 			}
 
+			/* Execute event handler */
+			if (sc->handler_events & (1 << (arg - 1)))
+				acpi_ibm_eventhandler(sc, (arg & 0xff));
+
 			/* Notify devd(8) */
 			acpi_UserNotify("IBM", h, (arg & 0xff));
 			break;


More information about the svn-src-stable-9 mailing list