[PATCH 3/5] Add Passthrough signal to handle_panel_passthrough

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add Passthrough signal to handle_panel_passthrough,
  rename avrcp->code to avrcp->ctype for consistency,
  correct sense of Key State flag field.

Based on Release 4.96
---
 audio/control.c |  121 
+++++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 99 insertions(+), 22 deletions(-)

diff --git a/audio/control.c b/audio/control.c
index 8ddcc10..472cab2 100644
--- a/audio/control.c
+++ b/audio/control.c
@@ -230,7 +230,7 @@ struct avctp_header {
 #define AVCTP_HEADER_LENGTH 3
 
 struct avrcp_header {
-	uint8_t code:4;
+	uint8_t ctype:4;
 	uint8_t _hdr0:4;
 	uint8_t subunit_id:3;
 	uint8_t subunit_type:5;
@@ -261,7 +261,7 @@ struct avctp_header {
 
 struct avrcp_header {
 	uint8_t _hdr0:4;
-	uint8_t code:4;
+	uint8_t ctype:4;
 	uint8_t subunit_type:5;
 	uint8_t subunit_id:3;
 	uint8_t opcode;
@@ -551,6 +551,23 @@ static sdp_record_t *avrcp_tg_record(void)
 	return record;
 }
 
+/**
+ *	@brief	get_company_id: Three-byte Company_ID from AVRCP message
+ *
+ *	AVRCP uses three-byte company_ids, which must be converted from
+ *	BT/network big-endian order to internal form.
+ */
+static gint32 get_company_id(unsigned char *cid)
+{
+	gint32 company_id = 0;
+	company_id = *cid;
+	company_id <<= 8;
+	company_id |= *(cid+1);
+	company_id <<= 8;
+	company_id |= *(cid+2);
+	return company_id;
+}
+
 static int send_event(int fd, uint16_t type, uint16_t code, int32_t value)
 {
 	struct uinput_event event;
@@ -572,17 +589,74 @@ static void send_key(int fd, uint16_t key, int pressed)
 	send_event(fd, EV_SYN, SYN_REPORT, 0);
 }
 
+/**
+ *	@brief: handle_panel_passthrough: Handles AVRCP 1.0+ PASSTHROUGH command.
+ *
+ *	Original version only passed 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,
-					int operand_count)
+				     struct avrcp_passthru *avrcp,
+				     int avrcp_length)
 {
 	const char *status;
 	int pressed, i;
+	guchar key_pressed;
+	gboolean key_status;
+	gint32 pass_company_id;
+	gchar *pass_string;
 
-	if (operand_count == 0)
+	if ((unsigned int) avrcp_length < sizeof(struct avrcp_passthru) - 5)
 		return;
 
-	if (operands[0] & 0x80) {
+	/*
+	 * Following creates the Passthrough signal.
+	 * Key_state is zero if key is pressed (AVRCP v14r00 sect 22.3, p119)
+	 */
+
+	key_pressed = avrcp->key;
+	key_status = !avrcp->key_state;
+	DBG("Passthrough Key: %x Pressed: %s",
+			key_pressed, key_status ? "true" : "false");
+	if (key_pressed == VENDOR_UNIQUE_OP) {
+		if ((unsigned int) avrcp_length >
+				sizeof(struct avrcp_passthru)) {
+			pass_company_id = get_company_id(avrcp->company_id);
+			pass_string = g_strndup((const char *) avrcp->op_data,
+						(gsize) avrcp->op_len - 3);
+			DBG("Passthrough Company_ID: %06X String: %s",
+			    pass_company_id, pass_string);
+		} else if (avrcp_length == sizeof(struct avrcp_passthru)) {
+			pass_company_id = get_company_id(avrcp->company_id);
+			pass_string = (gchar *) g_malloc0(1);
+			DBG("Passthrough Company_ID: %06X String: <none>",
+			    pass_company_id);
+		} else {
+			pass_company_id = -1;
+			pass_string = (gchar *) g_malloc0(1);
+			DBG("Passthrough: No Company_ID or String!");
+		};
+	} else {
+		pass_company_id = -1;
+		pass_string = (gchar *) g_malloc0(1);
+	};
+
+	g_dbus_emit_signal(control->dev->conn, control->dev->path,
+		AUDIO_CONTROL_INTERFACE, "Passthrough",
+		DBUS_TYPE_BYTE, &key_pressed,
+		DBUS_TYPE_BOOLEAN, &key_status,
+		DBUS_TYPE_INT32, &pass_company_id,
+		DBUS_TYPE_STRING, &pass_string,
+		DBUS_TYPE_INVALID);
+
+	g_free(pass_string);
+
+	/* From here on, we are doing the equivalent of "SendKeys" */
+
+	if (avrcp->key_state) {
 		status = "released";
 		pressed = 0;
 	} else {
@@ -593,7 +667,7 @@ static void handle_panel_passthrough(struct control 
*control,
 	for (i = 0; key_map[i].name != NULL; i++) {
 		uint8_t key_quirks;
 
-		if ((operands[0] & 0x7F) != key_map[i].avrcp)
+		if (avrcp->key != key_map[i].avrcp)
 			continue;
 
 		DBG("AVRCP: %s %s", key_map[i].name, status);
@@ -616,9 +690,12 @@ static void handle_panel_passthrough(struct control 
*control,
 		break;
 	}
 
+	/* Note that the following will flag Vendor Dependent keypresses
+	   and any others not in the key_map.  However, this does not affect
+	   the functionality. */
+
 	if (key_map[i].name == NULL)
-		DBG("AVRCP: unknown button 0x%02X %s",
-						operands[0] & 0x7F, status);
+		DBG("AVRCP: unknown button 0x%02X %s", avrcp->key, status);
 }
 
 /* handle vendordep pdu inside an avctp packet */
@@ -626,7 +703,7 @@ static int handle_vendordep_pdu(struct control *control,
 					struct avrcp_header *avrcp,
 					int operand_count)
 {
-	avrcp->code = CTYPE_NOT_IMPLEMENTED;
+	avrcp->ctype = CTYPE_NOT_IMPLEMENTED;
 	return AVRCP_HEADER_LENGTH;
 }
 
@@ -760,37 +837,36 @@ static gboolean control_cb(GIOChannel *chan, 
GIOCondition cond,
 
 	avrcp = (struct avrcp_header *) (buf + sizeof(struct avctp_header));
 
-	ret -= sizeof(struct avrcp_header);
-
 	operands = buf + sizeof(struct avctp_header) + sizeof(struct 
avrcp_header);
-	operand_count = ret;
+	operand_count = ret - sizeof(struct avrcp_header);
 
 	DBG("AVRCP %s 0x%01X, subunit_type 0x%02X, subunit_id 0x%01X, "
 			"opcode 0x%02X, %d operands",
 			avctp->cr ? "response" : "command",
-			avrcp->code, avrcp->subunit_type, avrcp->subunit_id,
+			avrcp->ctype, avrcp->subunit_type, avrcp->subunit_id,
 			avrcp->opcode, operand_count);
 
 	if (avctp->packet_type != AVCTP_PACKET_SINGLE) {
 		avctp->cr = AVCTP_RESPONSE;
-		avrcp->code = CTYPE_NOT_IMPLEMENTED;
+		avrcp->ctype = CTYPE_NOT_IMPLEMENTED;
 	} else if (avctp->pid != htons(AV_REMOTE_SVCLASS_ID)) {
 		avctp->ipid = 1;
 		avctp->cr = AVCTP_RESPONSE;
 		packet_size = sizeof(*avctp);
 	} else if (avctp->cr == AVCTP_COMMAND &&
-			avrcp->code == CTYPE_CONTROL &&
+			avrcp->ctype == CTYPE_CONTROL &&
 			avrcp->subunit_type == SUBUNIT_PANEL &&
 			avrcp->opcode == OP_PASSTHROUGH) {
-		handle_panel_passthrough(control, operands, operand_count);
+		handle_panel_passthrough(control,
+					 (struct avrcp_passthru *) avrcp, ret);
 		avctp->cr = AVCTP_RESPONSE;
-		avrcp->code = CTYPE_ACCEPTED;
+		avrcp->ctype = CTYPE_ACCEPTED;
 	} else if (avctp->cr == AVCTP_COMMAND &&
-			avrcp->code == CTYPE_STATUS &&
+			avrcp->ctype == CTYPE_STATUS &&
 			(avrcp->opcode == OP_UNITINFO
 			|| avrcp->opcode == OP_SUBUNITINFO)) {
 		avctp->cr = AVCTP_RESPONSE;
-		avrcp->code = CTYPE_STABLE;
+		avrcp->ctype = CTYPE_STABLE;
 		/* The first operand should be 0x07 for the UNITINFO response.
 		 * Neither AVRCP (section 22.1, page 117) nor AVC Digital
 		 * Interface Command Set (section 9.2.1, page 45) specs
@@ -810,7 +886,7 @@ static gboolean control_cb(GIOChannel *chan, GIOCondition 
cond,
 		packet_size = AVCTP_HEADER_LENGTH + r_size;
 	} else {
 		avctp->cr = AVCTP_RESPONSE;
-		avrcp->code = CTYPE_REJECTED;
+		avrcp->ctype = CTYPE_REJECTED;
 	}
 	ret = write(sock, buf, packet_size);
 	if (ret != packet_size)
@@ -1222,7 +1298,7 @@ static int avctp_send_passthrough(struct control 
*control, uint8_t op)
 	avctp->cr = AVCTP_COMMAND;
 	avctp->pid = htons(AV_REMOTE_SVCLASS_ID);
 
-	avrcp->code = CTYPE_CONTROL;
+	avrcp->ctype = CTYPE_CONTROL;
 	avrcp->subunit_type = SUBUNIT_PANEL;
 	avrcp->opcode = OP_PASSTHROUGH;
 
@@ -1324,6 +1400,7 @@ static GDBusSignalTable control_signals[] = {
 	{ "Connected",			"",	G_DBUS_SIGNAL_FLAG_DEPRECATED},
 	{ "Disconnected",		"",	G_DBUS_SIGNAL_FLAG_DEPRECATED},
 	{ "PropertyChanged",		"sv"	},
+	{ "Passthrough",		"ybis"	},
 	{ NULL, NULL }
 };
 
-- 
1.7.4.4

--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux