Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2015, Sony Mobile Communications Inc.
0004  * Copyright (c) 2013, The Linux Foundation. All rights reserved.
0005  */
0006 
0007 #include <linux/module.h>
0008 #include <linux/skbuff.h>
0009 #include <linux/rpmsg.h>
0010 
0011 #include "qrtr.h"
0012 
0013 struct qrtr_smd_dev {
0014     struct qrtr_endpoint ep;
0015     struct rpmsg_endpoint *channel;
0016     struct device *dev;
0017 };
0018 
0019 /* from smd to qrtr */
0020 static int qcom_smd_qrtr_callback(struct rpmsg_device *rpdev,
0021                   void *data, int len, void *priv, u32 addr)
0022 {
0023     struct qrtr_smd_dev *qdev = dev_get_drvdata(&rpdev->dev);
0024     int rc;
0025 
0026     if (!qdev)
0027         return -EAGAIN;
0028 
0029     rc = qrtr_endpoint_post(&qdev->ep, data, len);
0030     if (rc == -EINVAL) {
0031         dev_err(qdev->dev, "invalid ipcrouter packet\n");
0032         /* return 0 to let smd drop the packet */
0033         rc = 0;
0034     }
0035 
0036     return rc;
0037 }
0038 
0039 /* from qrtr to smd */
0040 static int qcom_smd_qrtr_send(struct qrtr_endpoint *ep, struct sk_buff *skb)
0041 {
0042     struct qrtr_smd_dev *qdev = container_of(ep, struct qrtr_smd_dev, ep);
0043     int rc;
0044 
0045     rc = skb_linearize(skb);
0046     if (rc)
0047         goto out;
0048 
0049     rc = rpmsg_send(qdev->channel, skb->data, skb->len);
0050 
0051 out:
0052     if (rc)
0053         kfree_skb(skb);
0054     else
0055         consume_skb(skb);
0056     return rc;
0057 }
0058 
0059 static int qcom_smd_qrtr_probe(struct rpmsg_device *rpdev)
0060 {
0061     struct qrtr_smd_dev *qdev;
0062     int rc;
0063 
0064     qdev = devm_kzalloc(&rpdev->dev, sizeof(*qdev), GFP_KERNEL);
0065     if (!qdev)
0066         return -ENOMEM;
0067 
0068     qdev->channel = rpdev->ept;
0069     qdev->dev = &rpdev->dev;
0070     qdev->ep.xmit = qcom_smd_qrtr_send;
0071 
0072     rc = qrtr_endpoint_register(&qdev->ep, QRTR_EP_NID_AUTO);
0073     if (rc)
0074         return rc;
0075 
0076     dev_set_drvdata(&rpdev->dev, qdev);
0077 
0078     dev_dbg(&rpdev->dev, "Qualcomm SMD QRTR driver probed\n");
0079 
0080     return 0;
0081 }
0082 
0083 static void qcom_smd_qrtr_remove(struct rpmsg_device *rpdev)
0084 {
0085     struct qrtr_smd_dev *qdev = dev_get_drvdata(&rpdev->dev);
0086 
0087     qrtr_endpoint_unregister(&qdev->ep);
0088 
0089     dev_set_drvdata(&rpdev->dev, NULL);
0090 }
0091 
0092 static const struct rpmsg_device_id qcom_smd_qrtr_smd_match[] = {
0093     { "IPCRTR" },
0094     {}
0095 };
0096 
0097 static struct rpmsg_driver qcom_smd_qrtr_driver = {
0098     .probe = qcom_smd_qrtr_probe,
0099     .remove = qcom_smd_qrtr_remove,
0100     .callback = qcom_smd_qrtr_callback,
0101     .id_table = qcom_smd_qrtr_smd_match,
0102     .drv = {
0103         .name = "qcom_smd_qrtr",
0104     },
0105 };
0106 
0107 module_rpmsg_driver(qcom_smd_qrtr_driver);
0108 
0109 MODULE_ALIAS("rpmsg:IPCRTR");
0110 MODULE_DESCRIPTION("Qualcomm IPC-Router SMD interface driver");
0111 MODULE_LICENSE("GPL v2");