diff options
| -rw-r--r-- | Documentation/ioctl/ioctl-number.txt | 1 | ||||
| -rw-r--r-- | drivers/rpmsg/Kconfig | 8 | ||||
| -rw-r--r-- | drivers/rpmsg/Makefile | 1 | ||||
| -rw-r--r-- | drivers/rpmsg/rpmsg_char.c | 585 | ||||
| -rw-r--r-- | drivers/rpmsg/rpmsg_internal.h | 15 | ||||
| -rw-r--r-- | include/uapi/linux/rpmsg.h | 35 |
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 | |||
| 321 | 0xB1 00-1F PPPoX <mailto:mostrows@styx.uwaterloo.ca> | 321 | 0xB1 00-1F PPPoX <mailto:mostrows@styx.uwaterloo.ca> |
| 322 | 0xB3 00 linux/mmc/ioctl.h | 322 | 0xB3 00 linux/mmc/ioctl.h |
| 323 | 0xB4 00-0F linux/gpio.h <mailto:linux-gpio@vger.kernel.org> | 323 | 0xB4 00-0F linux/gpio.h <mailto:linux-gpio@vger.kernel.org> |
| 324 | 0xB5 00-0F uapi/linux/rpmsg.h <mailto:linux-remoteproc@vger.kernel.org> | ||
| 324 | 0xC0 00-0F linux/usb/iowarrior.h | 325 | 0xC0 00-0F linux/usb/iowarrior.h |
| 325 | 0xCA 00-0F uapi/misc/cxl.h | 326 | 0xCA 00-0F uapi/misc/cxl.h |
| 326 | 0xCA 80-8F uapi/scsi/cxlflash_ioctl.h | 327 | 0xCA 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" | |||
| 4 | config RPMSG | 4 | config RPMSG |
| 5 | tristate | 5 | tristate |
| 6 | 6 | ||
| 7 | config 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 | |||
| 7 | config RPMSG_QCOM_SMD | 15 | config 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 @@ | |||
| 1 | obj-$(CONFIG_RPMSG) += rpmsg_core.o | 1 | obj-$(CONFIG_RPMSG) += rpmsg_core.o |
| 2 | obj-$(CONFIG_RPMSG_CHAR) += rpmsg_char.o | ||
| 2 | obj-$(CONFIG_RPMSG_QCOM_SMD) += qcom_smd.o | 3 | obj-$(CONFIG_RPMSG_QCOM_SMD) += qcom_smd.o |
| 3 | obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o | 4 | obj-$(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 | |||
| 37 | static dev_t rpmsg_major; | ||
| 38 | static struct class *rpmsg_class; | ||
| 39 | |||
| 40 | static DEFINE_IDA(rpmsg_ctrl_ida); | ||
| 41 | static DEFINE_IDA(rpmsg_ept_ida); | ||
| 42 | static 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 | */ | ||
| 56 | struct 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 | */ | ||
| 74 | struct 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 | |||
| 89 | static 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 | |||
| 109 | static 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 | |||
| 131 | static 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 | |||
| 153 | static 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); | ||
