2019-05-29 17:17:58 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2016-05-06 17:09:08 +03:00
/*
* Copyright ( c ) 2015 , Sony Mobile Communications Inc .
* Copyright ( c ) 2013 , The Linux Foundation . All rights reserved .
*/
# include <linux/module.h>
# include <linux/skbuff.h>
2017-03-28 08:26:33 +03:00
# include <linux/rpmsg.h>
2016-05-06 17:09:08 +03:00
# include "qrtr.h"
struct qrtr_smd_dev {
struct qrtr_endpoint ep ;
2017-03-28 08:26:33 +03:00
struct rpmsg_endpoint * channel ;
2016-05-14 00:36:11 +03:00
struct device * dev ;
2016-05-06 17:09:08 +03:00
} ;
/* from smd to qrtr */
2017-03-28 08:26:33 +03:00
static int qcom_smd_qrtr_callback ( struct rpmsg_device * rpdev ,
void * data , int len , void * priv , u32 addr )
2016-05-06 17:09:08 +03:00
{
2017-03-28 08:26:33 +03:00
struct qrtr_smd_dev * qdev = dev_get_drvdata ( & rpdev - > dev ) ;
2016-05-06 17:09:08 +03:00
int rc ;
if ( ! qdev )
return - EAGAIN ;
rc = qrtr_endpoint_post ( & qdev - > ep , data , len ) ;
if ( rc = = - EINVAL ) {
2016-05-14 00:36:11 +03:00
dev_err ( qdev - > dev , " invalid ipcrouter packet \n " ) ;
2016-05-06 17:09:08 +03:00
/* return 0 to let smd drop the packet */
rc = 0 ;
}
return rc ;
}
/* from qrtr to smd */
static int qcom_smd_qrtr_send ( struct qrtr_endpoint * ep , struct sk_buff * skb )
{
struct qrtr_smd_dev * qdev = container_of ( ep , struct qrtr_smd_dev , ep ) ;
int rc ;
rc = skb_linearize ( skb ) ;
if ( rc )
goto out ;
2017-03-28 08:26:33 +03:00
rc = rpmsg_send ( qdev - > channel , skb - > data , skb - > len ) ;
2016-05-06 17:09:08 +03:00
out :
if ( rc )
kfree_skb ( skb ) ;
else
consume_skb ( skb ) ;
return rc ;
}
2017-03-28 08:26:33 +03:00
static int qcom_smd_qrtr_probe ( struct rpmsg_device * rpdev )
2016-05-06 17:09:08 +03:00
{
struct qrtr_smd_dev * qdev ;
int rc ;
2017-03-28 08:26:33 +03:00
qdev = devm_kzalloc ( & rpdev - > dev , sizeof ( * qdev ) , GFP_KERNEL ) ;
2016-05-06 17:09:08 +03:00
if ( ! qdev )
return - ENOMEM ;
2017-03-28 08:26:33 +03:00
qdev - > channel = rpdev - > ept ;
qdev - > dev = & rpdev - > dev ;
2016-05-06 17:09:08 +03:00
qdev - > ep . xmit = qcom_smd_qrtr_send ;
rc = qrtr_endpoint_register ( & qdev - > ep , QRTR_EP_NID_AUTO ) ;
if ( rc )
return rc ;
2017-03-28 08:26:33 +03:00
dev_set_drvdata ( & rpdev - > dev , qdev ) ;
2016-05-06 17:09:08 +03:00
2017-03-28 08:26:33 +03:00
dev_dbg ( & rpdev - > dev , " Qualcomm SMD QRTR driver probed \n " ) ;
2016-05-06 17:09:08 +03:00
return 0 ;
}
2017-03-28 08:26:33 +03:00
static void qcom_smd_qrtr_remove ( struct rpmsg_device * rpdev )
2016-05-06 17:09:08 +03:00
{
2017-03-28 08:26:33 +03:00
struct qrtr_smd_dev * qdev = dev_get_drvdata ( & rpdev - > dev ) ;
2016-05-06 17:09:08 +03:00
qrtr_endpoint_unregister ( & qdev - > ep ) ;
2017-03-28 08:26:33 +03:00
dev_set_drvdata ( & rpdev - > dev , NULL ) ;
2016-05-06 17:09:08 +03:00
}
2017-03-28 08:26:33 +03:00
static const struct rpmsg_device_id qcom_smd_qrtr_smd_match [ ] = {
2016-05-06 17:09:08 +03:00
{ " IPCRTR " } ,
{ }
} ;
2017-03-28 08:26:33 +03:00
static struct rpmsg_driver qcom_smd_qrtr_driver = {
2016-05-06 17:09:08 +03:00
. probe = qcom_smd_qrtr_probe ,
. remove = qcom_smd_qrtr_remove ,
. callback = qcom_smd_qrtr_callback ,
2017-03-28 08:26:33 +03:00
. id_table = qcom_smd_qrtr_smd_match ,
. drv = {
2016-05-06 17:09:08 +03:00
. name = " qcom_smd_qrtr " ,
} ,
} ;
2017-03-28 08:26:33 +03:00
module_rpmsg_driver ( qcom_smd_qrtr_driver ) ;
2016-05-06 17:09:08 +03:00
2018-02-25 10:49:37 +03:00
MODULE_ALIAS ( " rpmsg:IPCRTR " ) ;
2016-05-06 17:09:08 +03:00
MODULE_DESCRIPTION ( " Qualcomm IPC-Router SMD interface driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;