Skip to content

Commit

Permalink
[media] siano: add support for .poll on debugfs
Browse files Browse the repository at this point in the history
Implement poll() method for debugfs and be sure that the
debug_data won't be freed on ir or on read().
With this change, poll() will return POLLIN if either data was
filled or if data was read. That allows read() to return 0
to indicate EOF in the latter case.
As poll() is now provided, fix support for non-block mode.

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
  • Loading branch information
Mauro Carvalho Chehab committed Mar 21, 2013
1 parent 773adad commit 6a28bd9
Showing 1 changed file with 59 additions and 18 deletions.
77 changes: 59 additions & 18 deletions drivers/media/common/siano/smsdvb-debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,14 @@ static int smsdvb_stats_open(struct inode *inode, struct file *file)
return 0;
}

static void smsdvb_debugfs_data_release(struct kref *ref)
{
struct smsdvb_debugfs *debug_data;

debug_data = container_of(ref, struct smsdvb_debugfs, refcount);
kfree(debug_data);
}

static int smsdvb_stats_wait_read(struct smsdvb_debugfs *debug_data)
{
int rc = 1;
Expand All @@ -368,41 +376,73 @@ static int smsdvb_stats_wait_read(struct smsdvb_debugfs *debug_data)
return rc;
}

static ssize_t smsdvb_stats_read(struct file *file, char __user *user_buf,
size_t nbytes, loff_t *ppos)
static unsigned int smsdvb_stats_poll(struct file *file, poll_table *wait)
{
int rc = 0;
struct smsdvb_debugfs *debug_data = file->private_data;
int rc;

rc = wait_event_interruptible(debug_data->stats_queue,
smsdvb_stats_wait_read(debug_data));
if (rc < 0)
return rc;
kref_get(&debug_data->refcount);

rc = simple_read_from_buffer(user_buf, nbytes, ppos,
debug_data->stats_data,
debug_data->stats_count);
spin_lock(&debug_data->lock);
debug_data->stats_was_read = true;
spin_unlock(&debug_data->lock);
poll_wait(file, &debug_data->stats_queue, wait);

rc = smsdvb_stats_wait_read(debug_data);
if (rc > 0)
rc = POLLIN | POLLRDNORM;

kref_put(&debug_data->refcount, smsdvb_debugfs_data_release);

return rc;
}

static void smsdvb_debugfs_data_release(struct kref *ref)
static ssize_t smsdvb_stats_read(struct file *file, char __user *user_buf,
size_t nbytes, loff_t *ppos)
{
struct smsdvb_debugfs *debug_data;
int rc = 0, len;
struct smsdvb_debugfs *debug_data = file->private_data;

debug_data = container_of(ref, struct smsdvb_debugfs, refcount);
kfree(debug_data);
kref_get(&debug_data->refcount);

if (file->f_flags & O_NONBLOCK) {
rc = smsdvb_stats_wait_read(debug_data);
if (!rc) {
rc = -EWOULDBLOCK;
goto ret;
}
} else {
rc = wait_event_interruptible(debug_data->stats_queue,
smsdvb_stats_wait_read(debug_data));
if (rc < 0)
goto ret;
}

if (debug_data->stats_was_read) {
rc = 0; /* EOF */
goto ret;
}

len = debug_data->stats_count - *ppos;
if (len >= 0)
rc = simple_read_from_buffer(user_buf, nbytes, ppos,
debug_data->stats_data, len);
else
rc = 0;

if (*ppos >= debug_data->stats_count) {
spin_lock(&debug_data->lock);
debug_data->stats_was_read = true;
spin_unlock(&debug_data->lock);
}
ret:
kref_put(&debug_data->refcount, smsdvb_debugfs_data_release);
return rc;
}

static int smsdvb_stats_release(struct inode *inode, struct file *file)
{
struct smsdvb_debugfs *debug_data = file->private_data;

spin_lock(&debug_data->lock);
debug_data->stats_was_read = true;
debug_data->stats_was_read = true; /* return EOF to read() */
spin_unlock(&debug_data->lock);
wake_up_interruptible_sync(&debug_data->stats_queue);

Expand All @@ -414,6 +454,7 @@ static int smsdvb_stats_release(struct inode *inode, struct file *file)

static const struct file_operations debugfs_stats_ops = {
.open = smsdvb_stats_open,
.poll = smsdvb_stats_poll,
.read = smsdvb_stats_read,
.release = smsdvb_stats_release,
.llseek = generic_file_llseek,
Expand Down

0 comments on commit 6a28bd9

Please sign in to comment.