aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSudeep Holla <sudeep.holla@arm.com>2016-11-29 09:37:04 -0500
committerJassi Brar <jaswinder.singh@linaro.org>2016-12-19 09:40:23 -0500
commitbaef9a35d24626ebdc5a9074455e63eea6c7f6af (patch)
tree76e12c0aa8aa623afdee0cc74d78c4696489edb5
parentcf17581340d730175f1f3f4ce6e90ae434154e37 (diff)
mailbox: mailbox-test: add support for fasync/poll
Currently the read operation on the message debug file returns error if there's no data ready to be read. It expects the userspace to retry if it fails. Since the mailbox response could be asynchronous, it would be good to add support to block the read until the data is available. We can also implement poll file operations so that the userspace can wait to become ready to perform any I/O. This patch implements the poll and fasync file operation callback for the test mailbox device. Cc: Lee Jones <lee.jones@linaro.org> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com> Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
-rw-r--r--drivers/mailbox/mailbox-test.c79
1 files changed, 71 insertions, 8 deletions
diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c
index deb9c61aebb4..383a8b7600ac 100644
--- a/drivers/mailbox/mailbox-test.c
+++ b/drivers/mailbox/mailbox-test.c
@@ -11,12 +11,14 @@
11 11
12#include <linux/debugfs.h> 12#include <linux/debugfs.h>
13#include <linux/err.h> 13#include <linux/err.h>
14#include <linux/fs.h>
14#include <linux/io.h> 15#include <linux/io.h>
15#include <linux/kernel.h> 16#include <linux/kernel.h>
16#include <linux/mailbox_client.h> 17#include <linux/mailbox_client.h>
17#include <linux/module.h> 18#include <linux/module.h>
18#include <linux/of.h> 19#include <linux/of.h>
19#include <linux/platform_device.h> 20#include <linux/platform_device.h>
21#include <linux/poll.h>
20#include <linux/slab.h> 22#include <linux/slab.h>
21#include <linux/uaccess.h> 23#include <linux/uaccess.h>
22 24
@@ -39,6 +41,8 @@ struct mbox_test_device {
39 char *signal; 41 char *signal;
40 char *message; 42 char *message;
41 spinlock_t lock; 43 spinlock_t lock;
44 wait_queue_head_t waitq;
45 struct fasync_struct *async_queue;
42}; 46};
43 47
44static ssize_t mbox_test_signal_write(struct file *filp, 48static ssize_t mbox_test_signal_write(struct file *filp,
@@ -81,6 +85,13 @@ static const struct file_operations mbox_test_signal_ops = {
81 .llseek = generic_file_llseek, 85 .llseek = generic_file_llseek,
82}; 86};
83 87
88static int mbox_test_message_fasync(int fd, struct file *filp, int on)
89{
90 struct mbox_test_device *tdev = filp->private_data;
91
92 return fasync_helper(fd, filp, on, &tdev->async_queue);
93}
94
84static ssize_t mbox_test_message_write(struct file *filp, 95static ssize_t mbox_test_message_write(struct file *filp,
85 const char __user *userbuf, 96 const char __user *userbuf,
86 size_t count, loff_t *ppos) 97 size_t count, loff_t *ppos)
@@ -138,6 +149,20 @@ out:
138 return ret < 0 ? ret : count; 149 return ret < 0 ? ret : count;
139} 150}
140 151
152static bool mbox_test_message_data_ready(struct mbox_test_device *tdev)
153{
154 unsigned char data;
155 unsigned long flags;
156
157 spin_lock_irqsave(&tdev->lock, flags);
158 data = tdev->rx_buffer[0];
159 spin_unlock_irqrestore(&tdev->lock, flags);
160
161 if (data != '\0')
162 return true;
163 return false;
164}
165
141static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf, 166static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf,
142 size_t count, loff_t *ppos) 167 size_t count, loff_t *ppos)
143{ 168{
@@ -147,6 +172,8 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf,
147 int l = 0; 172 int l = 0;
148 int ret; 173 int ret;
149 174
175 DECLARE_WAITQUEUE(wait, current);
176
150 touser = kzalloc(MBOX_HEXDUMP_MAX_LEN + 1, GFP_KERNEL); 177 touser = kzalloc(MBOX_HEXDUMP_MAX_LEN + 1, GFP_KERNEL);
151 if (!touser) 178 if (!touser)
152 return -ENOMEM; 179 return -ENOMEM;
@@ -155,15 +182,29 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf,
155 ret = snprintf(touser, 20, "<NO RX CAPABILITY>\n"); 182 ret = snprintf(touser, 20, "<NO RX CAPABILITY>\n");
156 ret = simple_read_from_buffer(userbuf, count, ppos, 183 ret = simple_read_from_buffer(userbuf, count, ppos,
157 touser, ret); 184 touser, ret);
158 goto out; 185 goto kfree_err;
159 } 186 }
160 187
161 if (tdev->rx_buffer[0] == '\0') { 188 add_wait_queue(&tdev->waitq, &wait);
162 ret = snprintf(touser, 9, "<EMPTY>\n"); 189
163 ret = simple_read_from_buffer(userbuf, count, ppos, 190 do {
164 touser, ret); 191 __set_current_state(TASK_INTERRUPTIBLE);
165 goto out; 192
166 } 193 if (mbox_test_message_data_ready(tdev))
194 break;
195
196 if (filp->f_flags & O_NONBLOCK) {
197 ret = -EAGAIN;
198 goto waitq_err;
199 }
200
201 if (signal_pending(current)) {
202 ret = -ERESTARTSYS;
203 goto waitq_err;
204 }
205 schedule();
206
207 } while (1);
167 208
168 spin_lock_irqsave(&tdev->lock, flags); 209 spin_lock_irqsave(&tdev->lock, flags);
169 210
@@ -185,14 +226,31 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf,
185 spin_unlock_irqrestore(&tdev->lock, flags); 226 spin_unlock_irqrestore(&tdev->lock, flags);
186 227
187 ret = simple_read_from_buffer(userbuf, count, ppos, touser, MBOX_HEXDUMP_MAX_LEN); 228 ret = simple_read_from_buffer(userbuf, count, ppos, touser, MBOX_HEXDUMP_MAX_LEN);
188out: 229waitq_err:
230 __set_current_state(TASK_RUNNING);
231 remove_wait_queue(&tdev->waitq, &wait);
232kfree_err:
189 kfree(touser); 233 kfree(touser);
190 return ret; 234 return ret;
191} 235}
192 236
237static unsigned int
238mbox_test_message_poll(struct file *filp, struct poll_table_struct *wait)
239{
240 struct mbox_test_device *tdev = filp->private_data;
241
242 poll_wait(filp, &tdev->waitq, wait);
243
244 if (mbox_test_message_data_ready(tdev))
245 return POLLIN | POLLRDNORM;
246 return 0;
247}
248
193static const struct file_operations mbox_test_message_ops = { 249static const struct file_operations mbox_test_message_ops = {
194 .write = mbox_test_message_write, 250 .write = mbox_test_message_write,
195 .read = mbox_test_message_read, 251 .read = mbox_test_message_read,
252 .fasync = mbox_test_message_fasync,
253 .poll = mbox_test_message_poll,
196 .open = simple_open, 254 .open = simple_open,
197 .llseek = generic_file_llseek, 255 .llseek = generic_file_llseek,
198}; 256};
@@ -234,6 +292,10 @@ static void mbox_test_receive_message(struct mbox_client *client, void *message)
234 memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN); 292 memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN);
235 } 293 }
236 spin_unlock_irqrestore(&tdev->lock, flags); 294 spin_unlock_irqrestore(&tdev->lock, flags);
295
296 wake_up_interruptible(&tdev->waitq);
297
298 kill_fasync(&tdev->async_queue, SIGIO, POLL_IN);
237} 299}
238 300
239static void mbox_test_prepare_message(struct mbox_client *client, void *message) 301static void mbox_test_prepare_message(struct mbox_client *client, void *message)
@@ -334,6 +396,7 @@ static int mbox_test_probe(struct platform_device *pdev)
334 if (ret) 396 if (ret)
335 return ret; 397 return ret;
336 398
399 init_waitqueue_head(&tdev->waitq);
337 dev_info(&pdev->dev, "Successfully registered\n"); 400 dev_info(&pdev->dev, "Successfully registered\n");
338 401
339 return 0; 402 return 0;