[PATCH 6/6] add input.jack support

Guillem Jover guillem.jover at nokia.com
Fri Oct 31 17:31:13 PDT 2008


A device with an input.jack capability supports sensing when a jack has
been inserted or removed from the socket. Additional capabilities might
be present depending on what the socket is able to sense. The device
will have a button to signal those events, and a property input.jack.type
listing the supported contacts in the currently plugged jack.

The supported jack types are: headphone, microphone and line-out.
---
 doc/spec/hal-spec-properties.xml |   98 ++++++++++++++++++++++++++++++++++++++
 hald/linux/addons/addon-input.c  |   58 ++++++++++++++++++++--
 hald/linux/device.c              |   43 +++++++++++++++-
 hald/linux/probing/probe-input.c |   27 ++++++-----
 4 files changed, 205 insertions(+), 21 deletions(-)

diff --git a/doc/spec/hal-spec-properties.xml b/doc/spec/hal-spec-properties.xml
index a942513..b7ddcf9 100644
--- a/doc/spec/hal-spec-properties.xml
+++ b/doc/spec/hal-spec-properties.xml
@@ -4327,6 +4327,14 @@ org.freedesktop.Hal.Device.Volume.method_signatures = {'ssas', 'as', 'as'}
               </entry>
             </row>
             <row>
+              <entry></entry>
+              <entry>jack_insert</entry>
+              <entry></entry>
+              <entry>
+                A jack socket triggering insertion and removal events
+              </entry>
+            </row>
+            <row>
               <entry>
                 <literal>button.has_state</literal> (bool)
               </entry>
@@ -4500,6 +4508,96 @@ org.freedesktop.Hal.Device.Volume.method_signatures = {'ssas', 'as', 'as'}
       </informaltable>
     </sect2>
 
+    <sect2 id="device-properties-input-jack">
+      <title>
+        input.jack namespace
+      </title>
+      <para>
+        Device objects with the capability <literal>input.jack</literal>
+        are jack sockets.
+      </para>
+      <informaltable>
+        <tgroup cols="2">
+          <thead>
+            <row>
+              <entry>Key (type)</entry>
+              <entry>Values</entry>
+              <entry>Mandatory</entry>
+              <entry>Description</entry>
+            </row>
+          </thead>
+          <tbody>
+            <row>
+              <entry>
+                <literal>input.jack.type</literal> (strlist)
+              </entry>
+              <entry></entry>
+              <entry>Yes</entry>
+              <entry>
+                The type of jack currently plugged. Several strings can be
+                present at the same time if the currently plugged jack
+                supports them.
+              </entry>
+            </row>
+            <row>
+              <entry></entry>
+              <entry>headphone</entry>
+              <entry></entry>
+              <entry>
+                The inserted jack connects to a headphone.
+              </entry>
+            </row>
+            <row>
+              <entry></entry>
+              <entry>microphone</entry>
+              <entry></entry>
+              <entry>
+                The inserted jack connects to a microphone.
+              </entry>
+            </row>
+            <row>
+              <entry></entry>
+              <entry>line-out</entry>
+              <entry></entry>
+              <entry>
+                The inserted jack connects to a line-in.
+              </entry>
+            </row>
+          </tbody>
+        </tgroup>
+      </informaltable>
+    </sect2>
+
+    <sect2 id="device-properties-input-jack-headphone">
+      <title>
+        input.jack.headphone namespace
+      </title>
+      <para>
+        The input device is a jack socket that supports headphone jacks.
+        No namespace specific properties.
+      </para>
+    </sect2>
+
+    <sect2 id="device-properties-input-jack-microphone">
+      <title>
+        input.jack.microphone namespace
+      </title>
+      <para>
+        The input device is a jack socket that supports microphone jacks.
+        No namespace specific properties.
+      </para>
+    </sect2>
+
+    <sect2 id="device-properties-input-jack-line-out">
+      <title>
+        input.jack.lineout namespace
+      </title>
+      <para>
+        The input device is a jack socket that supports line-out jacks.
+        No namespace specific properties.
+      </para>
+    </sect2>
+
     <sect2 id="device-properties-input-joystick">
       <title>
         input.joystick namespace
diff --git a/hald/linux/addons/addon-input.c b/hald/linux/addons/addon-input.c
index a4a763f..087ce11 100644
--- a/hald/linux/addons/addon-input.c
+++ b/hald/linux/addons/addon-input.c
@@ -7,6 +7,7 @@
  * Copyright (C) 2005 Ryan Lortie <desrt at desrt.ca>
  * Copyright (C) 2006 Matthew Garrett <mjg59 at srcf.ucam.org>
  * Copyright (C) 2007 Codethink Ltd. Author Rob Taylor <rob.taylor at codethink.co.uk>
+ * Copyright (C) 2008 Nokia Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -168,6 +169,8 @@ struct _InputData
 	char *button_type;
 	gboolean button_has_state;
 	gboolean button_state;
+	gboolean button_new_state;
+	gboolean is_jack;
 	char udi[1];			/*variable size*/
 };
 
@@ -177,12 +180,13 @@ static GHashTable *inputs = NULL;
 static GList *devices = NULL;
 
 static void
-emit_switch_condition (InputData *input_data, gboolean new_state)
+emit_switch_condition (InputData *input_data)
 {
-	if (new_state != input_data->button_state) {
+	if (input_data->button_new_state != input_data->button_state) {
 		DBusError error;
 
-		input_data->button_state = new_state;
+		input_data->button_state = input_data->button_new_state;
+		input_data->button_new_state = 0;
 
 		dbus_error_init (&error);
 		libhal_device_set_property_bool (ctx, input_data->udi, "button.state.value",
@@ -197,6 +201,19 @@ emit_switch_condition (InputData *input_data, gboolean new_state)
 	}
 }
 
+static void
+set_jack_switch_type (const char *udi, const char *name, gboolean state)
+{
+	DBusError error;
+
+	dbus_error_init (&error);
+	if (state)
+		libhal_device_property_strlist_append (ctx, udi, "input.jack.type", name, &error);
+	else
+		libhal_device_property_strlist_remove (ctx, udi, "input.jack.type", name, &error);
+	dbus_error_free (&error);
+}
+
 static gboolean
 event_io (GIOChannel *channel, GIOCondition condition, gpointer data)
 {
@@ -230,7 +247,6 @@ event_io (GIOChannel *channel, GIOCondition condition, gpointer data)
 			switch (event.code) {
 			case SW_LID:
 			case SW_TABLET_MODE:
-			case SW_HEADPHONE_INSERT:
 			case SW_RFKILL_ALL:
 				/* check switch state - cuz apparently we get spurious events (or I don't know
 				 * how to use the input layer correctly)
@@ -246,16 +262,38 @@ event_io (GIOChannel *channel, GIOCondition condition, gpointer data)
 				 * 19:08:26.868 [I] event.value=0 ; event.code=0 (0x00)
 				 * 19:08:26.955 [I] event.value=0 ; event.code=0 (0x00)
 				 * 19:08:26.960 [I] event.value=0 ; event.code=0 (0x00)
+				 *
+				 * XXX: with latest kernels we should be able
+				 * to just use event.value, as the input layer
+				 * removes those duped events.
+				 *
+				 * XXX: in older kernels and devices SW_LID is
+				 * not always followed by an EV_SYN event, so
+				 * this code cannot be refactored just yet.
 				 */
 
 				if (ioctl (g_io_channel_unix_get_fd(channel), EVIOCGSW(sizeof (bitmask)), bitmask) < 0) {
 					HAL_DEBUG (("ioctl EVIOCGSW failed"));
 				} else {
-					int new_state = test_bit (event.code, bitmask);
-					emit_switch_condition (input_data, new_state);
+					input_data->button_new_state = test_bit (event.code, bitmask);
+					emit_switch_condition (input_data);
 				}
 				break;
+			case SW_HEADPHONE_INSERT:
+				input_data->button_new_state |= event.value;
+				set_jack_switch_type (input_data->udi, "headphone", event.value);
+				break;
+			case SW_MICROPHONE_INSERT:
+				input_data->button_new_state |= event.value;
+				set_jack_switch_type (input_data->udi, "microphone", event.value);
+				break;
+			case SW_LINEOUT_INSERT:
+				input_data->button_new_state |= event.value;
+				set_jack_switch_type (input_data->udi, "line-out", event.value);
+				break;
 			}
+		} else if (event.type == EV_SYN && input_data->is_jack) {
+			emit_switch_condition (input_data);
 		} else if (event.type == EV_KEY && key_name[event.code] != NULL && event.value) {
 			dbus_error_init (&error);
 			libhal_device_emit_condition (ctx, input_data->udi,
@@ -315,6 +353,7 @@ add_device (LibHalContext *ctx,
 	int len = strlen (udi);
 	const char* device_file;
 	const char *button_type;
+	long bitmask[NBITS(SW_MAX)];
 
 	data = (InputData*) g_malloc (sizeof (InputData) + len);
 
@@ -330,6 +369,8 @@ add_device (LibHalContext *ctx,
 		button_type = "unknown";
 	data->button_type = g_strdup (button_type);
 
+	data->is_jack = strcmp (data->button_type, "jack_insert") == 0;
+
 	/* button_has_state will be false if the key isn't available*/
 	data->button_has_state = libhal_ps_get_bool (properties, "button.has_state");
 	if (data->button_has_state)
@@ -341,6 +382,11 @@ add_device (LibHalContext *ctx,
 		return;
 	}
 
+	if (data->is_jack && ioctl (eventfp, EVIOCGSW (sizeof (bitmask)), bitmask) < 0) {
+		set_jack_switch_type (udi, "headphone", test_bit (SW_HEADPHONE_INSERT, bitmask));
+		set_jack_switch_type (udi, "microphone", test_bit (SW_MICROPHONE_INSERT, bitmask));
+		set_jack_switch_type (udi, "line-out", test_bit (SW_LINEOUT_INSERT, bitmask));
+	}
 
 	HAL_DEBUG (("%s: Listening on %s", udi, device_file));
 
diff --git a/hald/linux/device.c b/hald/linux/device.c
index ffa68b4..97b6cfb 100644
--- a/hald/linux/device.c
+++ b/hald/linux/device.c
@@ -5,6 +5,7 @@
  * Copyright (C) 2005 Richard Hughes, <richard at hughsie.com>
  * Copyright (C) 2005 Danny Kukawka, <danny.kukawka at web.de>
  * Copyright (C) 2006 Kay Sievers <kay.sievers at vrfy.org>
+ * Copyright (C) 2007, 2008 Nokia Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -1000,6 +1001,23 @@ out:
 	;
 }
 
+static int
+input_count_jack_switches (long *bitmask)
+{
+	int jack_sw[] = {
+		 SW_HEADPHONE_INSERT,
+		 SW_MICROPHONE_INSERT,
+		 SW_LINEOUT_INSERT,
+	};
+	int i, found = 0;
+
+	for (i = 0; i < (int)(sizeof (jack_sw) / sizeof (jack_sw[0])); i++)
+		if (test_bit (jack_sw[i], bitmask))
+			found++;
+
+	return found;
+}
+
 static void
 input_test_switch (HalDevice *d, const char *sysfs_path)
 {
@@ -1016,7 +1034,9 @@ input_test_switch (HalDevice *d, const char *sysfs_path)
 		goto out;
 
 	hal_device_add_capability (d, "input.switch");
-	if (num_bits == 1) {
+	if (num_bits == 1 || num_bits == input_count_jack_switches (bitmask)) {
+		gboolean is_jack_switch = FALSE;
+
 		hal_device_add_capability (d, "button");
 		hal_device_property_set_bool (d, "button.has_state", TRUE);
 		/* NOTE: button.state.value will be set from our prober in hald/linux/probing/probe-input.c */
@@ -1026,11 +1046,28 @@ input_test_switch (HalDevice *d, const char *sysfs_path)
 			_have_sysfs_lid_button = TRUE;
 		} else if (test_bit (SW_TABLET_MODE, bitmask)) {
 			hal_device_property_set_string (d, "button.type", "tablet_mode");
-		} else if (test_bit (SW_HEADPHONE_INSERT, bitmask)) {
-			hal_device_property_set_string (d, "button.type", "headphone_insert");
 		} else if (test_bit (SW_RFKILL_ALL, bitmask)) {
 			hal_device_property_set_string (d, "button.type", "radio");
 		}
+
+		if (test_bit (SW_HEADPHONE_INSERT, bitmask)) {
+			is_jack_switch = TRUE;
+			hal_device_add_capability (d, "input.jack.headphone");
+		}
+		if (test_bit (SW_MICROPHONE_INSERT, bitmask)) {
+			is_jack_switch = TRUE;
+			hal_device_add_capability (d, "input.jack.microphone");
+		}
+		if (test_bit (SW_LINEOUT_INSERT, bitmask)) {
+			is_jack_switch = TRUE;
+			hal_device_add_capability (d, "input.jack.lineout");
+		}
+
+		if (is_jack_switch) {
+			hal_device_add_capability (d, "input.jack");
+			hal_device_property_set_strlist (d, "input.jack.type", NULL);
+			hal_device_property_set_string (d, "button.type", "jack_insert");
+		}
 	}
 
 out:
diff --git a/hald/linux/probing/probe-input.c b/hald/linux/probing/probe-input.c
index e860b5e..8617498 100644
--- a/hald/linux/probing/probe-input.c
+++ b/hald/linux/probing/probe-input.c
@@ -4,6 +4,7 @@
  * probe-input.c : Probe input devices
  *
  * Copyright (C) 2004 David Zeuthen, <david at fubar.dk>
+ * Copyright (C) 2008 Nokia Corporation
  *
  * Licensed under the Academic Free License version 2.1
  *
@@ -71,17 +72,6 @@ main (int argc, char *argv[])
 	if (button_type == NULL)
 		goto out;
 
-	if (strcmp (button_type, "lid") == 0)
-		sw = SW_LID;
-	else if (strcmp (button_type, "tablet_mode") == 0)
-		sw = SW_TABLET_MODE;
-	else if (strcmp (button_type, "headphone_insert") == 0)
-		sw = SW_HEADPHONE_INSERT;
-	else if (strcmp (button_type, "radio") == 0)
-		sw = SW_RFKILL_ALL;
-	else
-		goto out;
-
 	device_file = getenv ("HAL_PROP_INPUT_DEVICE");
 	if (device_file == NULL)
 		goto out;
@@ -107,8 +97,21 @@ main (int argc, char *argv[])
 		goto out;
 	}
 
+	if (strcmp (button_type, "lid") == 0)
+		sw = test_bit (SW_LID, bitmask);
+	else if (strcmp (button_type, "tablet_mode") == 0)
+		sw = test_bit (SW_TABLET_MODE, bitmask);
+	else if (strcmp (button_type, "radio") == 0)
+		sw = test_bit (SW_RADIO, bitmask);
+	else if (strcmp (button_type, "jack_insert") == 0) {
+		sw = test_bit (SW_HEADPHONE_INSERT, bitmask) ||
+		     test_bit (SW_MICROPHONE_INSERT, bitmask) ||
+		     test_bit (SW_LINEOUT_INSERT, bitmask);
+	} else
+		goto out;
+
 	dbus_error_init (&error);
-	libhal_device_set_property_bool (ctx, udi, "button.state.value", test_bit (sw, bitmask), &error);
+	libhal_device_set_property_bool (ctx, udi, "button.state.value", sw, &error);
 	
 	ret = 0;
 
-- 
1.6.0.2



More information about the hal mailing list