@@ -320,8 +321,11 @@ static ssize_t serio_raw_write(struct file *file, const char __user *buffer,
{
struct serio_raw_client *client = file->private_data;
struct serio_raw *serio_raw = client->serio_raw;
+ struct queue *queue = serio_raw->debug_user_opened ?
+ &serio_raw->debug_user : NULL;
- return serio_raw_write_mainloop(serio_raw, buffer, count, true, NULL);
+ return serio_raw_write_mainloop(serio_raw, buffer, count,
+ !serio_raw->replay, queue);
}
static unsigned int serio_raw_poll(struct file *file, poll_table *wait)@@ -349,10 +353,144 @@ static const struct file_operations serio_raw_fops = {
* Interface with debugfs (file operations) *
*********************************************************************/
+static int debug_user_open(struct inode *inode, struct file *file)
+{
+ struct serio_raw *serio_raw = inode->i_private;
+
+ file->private_data = serio_raw;
+ queue_clear(&serio_raw->debug_user);
+ serio_raw->debug_user_opened = true;
+ kref_get(&serio_raw->kref);
+
+ return 0;
+}
+
+static int debug_device_open(struct inode *inode, struct file *file)
+{
+ struct serio_raw *serio_raw = inode->i_private;
+
+ file->private_data = serio_raw;
+ queue_clear(&serio_raw->debug_device);
+ serio_raw->debug_device_opened = true;
+ kref_get(&serio_raw->kref);
+
+ return 0;
+}
+
+static int debug_user_release(struct inode *inode, struct file *file)
+{
+ struct serio_raw *serio_raw = file->private_data;
+
+ file->private_data = NULL;
+ serio_raw->debug_user_opened = false;
+ kref_put(&serio_raw->kref, serio_raw_free);
+
+ return 0;
+}
+
+static int debug_device_release(struct inode *inode, struct file *file)
+{
+ struct serio_raw *serio_raw = file->private_data;
+
+ file->private_data = NULL;
+ serio_raw->debug_device_opened = false;
+ kref_put(&serio_raw->kref, serio_raw_free);
+
+ return 0;
+}
+
+static ssize_t debug_user_read(struct file *file,
+ char __user *buffer, size_t count, loff_t *ppos)
+{
+ struct serio_raw *serio_raw = file->private_data;
+ struct queue *queue = &serio_raw->debug_user;
+
+ return queue_read(queue, buffer, count,
+ &serio_raw->dead, file->f_flags & O_NONBLOCK,
+ queue_fetch_byte);
+}
+
+static ssize_t debug_device_read(struct file *file,
+ char __user *buffer, size_t count, loff_t *ppos)
+{
+ struct serio_raw *serio_raw = file->private_data;
+ struct queue *queue = &serio_raw->debug_device;
+
+ return queue_read(queue, buffer, count,
+ &serio_raw->dead, file->f_flags & O_NONBLOCK,
+ queue_fetch_byte);
+}
+
+static ssize_t debug_user_write(struct file *file,
+ const char __user *buffer, size_t count, loff_t *ppos)
+{
+ struct serio_raw *serio_raw = file->private_data;
+ struct serio_raw_client *client;
+ size_t written = 0;
+
+ if (!serio_raw->replay)
+ return -EIO;
+
+ serio_pause_rx(serio_raw->serio);
+
+ for (written = 0; written < count; written++)
+ if (!queue_write_byte(&serio_raw->queue, buffer[written]))
+ break;
+ if (written) {
+ list_for_each_entry(client, &serio_raw->client_list, node)
+ kill_fasync(&client->fasync, SIGIO, POLL_IN);
+ queue_wakeup(&serio_raw->queue);
+ }
+
+ serio_continue_rx(serio_raw->serio);
+ return written ?: -EIO;
+}
+
+static ssize_t debug_device_write(struct file *file,
+ const char __user *buffer, size_t count, loff_t *ppos)
+{
+ struct serio_raw *serio_raw = file->private_data;
+
+ if (!serio_raw->replay)
+ return -EIO;
+
+ return serio_raw_write_mainloop(serio_raw, buffer, count, true, NULL);
+}
+
+static unsigned int debug_user_poll(struct file *file, poll_table *wait)
+{
+ struct serio_raw *serio_raw = file->private_data;
+ struct queue *queue = &serio_raw->debug_user;
+
+ return queue_poll(queue, file, wait, &serio_raw->dead);
+}
+
+static unsigned int debug_device_poll(struct file *file, poll_table *wait)
+{
+ struct serio_raw *serio_raw = file->private_data;
+ struct queue *queue = &serio_raw->debug_device;
+
+ return queue_poll(queue, file, wait, &serio_raw->dead);
+}
+
static const struct file_operations debug_user_fops = {
+ .owner = THIS_MODULE,
+ .open = debug_user_open,
+ .release = debug_user_release,
+ .read = debug_user_read,
+ .write = debug_user_write,
+ .poll = debug_user_poll,
+ .llseek = noop_llseek,
};
static const struct file_operations debug_device_fops = {
+ .owner = THIS_MODULE,
+ .open = debug_device_open,
+ .release = debug_device_release,
+ .read = debug_device_read,
+ .write = debug_device_write,
+ .poll = debug_device_poll,
+ .llseek = noop_llseek,
};
@@ -367,7 +505,12 @@ static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data,
struct serio_raw_client *client;
/* we are holding serio->lock here so we are protected */
- if (queue_write_byte(&serio_raw->queue, data)) {
+
+ if (serio_raw->debug_device_opened &&
+ queue_write_byte(&serio_raw->debug_device, data))
+ queue_wakeup(&serio_raw->debug_device);
+
+ if (!serio_raw->replay && queue_write_byte(&serio_raw->queue, data)) {
list_for_each_entry(client, &serio_raw->client_list, node)
kill_fasync(&client->fasync, SIGIO, POLL_IN);
queue_wakeup(&serio_raw->queue);