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;
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);
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,