aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ioctl/ioctl-number.txt1
-rw-r--r--drivers/rpmsg/Kconfig8
-rw-r--r--drivers/rpmsg/Makefile1
-rw-r--r--drivers/rpmsg/rpmsg_char.c585
-rw-r--r--drivers/rpmsg/rpmsg_internal.h15
-rw-r--r--include/uapi/linux/rpmsg.h35
6 files changed, 645 insertions, 0 deletions
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 81c7f2bb7daf..08244bea5048 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -321,6 +321,7 @@ Code Seq#(hex) Include File Comments
3210xB1 00-1F PPPoX <mailto:mostrows@styx.uwaterloo.ca> 3210xB1 00-1F PPPoX <mailto:mostrows@styx.uwaterloo.ca>
3220xB3 00 linux/mmc/ioctl.h 3220xB3 00 linux/mmc/ioctl.h
3230xB4 00-0F linux/gpio.h <mailto:linux-gpio@vger.kernel.org> 3230xB4 00-0F linux/gpio.h <mailto:linux-gpio@vger.kernel.org>
3240xB5 00-0F uapi/linux/rpmsg.h <mailto:linux-remoteproc@vger.kernel.org>
3240xC0 00-0F linux/usb/iowarrior.h 3250xC0 00-0F linux/usb/iowarrior.h
3250xCA 00-0F uapi/misc/cxl.h 3260xCA 00-0F uapi/misc/cxl.h
3260xCA 80-8F uapi/scsi/cxlflash_ioctl.h 3270xCA 80-8F uapi/scsi/cxlflash_ioctl.h
diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig
index de31c5f14dd9..fa0d582efb3d 100644
--- a/drivers/rpmsg/Kconfig
+++ b/drivers/rpmsg/Kconfig
@@ -4,6 +4,14 @@ menu "Rpmsg drivers"
4config RPMSG 4config RPMSG
5 tristate 5 tristate
6 6
7config RPMSG_CHAR
8 tristate "RPMSG device interface"
9 depends on RPMSG
10 help
11 Say Y here to export rpmsg endpoints as device files, usually found
12 in /dev. They make it possible for user-space programs to send and
13 receive rpmsg packets.
14
7config RPMSG_QCOM_SMD 15config RPMSG_QCOM_SMD
8 tristate "Qualcomm Shared Memory Driver (SMD)" 16 tristate "Qualcomm Shared Memory Driver (SMD)"
9 depends on QCOM_SMEM 17 depends on QCOM_SMEM
diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile
index ae9c9132cf76..fae9a6d548fb 100644
--- a/drivers/rpmsg/Makefile
+++ b/drivers/rpmsg/Makefile
@@ -1,3 +1,4 @@
1obj-$(CONFIG_RPMSG) += rpmsg_core.o 1obj-$(CONFIG_RPMSG) += rpmsg_core.o
2obj-$(CONFIG_RPMSG_CHAR) += rpmsg_char.o
2obj-$(CONFIG_RPMSG_QCOM_SMD) += qcom_smd.o 3obj-$(CONFIG_RPMSG_QCOM_SMD) += qcom_smd.o
3obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o 4obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o
diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
new file mode 100644
index 000000000000..a78b6b79cea4
--- /dev/null
+++ b/drivers/rpmsg/rpmsg_char.c
@@ -0,0 +1,585 @@
1/*
2 * Copyright (c) 2016, Linaro Ltd.
3 * Copyright (c) 2012, Michal Simek <monstr@monstr.eu>
4 * Copyright (c) 2012, PetaLogix
5 * Copyright (c) 2011, Texas Instruments, Inc.
6 * Copyright (c) 2011, Google, Inc.
7 *
8 * Based on rpmsg performance statistics driver by Michal Simek, which in turn
9 * was based on TI & Google OMX rpmsg driver.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 and
13 * only version 2 as published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 */
20#include <linux/cdev.h>
21#include <linux/device.h>
22#include <linux/fs.h>
23#include <linux/idr.h>
24#include <linux/kernel.h>
25#include <linux/module.h>
26#include <linux/poll.h>
27#include <linux/rpmsg.h>
28#include <linux/skbuff.h>
29#include <linux/slab.h>
30#include <linux/uaccess.h>
31#include <uapi/linux/rpmsg.h>
32
33#include "rpmsg_internal.h"
34
35#define RPMSG_DEV_MAX (MINORMASK + 1)
36
37static dev_t rpmsg_major;
38static struct class *rpmsg_class;
39
40static DEFINE_IDA(rpmsg_ctrl_ida);
41static DEFINE_IDA(rpmsg_ept_ida);
42static DEFINE_IDA(rpmsg_minor_ida);
43
44#define dev_to_eptdev(dev) container_of(dev, struct rpmsg_eptdev, dev)
45#define cdev_to_eptdev(i_cdev) container_of(i_cdev, struct rpmsg_eptdev, cdev)
46
47#define dev_to_ctrldev(dev) container_of(dev, struct rpmsg_ctrldev, dev)
48#define cdev_to_ctrldev(i_cdev) container_of(i_cdev, struct rpmsg_ctrldev, cdev)
49
50/**
51 * struct rpmsg_ctrldev - control device for instantiating endpoint devices
52 * @rpdev: underlaying rpmsg device
53 * @cdev: cdev for the ctrl device
54 * @dev: device for the ctrl device
55 */
56struct rpmsg_ctrldev {
57 struct rpmsg_device *rpdev;
58 struct cdev cdev;
59 struct device dev;
60};
61
62/**
63 * struct rpmsg_eptdev - endpoint device context
64 * @dev: endpoint device
65 * @cdev: cdev for the endpoint device
66 * @rpdev: underlaying rpmsg device
67 * @chinfo: info used to open the endpoint
68 * @ept_lock: synchronization of @ept modifications
69 * @ept: rpmsg endpoint reference, when open
70 * @queue_lock: synchronization of @queue operations
71 * @queue: incoming message queue
72 * @readq: wait object for incoming queue
73 */
74struct rpmsg_eptdev {
75 struct device dev;
76 struct cdev cdev;
77
78 struct rpmsg_device *rpdev;
79 struct rpmsg_channel_info chinfo;
80
81 struct mutex ept_lock;
82 struct rpmsg_endpoint *ept;
83
84 spinlock_t queue_lock;
85 struct sk_buff_head queue;
86 wait_queue_head_t readq;
87};
88
89static int rpmsg_eptdev_destroy(struct device *dev, void *data)
90{
91 struct rpmsg_eptdev *eptdev = dev_to_eptdev(dev);
92
93 mutex_lock(&eptdev->ept_lock);
94 if (eptdev->ept) {
95 rpmsg_destroy_ept(eptdev->ept);
96 eptdev->ept = NULL;
97 }
98 mutex_unlock(&eptdev->ept_lock);
99
100 /* wake up any blocked readers */
101 wake_up_interruptible(&eptdev->readq);
102
103 device_del(&eptdev->dev);
104 put_device(&eptdev->dev);
105
106 return 0;
107}
108
109static int rpmsg_ept_cb(struct rpmsg_device *rpdev, void *buf, int len,
110 void *priv, u32 addr)
111{
112 struct rpmsg_eptdev *eptdev = priv;
113 struct sk_buff *skb;
114
115 skb = alloc_skb(len, GFP_ATOMIC);
116 if (!skb)
117 return -ENOMEM;
118
119 memcpy(skb_put(skb, len), buf, len);
120
121 spin_lock(&eptdev->queue_lock);
122 skb_queue_tail(&eptdev->queue, skb);
123 spin_unlock(&eptdev->queue_lock);
124
125 /* wake up any blocking processes, waiting for new data */
126 wake_up_interruptible(&eptdev->readq);
127
128 return 0;
129}
130
131static int rpmsg_eptdev_open(struct inode *inode, struct file *filp)
132{
133 struct rpmsg_eptdev *eptdev = cdev_to_eptdev(inode->i_cdev);
134 struct rpmsg_endpoint *ept;
135 struct rpmsg_device *rpdev = eptdev->rpdev;
136 struct device *dev = &eptdev->dev;
137
138 get_device(dev);
139
140 ept = rpmsg_create_ept(rpdev, rpmsg_ept_cb, eptdev, eptdev->chinfo);
141 if (!ept) {
142 dev_err(dev, "failed to open %s\n", eptdev->chinfo.name);
143 put_device(dev);
144 return -EINVAL;
145 }
146
147 eptdev->ept = ept;
148 filp->private_data = eptdev;
149
150 return 0;
151}
152
153static int rpmsg_eptdev_release(struct inode *inode, struct file *filp)
154{
155 struct rpmsg_eptdev *eptdev = cdev_to_eptdev(inode->i_cdev);
156 struct device *dev = &eptdev->dev;
157 struct sk_buff *skb;
158
159 /* Close the endpoint, if it's not already destroyed by the parent */
160 mutex_lock(&eptdev->ept_lock);
161 if (eptdev->ept) {
162 rpmsg_destroy_ept(eptdev->ept);
163 eptdev->ept = NULL;
164 }
165 mutex_unlock(&eptdev->ept_lock);
166
167 /* Discard all SKBs */
168 while (!skb_queue_empty(&eptdev->queue)) {
169 skb = skb_dequeue(&eptdev->queue);