[RFC 01/19] avrcp: handle query for company ids

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

 



---
 audio/control.c |   88 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 86 insertions(+), 2 deletions(-)

diff --git a/audio/control.c b/audio/control.c
index c3ef737..983c8cd 100644
--- a/audio/control.c
+++ b/audio/control.c
@@ -102,6 +102,22 @@
 #define FORWARD_OP		0x4b
 #define BACKWARD_OP		0x4c
 
+/* Company IDs for vendor dependent commands */
+#define IEEEID_BTSIG		0x001958
+
+/* Error codes for metadata transfer */
+#define E_INVALID_COMMAND	0x00
+#define E_INVALID_PARAM		0x01
+#define E_PARAM_NOT_FOUND	0x02
+#define E_INTERNAL		0x03
+
+/* PDU types for metadata transfer */
+#define AVRCP_GET_CAPABILITIES		0x10
+
+/* Capabilities for AVRCP_GET_CAPABILITIES pdu */
+#define CAP_COMPANY_ID		0x02
+#define CAP_EVENTS_SUPPORTED	0x03
+
 #define QUIRK_NO_RELEASE	1 << 0
 
 static DBusConnection *connection = NULL;
@@ -217,6 +233,11 @@ static struct {
 	{ NULL }
 };
 
+/* Company IDs supported by this device */
+static uint32_t company_ids[] = {
+	IEEEID_BTSIG,
+};
+
 static GSList *avctp_callbacks = NULL;
 
 static void auth_cb(DBusError *derr, void *user_data);
@@ -424,8 +445,71 @@ static int handle_vendordep_pdu(struct control *control,
 					struct avrcp_header *avrcp,
 					int operand_count)
 {
-	avrcp->code = CTYPE_NOT_IMPLEMENTED;
-	return AVRCP_HEADER_LENGTH;
+	struct avrcp_spec_avc_pdu *pdu = (void *) avrcp + AVRCP_HEADER_LENGTH;
+	uint32_t company_id = (pdu->company_id[0] << 16) |
+				(pdu->company_id[1] << 8) |
+				(pdu->company_id[2]);
+	uint16_t len;
+	unsigned int i;
+
+	if (company_id != IEEEID_BTSIG ||
+				pdu->packet_type != AVCTP_PACKET_SINGLE) {
+		avrcp->code = CTYPE_NOT_IMPLEMENTED;
+		return AVRCP_HEADER_LENGTH;
+	}
+
+	pdu->packet_type = 0;
+	pdu->rsvd = 0;
+
+	if (operand_count + 3 < AVRCP_SPECAVCPDU_HEADER_LENGTH) {
+		pdu->params[0] = E_INVALID_COMMAND;
+		goto err_metadata;
+	}
+
+	len = ntohs(pdu->params_len);
+
+	switch (pdu->pdu_id) {
+	case AVRCP_GET_CAPABILITIES:
+		if (len != 1 || avrcp->code != CTYPE_STATUS)
+			break;
+
+		DBG("GET_CAPABILITIES id=%u", pdu->params[0]);
+
+		switch (pdu->params[0]) { /* capability id */
+		case CAP_COMPANY_ID:
+			avrcp->code = CTYPE_STABLE;
+			pdu->params_len = htons(1 +
+						3 * G_N_ELEMENTS(company_ids));
+			pdu->params[1] = G_N_ELEMENTS(company_ids);
+
+			for (i = 0; i < G_N_ELEMENTS(company_ids); i++) {
+				pdu->params[2 + i * 3] = company_ids[i] >> 16;
+				pdu->params[3 + i * 3] = (company_ids[i] >> 8)
+									& 0xFF;
+				pdu->params[4 + i * 3] = company_ids[i] & 0xFF;
+			}
+
+			return AVRCP_HEADER_LENGTH +
+					AVRCP_SPECAVCPDU_HEADER_LENGTH + 1 +
+					3 * G_N_ELEMENTS(company_ids);
+		}
+
+		pdu->params[0] = E_INVALID_PARAM;
+		goto err_metadata;
+	}
+
+	/*
+	 * If either pdu_id was invalid or message was malformed, respond with
+	 * E_INVALID_COMMAND. For other errors, we already jumped into
+	 * err_metadata.
+	 */
+	pdu->params[0] = E_INVALID_COMMAND;
+
+err_metadata:
+	avrcp->code = CTYPE_REJECTED;
+	pdu->params_len = htons(1);
+
+	return AVRCP_HEADER_LENGTH + AVRCP_SPECAVCPDU_HEADER_LENGTH + 1;
 }
 
 static void avctp_disconnected(struct audio_device *dev)
-- 
1.7.6

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