drivers/soc/qcom/qmi_interface.c

Source file repositories/reference/linux-study-clean/drivers/soc/qcom/qmi_interface.c

File Facts

System
Linux kernel
Corpus path
drivers/soc/qcom/qmi_interface.c
Extension
.c
Size
21591 bytes
Lines
855
Domain
Driver Families
Bucket
drivers/soc
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (!txn) {
			mutex_unlock(&qmi->txn_lock);
			return;
		}

		mutex_lock(&txn->lock);
		mutex_unlock(&qmi->txn_lock);

		if (txn->dest && txn->ei) {
			ret = qmi_decode_message(buf, len, txn->ei, txn->dest);
			if (ret < 0)
				pr_err("failed to decode incoming message\n");

			txn->result = ret;
			complete(&txn->completion);
		} else  {
			qmi_invoke_handler(qmi, sq, txn, buf, len);
		}

		mutex_unlock(&txn->lock);
	} else {
		/* Create a txn based on the txn_id of the incoming message */
		memset(&tmp_txn, 0, sizeof(tmp_txn));
		tmp_txn.id = le16_to_cpu(hdr->txn_id);

		qmi_invoke_handler(qmi, sq, &tmp_txn, buf, len);
	}
}

static void qmi_data_ready_work(struct work_struct *work)
{
	struct qmi_handle *qmi = container_of(work, struct qmi_handle, work);
	struct qmi_ops *ops = &qmi->ops;
	struct sockaddr_qrtr sq;
	struct msghdr msg = { .msg_name = &sq, .msg_namelen = sizeof(sq) };
	struct kvec iv;
	ssize_t msglen;

	for (;;) {
		iv.iov_base = qmi->recv_buf;
		iv.iov_len = qmi->recv_buf_size;

		mutex_lock(&qmi->sock_lock);
		if (qmi->sock)
			msglen = kernel_recvmsg(qmi->sock, &msg, &iv, 1,
						iv.iov_len, MSG_DONTWAIT);
		else
			msglen = -EPIPE;
		mutex_unlock(&qmi->sock_lock);
		if (msglen == -EAGAIN)
			break;

		if (msglen == -ENETRESET) {
			qmi_handle_net_reset(qmi);

			/* The old qmi->sock is gone, our work is done */
			break;
		}

		if (msglen < 0) {
			pr_err("qmi recvmsg failed: %zd\n", msglen);
			break;
		}

		if (sq.sq_node == qmi->sq.sq_node &&
		    sq.sq_port == QRTR_PORT_CTRL) {
			qmi_recv_ctrl_pkt(qmi, qmi->recv_buf, msglen);
		} else if (ops->msg_handler) {
			ops->msg_handler(qmi, &sq, qmi->recv_buf, msglen);
		} else {
			qmi_handle_message(qmi, &sq, qmi->recv_buf, msglen);
		}
	}
}

static void qmi_data_ready(struct sock *sk)
{
	struct qmi_handle *qmi = sk->sk_user_data;

	trace_sk_data_ready(sk);

	/*
	 * This will be NULL if we receive data while being in
	 * qmi_handle_release()
	 */
	if (!qmi)
		return;

	queue_work(qmi->wq, &qmi->work);
}

Annotation

Implementation Notes