[PATCH BlueZ 5/5] android/avctp: Make avctp_send_vendor_req to take struct iovec

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

 



From: Luiz Augusto von Dentz <luiz.von.dentz@xxxxxxxxx>

This makes it possible to pass data without copying.
---
 android/avctp.c     | 155 +++++++++++++++++++++++++++++++---------------------
 android/avctp.h     |   7 +--
 android/avrcp-lib.c |  39 ++++++-------
 unit/test-avctp.c   |   2 +-
 4 files changed, 115 insertions(+), 88 deletions(-)

diff --git a/android/avctp.c b/android/avctp.c
index f49b3c3..36eaf73 100644
--- a/android/avctp.c
+++ b/android/avctp.c
@@ -115,8 +115,8 @@ struct avctp_control_req {
 	uint8_t code;
 	uint8_t subunit;
 	uint8_t op;
-	uint8_t *operands;
-	uint16_t operand_count;
+	struct iovec *iov;
+	int iov_cnt;
 	avctp_rsp_cb func;
 	void *user_data;
 };
@@ -508,41 +508,53 @@ static void avctp_channel_destroy(struct avctp_channel *chan)
 static int avctp_send(struct avctp_channel *control, uint8_t transaction,
 				uint8_t cr, uint8_t code,
 				uint8_t subunit, uint8_t opcode,
-				uint8_t *operands, size_t operand_count)
+				const struct iovec *iov, int iov_cnt)
 {
-	struct avctp_header *avctp;
-	struct avc_header *avc;
+	struct avctp_header avctp;
+	struct avc_header avc;
 	struct msghdr msg;
-	struct iovec iov[2];
 	int sk, err = 0;
+	struct iovec pdu[iov_cnt + 2];
+	int i;
+	size_t len = sizeof(avctp) + sizeof(avc);
+
+	DBG("");
+
+	pdu[0].iov_base = (void *) &avctp;
+	pdu[0].iov_len  = sizeof(avctp);
+	pdu[1].iov_base = (void *) &avc;
+	pdu[1].iov_len  = sizeof(avc);
+
+	for (i = 0; i < iov_cnt; i++) {
+		pdu[i + 2].iov_base = iov[i].iov_base;
+		pdu[i + 2].iov_len  = iov[i].iov_len;
+		len += iov[i].iov_len;
+	}
 
-	iov[0].iov_base = control->buffer;
-	iov[0].iov_len  = sizeof(*avctp) + sizeof(*avc);
-	iov[1].iov_base = operands;
-	iov[1].iov_len  = operand_count;
+	pdu[0].iov_base = (void *) &avctp;
+	pdu[0].iov_len  = sizeof(avctp);
 
-	if (control->omtu < (iov[0].iov_len + iov[1].iov_len))
+	if (control->omtu < len)
 		return -EOVERFLOW;
 
 	sk = g_io_channel_unix_get_fd(control->io);
 
-	memset(control->buffer, 0, iov[0].iov_len);
+	memset(&avctp, 0, sizeof(avctp));
 
-	avctp = (void *) control->buffer;
-	avc = (void *) avctp + sizeof(*avctp);
+	avctp.transaction = transaction;
+	avctp.packet_type = AVCTP_PACKET_SINGLE;
+	avctp.cr = cr;
+	avctp.pid = htons(AV_REMOTE_SVCLASS_ID);
 
-	avctp->transaction = transaction;
-	avctp->packet_type = AVCTP_PACKET_SINGLE;
-	avctp->cr = cr;
-	avctp->pid = htons(AV_REMOTE_SVCLASS_ID);
+	memset(&avc, 0, sizeof(avc));
 
-	avc->code = code;
-	avc->subunit_type = subunit;
-	avc->opcode = opcode;
+	avc.code = code;
+	avc.subunit_type = subunit;
+	avc.opcode = opcode;
 
 	memset(&msg, 0, sizeof(msg));
-	msg.msg_iov = iov;
-	msg.msg_iovlen = 2;
+	msg.msg_iov = pdu;
+	msg.msg_iovlen = iov_cnt + 2;
 
 	if (sendmsg(sk, &msg, 0) < 0)
 		err = -errno;
@@ -597,6 +609,7 @@ static void control_req_destroy(void *data)
 	struct avctp_control_req *req = data;
 	struct avctp_pending_req *p = req->p;
 	struct avctp *session = p->chan->session;
+	int i;
 
 	if (p->err == 0 || req->func == NULL)
 		goto done;
@@ -605,7 +618,10 @@ static void control_req_destroy(void *data)
 							req->user_data);
 
 done:
-	g_free(req->operands);
+	for (i = 0; i < req->iov_cnt; i++)
+		g_free(req->iov[i].iov_base);
+
+	g_free(req->iov);
 	g_free(req);
 }
 
@@ -654,8 +670,7 @@ static int process_control(void *data)
 	struct avctp_pending_req *p = req->p;
 
 	return avctp_send(p->chan, p->transaction, AVCTP_COMMAND, req->code,
-					req->subunit, req->op,
-					req->operands, req->operand_count);
+				req->subunit, req->op, req->iov, req->iov_cnt);
 }
 
 static int process_browsing(void *data)
@@ -1099,25 +1114,33 @@ done:
 	return p;
 }
 
-static int avctp_send_req(struct avctp *session, uint8_t code,
-				uint8_t subunit, uint8_t opcode,
-				uint8_t *operands, size_t operand_count,
-				avctp_rsp_cb func, void *user_data)
+static int avctp_send_req(struct avctp *session, uint8_t code, uint8_t subunit,
+			uint8_t opcode, const struct iovec *iov, int iov_cnt,
+			avctp_rsp_cb func, void *user_data)
 {
 	struct avctp_channel *control = session->control;
 	struct avctp_pending_req *p;
 	struct avctp_control_req *req;
+	struct iovec *pdu;
+	int i;
 
 	if (control == NULL)
 		return -ENOTCONN;
 
+	pdu = g_new0(struct iovec, iov_cnt);
+
+	for (i = 0; i < iov_cnt; i++) {
+		pdu[i].iov_len = iov[i].iov_len;
+		pdu[i].iov_base = g_memdup(iov[i].iov_base, iov[i].iov_len);
+	}
+
 	req = g_new0(struct avctp_control_req, 1);
 	req->code = code;
 	req->subunit = subunit;
 	req->op = opcode;
 	req->func = func;
-	req->operands = g_memdup(operands, operand_count);
-	req->operand_count = operand_count;
+	req->iov = pdu;
+	req->iov_cnt = iov_cnt;
 	req->user_data = user_data;
 
 	p = pending_create(control, process_control, req, control_req_destroy);
@@ -1190,53 +1213,61 @@ static const char *op2str(uint8_t op)
 static int avctp_passthrough_press(struct avctp *session, uint8_t op,
 					uint8_t *params, size_t params_len)
 {
-	uint8_t operands[7];
-	size_t len;
+	struct iovec iov[2];
+	int iov_cnt;
+	uint8_t operands[2];
+
+	DBG("%s", op2str(op));
 
-	DBG("op 0x%02x %s params_len %zd", op, op2str(op), params_len);
+	iov[0].iov_base = (void *) operands;
+	iov[0].iov_len = sizeof(operands);
 
 	/* Button pressed */
 	operands[0] = op & 0x7f;
 
-	if (op == AVC_VENDOR_UNIQUE && params &&
-				params_len == 5) {
-		memcpy(&operands[2], params, params_len);
-		len = params_len + 2;
+	if (params_len > 0) {
+		iov[1].iov_base = params;
+		iov[1].iov_len = params_len;
+		iov_cnt = 2;
 		operands[1] = params_len;
 	} else {
-		len = 2;
+		iov_cnt = 1;
 		operands[1] = 0;
 	}
 
 	return avctp_send_req(session, AVC_CTYPE_CONTROL,
 				AVC_SUBUNIT_PANEL, AVC_OP_PASSTHROUGH,
-				operands, len,
-				avctp_passthrough_rsp, NULL);
+				iov, iov_cnt, avctp_passthrough_rsp, NULL);
 }
 
 static int avctp_passthrough_release(struct avctp *session, uint8_t op,
 					uint8_t *params, size_t params_len)
 {
-	uint8_t operands[7];
-	size_t len;
+	struct iovec iov[2];
+	int iov_cnt;
+	uint8_t operands[2];
 
 	DBG("%s", op2str(op));
 
+	iov[0].iov_base = (void *) operands;
+	iov[0].iov_len = sizeof(operands);
+
 	/* Button released */
 	operands[0] = op | 0x80;
-	operands[1] = 0;
 
-	if (op == AVC_VENDOR_UNIQUE && params &&
-				params_len > sizeof(operands) - 2) {
-		memcpy(&operands[2], params, params_len);
-		len = params_len;
-	} else
-		len = 2;
+	if (params_len > 0) {
+		iov[1].iov_base = params;
+		iov[1].iov_len = params_len;
+		iov_cnt = 2;
+		operands[1] = params_len;
+	} else {
+		iov_cnt = 1;
+		operands[1] = 0;
+	}
 
 	return avctp_send_req(session, AVC_CTYPE_CONTROL,
 				AVC_SUBUNIT_PANEL, AVC_OP_PASSTHROUGH,
-				operands, len,
-				NULL, NULL);
+				iov, iov_cnt, NULL, NULL);
 }
 
 static gboolean repeat_timeout(gpointer user_data)
@@ -1322,27 +1353,29 @@ int avctp_send_passthrough(struct avctp *session, uint8_t op, uint8_t *params,
 	return avctp_passthrough_press(session, op, params, params_len);
 }
 
-int avctp_send_vendordep(struct avctp *session, uint8_t transaction,
+int avctp_send_vendor(struct avctp *session, uint8_t transaction,
 				uint8_t code, uint8_t subunit,
 				uint8_t *operands, size_t operand_count)
 {
 	struct avctp_channel *control = session->control;
+	struct iovec iov;
 
 	if (control == NULL)
 		return -ENOTCONN;
 
+	iov.iov_base = (void *) operands;
+	iov.iov_len = operand_count;
+
 	return avctp_send(control, transaction, AVCTP_RESPONSE, code, subunit,
-					AVC_OP_VENDORDEP, operands, operand_count);
+						AVC_OP_VENDORDEP, &iov, 1);
 }
 
-int avctp_send_vendordep_req(struct avctp *session, uint8_t code,
-					uint8_t subunit, uint8_t *operands,
-					size_t operand_count,
+int avctp_send_vendor_req(struct avctp *session, uint8_t code, uint8_t subunit,
+					const struct iovec *iov, int iov_cnt,
 					avctp_rsp_cb func, void *user_data)
 {
-	return avctp_send_req(session, code, subunit, AVC_OP_VENDORDEP,
-						operands, operand_count,
-						func, user_data);
+	return avctp_send_req(session, code, subunit, AVC_OP_VENDORDEP, iov,
+						iov_cnt, func, user_data);
 }
 
 unsigned int avctp_register_passthrough_handler(struct avctp *session,
diff --git a/android/avctp.h b/android/avctp.h
index 6e6bfad..1b15398 100644
--- a/android/avctp.h
+++ b/android/avctp.h
@@ -166,12 +166,11 @@ bool avctp_unregister_browsing_pdu_handler(struct avctp *session,
 
 int avctp_send_passthrough(struct avctp *session, uint8_t op, uint8_t *params,
 							size_t params_len);
-int avctp_send_vendordep(struct avctp *session, uint8_t transaction,
+int avctp_send_vendor(struct avctp *session, uint8_t transaction,
 				uint8_t code, uint8_t subunit,
 				uint8_t *operands, size_t operand_count);
-int avctp_send_vendordep_req(struct avctp *session, uint8_t code,
-					uint8_t subunit, uint8_t *operands,
-					size_t operand_count,
+int avctp_send_vendor_req(struct avctp *session, uint8_t code, uint8_t subunit,
+					const struct iovec *iov, int iov_cnt,
 					avctp_rsp_cb func, void *user_data);
 int avctp_send_browsing_req(struct avctp *session,
 				const struct iovec *iov, int iov_cnt,
diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index 3b9735f..26d2031 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -724,7 +724,7 @@ int avrcp_send(struct avrcp *session, uint8_t transaction, uint8_t code,
 		pdu->params_len = htons(params_len);
 	}
 
-	return avctp_send_vendordep(session->conn, transaction, code, subunit,
+	return avctp_send_vendor(session->conn, transaction, code, subunit,
 							session->tx_buf, len);
 }
 
@@ -771,35 +771,28 @@ static int avrcp_send_req(struct avrcp *session, uint8_t code, uint8_t subunit,
 					int iov_cnt, avctp_rsp_cb func,
 					void *user_data)
 {
-	struct avrcp_header *pdu = (void *) session->tx_buf;
-	size_t len = sizeof(*pdu);
+	struct iovec pdu[iov_cnt + 1];
+	struct avrcp_header hdr;
 	int i;
 
-	memset(pdu, 0, len);
-
-	hton24(pdu->company_id, IEEEID_BTSIG);
-	pdu->pdu_id = pdu_id;
-	pdu->packet_type = AVRCP_PACKET_TYPE_SINGLE;
+	memset(&hdr, 0, sizeof(hdr));
 
-	if (iov_cnt <= 0)
-		goto done;
+	pdu[0].iov_base = (void *) &hdr;
+	pdu[0].iov_len = sizeof(hdr);
 
 	for (i = 0; i < iov_cnt; i++) {
-		len += iov[i].iov_len;
-
-		if (len > session->tx_mtu)
-			return -ENOBUFS;
-
-		memcpy(&pdu->params[pdu->params_len], iov[i].iov_base,
-							iov[i].iov_len);
-		pdu->params_len += iov[i].iov_len;
+		pdu[i + 1].iov_base = iov[i].iov_base;
+		pdu[i + 1].iov_len = iov[i].iov_len;
+		hdr.params_len += iov[i].iov_len;
 	}
 
-	pdu->params_len = htons(pdu->params_len);
+	hton24(hdr.company_id, IEEEID_BTSIG);
+	hdr.pdu_id = pdu_id;
+	hdr.packet_type = AVRCP_PACKET_TYPE_SINGLE;
+	hdr.params_len = htons(hdr.params_len);
 
-done:
-	return avctp_send_vendordep_req(session->conn, code, subunit,
-					session->tx_buf, len, func, user_data);
+	return avctp_send_vendor_req(session->conn, code, subunit, pdu,
+						iov_cnt + 1, func, user_data);
 }
 
 static int avrcp_send_browsing_req(struct avrcp *session, uint8_t pdu_id,
@@ -2231,6 +2224,8 @@ int avrcp_send_passthrough(struct avrcp *session, uint32_t vendor, uint8_t op)
 {
 	uint8_t params[5];
 
+	DBG("vendor %u op %u", vendor, op);
+
 	if (!vendor)
 		return avctp_send_passthrough(session->conn, op, NULL, 0);
 
diff --git a/unit/test-avctp.c b/unit/test-avctp.c
index 0759731..8f7d5ad 100644
--- a/unit/test-avctp.c
+++ b/unit/test-avctp.c
@@ -264,7 +264,7 @@ static void test_client(gconstpointer data)
 {
 	struct context *context = create_context(0x0100, data);
 
-	avctp_send_vendordep_req(context->session, AVC_CTYPE_CONTROL, 0, NULL,
+	avctp_send_vendor_req(context->session, AVC_CTYPE_CONTROL, 0, NULL,
 						0, handler_response, context);
 
 	execute_context(context);
-- 
1.9.0

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