All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 3/3] AVRCP: Add Passthrough Signal
@ 2011-08-24  3:27 David Stockwell
  2011-08-24  8:36 ` Johan Hedberg
  0 siblings, 1 reply; 9+ messages in thread
From: David Stockwell @ 2011-08-24  3:27 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: lucas.demarchi, luiz.dentz, johan.hedberg

AVRCP: Add Passthrough Signal

Send Passthrough signal, not only for simple keystrokes,
but especially for Vendor Unique key, passing company-id
and vendor-unique string as well.
---
 audio/control.c     |   90 
+++++++++++++++++++++++++++++++++++++++++++--------
 doc/control-api.txt |   14 +++-----
 2 files changed, 81 insertions(+), 23 deletions(-)

diff --git a/audio/control.c b/audio/control.c
index dd2930c..fcaad7c 100644
--- a/audio/control.c
+++ b/audio/control.c
@@ -106,6 +106,8 @@
 #define FORWARD_OP		0x4b
 #define BACKWARD_OP		0x4c
 
+#define VENDOR_UNIQUE_OP	0x7E
+
 /* Company IDs for vendor dependent commands */
 #define IEEEID_BTSIG		0x001958
 
@@ -515,28 +517,88 @@ static void send_key(int fd, uint16_t key, int pressed)
 	send_event(fd, EV_SYN, SYN_REPORT, 0);
 }
 
+/**
+ *	handle_panel_passthrough:
+ *
+ *	Handles AVRCP 1.0+ PASSTHROUGH command, passes the keystroke to uinput.
+ *
+ *	Added a Passthrough signal, with the key state and the optional
+ *	following company_id and vendor-unique message.
+ */
+
 static void handle_panel_passthrough(struct control *control,
-					const unsigned char *operands,
+					const uint8_t *operands,
 					int operand_count)
 {
 	const char *status;
-	int pressed, i;
-
-	if (operand_count == 0)
+	int i;
+	uint8_t key_pressed;
+	gboolean key_state;
+	uint32_t pass_company_id;
+	char *pass_string;
+	/*
+	 * operands[1] is operation_data_field_length (AV/C Panel Specification
+	 * v1.23, sect 9.4.5). Should always be present, even if zero.
+	 */
+	if (operand_count < 2)
 		return;
 
-	if (operands[0] & 0x80) {
-		status = "released";
-		pressed = 0;
+	key_pressed = operands[0] & 0x7F;
+
+	/* If key is pressed, key state bit is zero (AVRCP v13r00 p89). */
+	key_state = ((operands[0] & 0x80) == 0);
+	status = key_state ? "pressed" : "released";
+
+	DBG("Passthrough Key: %x %s", key_pressed, status);
+
+	if (key_pressed == VENDOR_UNIQUE_OP) {
+		if (operands[1] == 0 || operand_count < 5) {
+			pass_company_id = 0;
+			pass_string = g_malloc0(1);
+			DBG("Passthrough: No Company_ID or String");
+		} else if (operands[1] == 3 && operand_count == 5) {
+			pass_company_id = get_company_id(operands + 2);
+			pass_string = g_malloc0(1);
+			DBG("Passthrough Company_ID: %06X String: <none>",
+						pass_company_id);
+		} else if (operands[1] > 3 &&
+					operand_count == operands[1] + 2) {
+			pass_company_id = get_company_id(operands + 2);
+			pass_string = g_strndup((gchar *) operands + 5,
+							operands[1] - 3);
+			DBG("Passthrough Company_ID: %06X String: %s",
+						pass_company_id, pass_string);
+		} else { /* op_length does not match operand_count */
+			DBG("Passthrough: Malformed message");
+			DBG("op_len %u, op_cnt %u", operands[1], operand_count);
+			pass_company_id = 0;
+			pass_string = g_malloc0(1);
+		}
 	} else {
-		status = "pressed";
-		pressed = 1;
+		pass_company_id = 0;
+		pass_string = g_malloc0(1);
 	}
 
+	/*
+	 * Generate passthrough signal only if not BTSIG Company_ID.
+	 * For BTSIG, passthrough only for Group Navigation (unimplemented).
+	 */
+
+	if (pass_company_id != IEEEID_BTSIG)
+		g_dbus_emit_signal(control->dev->conn, control->dev->path,
+			   AUDIO_CONTROL_INTERFACE, "Passthrough",
+			   DBUS_TYPE_BYTE, &key_pressed,
+			   DBUS_TYPE_BOOLEAN, &key_state,
+			   DBUS_TYPE_UINT32, &pass_company_id,
+			   DBUS_TYPE_STRING, &pass_string,
+			   DBUS_TYPE_INVALID);
+
+	g_free(pass_string);
+
 	for (i = 0; key_map[i].name != NULL; i++) {
 		uint8_t key_quirks;
 
-		if ((operands[0] & 0x7F) != key_map[i].avrcp)
+		if (key_pressed != key_map[i].avrcp)
 			continue;
 
 		DBG("AVRCP: %s %s", key_map[i].name, status);
@@ -544,7 +606,7 @@ static void handle_panel_passthrough(struct control 
*control,
 		key_quirks = control->key_quirks[key_map[i].avrcp];
 
 		if (key_quirks & QUIRK_NO_RELEASE) {
-			if (!pressed) {
+			if (!key_state) {
 				DBG("AVRCP: Ignoring release");
 				break;
 			}
@@ -555,13 +617,12 @@ static void handle_panel_passthrough(struct control 
*control,
 			break;
 		}
 
-		send_key(control->uinput, key_map[i].uinput, pressed);
+		send_key(control->uinput, key_map[i].uinput, key_state);
 		break;
 	}
 
 	if (key_map[i].name == NULL)
-		DBG("AVRCP: unknown button 0x%02X %s",
-						operands[0] & 0x7F, status);
+		DBG("AVRCP: unknown button 0x%02X %s", key_pressed, status);
 }
 
 static unsigned int attr_get_max_val(uint8_t attr)
@@ -2291,6 +2352,7 @@ static GDBusSignalTable control_signals[] = {
 	{ "Connected",			"",	G_DBUS_SIGNAL_FLAG_DEPRECATED},
 	{ "Disconnected",		"",	G_DBUS_SIGNAL_FLAG_DEPRECATED},
 	{ "PropertyChanged",		"sv"	},
+	{ "Passthrough",		"ybus"	},
 	{ NULL, NULL }
 };
 
diff --git a/doc/control-api.txt b/doc/control-api.txt
index a7e5cbb..64ea5d3 100644
--- a/doc/control-api.txt
+++ b/doc/control-api.txt
@@ -55,18 +55,14 @@ Signals		Connected()
 			Sent when the AVRCP connection to the remote device
 			has been disconnected.
 
-		Passthrough(uint8 key, boolean state, int32 company_id,
+		Passthrough(uint8 key, boolean state, uint32 company_id,
 								string op_data)
 
-			Called when Passthrough command is received from
-			connected device.
+			Sent when Passthrough received from CT.
 
-			NOTE: according to the AV/C Subpanel Spec, company_id
-			and op_data are passed ONLY when the key is
-			"Vendor_Unique", or 0x7E.
-
-			When the key is NOT 0x7E, the signal returns
-			company_id=-1, and zero-length op_data.
+			Company_id and op_data returned only when key is 0x7E
+			(OP_VENDOR_UNIQUE).  Otherwise, returns zero for
+			company_id, and zero-length op_data.
 
 		VendorDependentReceived(string op_data)
 
-- 
1.7.3.4


^ permalink raw reply related	[flat|nested] 9+ messages in thread
* [PATCH 3/3] AVRCP: Add Passthrough Signal
@ 2011-08-24 13:07 David Stockwell
  2011-08-24 22:47 ` Luiz Augusto von Dentz
  0 siblings, 1 reply; 9+ messages in thread
From: David Stockwell @ 2011-08-24 13:07 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg

[PATCH 3/3] AVRCP: Add Passthrough Signal

Send Passthrough signal, not only for simple keystrokes,
but especially for Vendor Unique key, passing company-id
and vendor-unique string as well.
---
 audio/control.c     |   90 
+++++++++++++++++++++++++++++++++++++++++++--------
 doc/control-api.txt |   14 +++-----
 2 files changed, 81 insertions(+), 23 deletions(-)

diff --git a/audio/control.c b/audio/control.c
index eb86029..269c793 100644
--- a/audio/control.c
+++ b/audio/control.c
@@ -106,6 +106,8 @@
 #define FORWARD_OP		0x4b
 #define BACKWARD_OP		0x4c
 
+#define VENDOR_UNIQUE_OP	0x7E
+
 /* Company IDs for vendor dependent commands */
 #define IEEEID_BTSIG		0x001958
 
@@ -515,28 +517,88 @@ static void send_key(int fd, uint16_t key, int pressed)
 	send_event(fd, EV_SYN, SYN_REPORT, 0);
 }
 
+/**
+ *	handle_panel_passthrough:
+ *
+ *	Handles AVRCP 1.0+ PASSTHROUGH command, passes the keystroke to uinput.
+ *
+ *	Added a Passthrough signal, with the key state and the optional
+ *	following company_id and vendor-unique message.
+ */
+
 static void handle_panel_passthrough(struct control *control,
-					const unsigned char *operands,
+					const uint8_t *operands,
 					int operand_count)
 {
 	const char *status;
-	int pressed, i;
-
-	if (operand_count == 0)
+	int i;
+	uint8_t key_pressed;
+	gboolean key_state;
+	uint32_t pass_company_id;
+	char *pass_string;
+	/*
+	 * operands[1] is operation_data_field_length (AV/C Panel Specification
+	 * v1.23, sect 9.4.5). Should always be present, even if zero.
+	 */
+	if (operand_count < 2)
 		return;
 
-	if (operands[0] & 0x80) {
-		status = "released";
-		pressed = 0;
+	key_pressed = operands[0] & 0x7F;
+
+	/* If key is pressed, key state bit is zero (AVRCP v13r00 p89). */
+	key_state = ((operands[0] & 0x80) == 0);
+	status = key_state ? "pressed" : "released";
+
+	DBG("Passthrough Key: %x %s", key_pressed, status);
+
+	if (key_pressed == VENDOR_UNIQUE_OP) {
+		if (operands[1] == 0 || operand_count < 5) {
+			pass_company_id = 0;
+			pass_string = g_strdup("");
+			DBG("Passthrough: No Company_ID or String");
+		} else if (operands[1] == 3 && operand_count == 5) {
+			pass_company_id = get_company_id(operands + 2);
+			pass_string = g_strdup("");
+			DBG("Passthrough Company_ID: %06X String: <none>",
+						pass_company_id);
+		} else if (operands[1] > 3 &&
+					operand_count == operands[1] + 2) {
+			pass_company_id = get_company_id(operands + 2);
+			pass_string = g_strndup((gchar *) operands + 5,
+							operands[1] - 3);
+			DBG("Passthrough Company_ID: %06X String: %s",
+						pass_company_id, pass_string);
+		} else { /* op_length does not match operand_count */
+			DBG("Passthrough: Malformed message");
+			DBG("op_len %u, op_cnt %u", operands[1], operand_count);
+			pass_company_id = 0;
+			pass_string = g_strdup("");
+		}
 	} else {
-		status = "pressed";
-		pressed = 1;
+		pass_company_id = 0;
+		pass_string = g_strdup("");
 	}
 
+	/*
+	 * Generate passthrough signal only if not BTSIG Company_ID.
+	 * For BTSIG, passthrough only for Group Navigation (unimplemented).
+	 */
+
+	if (pass_company_id != IEEEID_BTSIG)
+		g_dbus_emit_signal(control->dev->conn, control->dev->path,
+			AUDIO_CONTROL_INTERFACE, "Passthrough",
+			DBUS_TYPE_BYTE, &key_pressed,
+			DBUS_TYPE_BOOLEAN, &key_state,
+			DBUS_TYPE_UINT32, &pass_company_id,
+			DBUS_TYPE_STRING, &pass_string,
+			DBUS_TYPE_INVALID);
+
+	g_free(pass_string);
+
 	for (i = 0; key_map[i].name != NULL; i++) {
 		uint8_t key_quirks;
 
-		if ((operands[0] & 0x7F) != key_map[i].avrcp)
+		if (key_pressed != key_map[i].avrcp)
 			continue;
 
 		DBG("AVRCP: %s %s", key_map[i].name, status);
@@ -544,7 +606,7 @@ static void handle_panel_passthrough(struct control 
*control,
 		key_quirks = control->key_quirks[key_map[i].avrcp];
 
 		if (key_quirks & QUIRK_NO_RELEASE) {
-			if (!pressed) {
+			if (!key_state) {
 				DBG("AVRCP: Ignoring release");
 				break;
 			}
@@ -555,13 +617,12 @@ static void handle_panel_passthrough(struct control 
*control,
 			break;
 		}
 
-		send_key(control->uinput, key_map[i].uinput, pressed);
+		send_key(control->uinput, key_map[i].uinput, key_state);
 		break;
 	}
 
 	if (key_map[i].name == NULL)
-		DBG("AVRCP: unknown button 0x%02X %s",
-						operands[0] & 0x7F, status);
+		DBG("AVRCP: unknown button 0x%02X %s", key_pressed, status);
 }
 
 static unsigned int attr_get_max_val(uint8_t attr)
@@ -2291,6 +2352,7 @@ static GDBusSignalTable control_signals[] = {
 	{ "Connected",			"",	G_DBUS_SIGNAL_FLAG_DEPRECATED},
 	{ "Disconnected",		"",	G_DBUS_SIGNAL_FLAG_DEPRECATED},
 	{ "PropertyChanged",		"sv"	},
+	{ "Passthrough",		"ybus"	},
 	{ NULL, NULL }
 };
 
diff --git a/doc/control-api.txt b/doc/control-api.txt
index a7e5cbb..64ea5d3 100644
--- a/doc/control-api.txt
+++ b/doc/control-api.txt
@@ -55,18 +55,14 @@ Signals		Connected()
 			Sent when the AVRCP connection to the remote device
 			has been disconnected.
 
-		Passthrough(uint8 key, boolean state, int32 company_id,
+		Passthrough(uint8 key, boolean state, uint32 company_id,
 								string op_data)
 
-			Called when Passthrough command is received from
-			connected device.
+			Sent when Passthrough received from CT.
 
-			NOTE: according to the AV/C Subpanel Spec, company_id
-			and op_data are passed ONLY when the key is
-			"Vendor_Unique", or 0x7E.
-
-			When the key is NOT 0x7E, the signal returns
-			company_id=-1, and zero-length op_data.
+			Company_id and op_data returned only when key is 0x7E
+			(OP_VENDOR_UNIQUE).  Otherwise, returns zero for
+			company_id, and zero-length op_data.
 
 		VendorDependentReceived(string op_data)
 
-- 
1.7.3.4


^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2011-08-25 13:14 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-08-24  3:27 [PATCH 3/3] AVRCP: Add Passthrough Signal David Stockwell
2011-08-24  8:36 ` Johan Hedberg
2011-08-24 12:37   ` David Stockwell
2011-08-24 13:07 David Stockwell
2011-08-24 22:47 ` Luiz Augusto von Dentz
2011-08-24 23:58   ` David Stockwell
2011-08-25  7:44     ` Luiz Augusto von Dentz
2011-08-25 12:45       ` David Stockwell
2011-08-25 13:14         ` David Stockwell

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.