|
@@ -17,6 +17,7 @@
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
*/
|
|
|
#include <linux/cdev.h>
|
|
|
+#include <linux/debugfs.h>
|
|
|
#include <linux/device.h>
|
|
|
#include <linux/err.h>
|
|
|
#include <linux/fs.h>
|
|
@@ -43,6 +44,9 @@ struct ports_driver_data {
|
|
|
/* Used for registering chardevs */
|
|
|
struct class *class;
|
|
|
|
|
|
+ /* Used for exporting per-port information to debugfs */
|
|
|
+ struct dentry *debugfs_dir;
|
|
|
+
|
|
|
/* Number of devices this driver is handling */
|
|
|
unsigned int index;
|
|
|
|
|
@@ -158,6 +162,9 @@ struct port {
|
|
|
/* The IO vqs for this port */
|
|
|
struct virtqueue *in_vq, *out_vq;
|
|
|
|
|
|
+ /* File in the debugfs directory that exposes this port's information */
|
|
|
+ struct dentry *debugfs_file;
|
|
|
+
|
|
|
/*
|
|
|
* The entries in this struct will be valid if this port is
|
|
|
* hooked up to an hvc console
|
|
@@ -783,6 +790,49 @@ static struct attribute_group port_attribute_group = {
|
|
|
.attrs = port_sysfs_entries,
|
|
|
};
|
|
|
|
|
|
+static int debugfs_open(struct inode *inode, struct file *filp)
|
|
|
+{
|
|
|
+ filp->private_data = inode->i_private;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t debugfs_read(struct file *filp, char __user *ubuf,
|
|
|
+ size_t count, loff_t *offp)
|
|
|
+{
|
|
|
+ struct port *port;
|
|
|
+ char *buf;
|
|
|
+ ssize_t ret, out_offset, out_count;
|
|
|
+
|
|
|
+ out_count = 1024;
|
|
|
+ buf = kmalloc(out_count, GFP_KERNEL);
|
|
|
+ if (!buf)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ port = filp->private_data;
|
|
|
+ out_offset = 0;
|
|
|
+ out_offset += snprintf(buf + out_offset, out_count,
|
|
|
+ "name: %s\n", port->name ? port->name : "");
|
|
|
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
|
|
|
+ "guest_connected: %d\n", port->guest_connected);
|
|
|
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
|
|
|
+ "host_connected: %d\n", port->host_connected);
|
|
|
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
|
|
|
+ "is_console: %s\n",
|
|
|
+ is_console_port(port) ? "yes" : "no");
|
|
|
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
|
|
|
+ "console_vtermno: %u\n", port->cons.vtermno);
|
|
|
+
|
|
|
+ ret = simple_read_from_buffer(ubuf, count, offp, buf, out_offset);
|
|
|
+ kfree(buf);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static const struct file_operations port_debugfs_ops = {
|
|
|
+ .owner = THIS_MODULE,
|
|
|
+ .open = debugfs_open,
|
|
|
+ .read = debugfs_read,
|
|
|
+};
|
|
|
+
|
|
|
/* Remove all port-specific data. */
|
|
|
static int remove_port(struct port *port)
|
|
|
{
|
|
@@ -809,6 +859,8 @@ static int remove_port(struct port *port)
|
|
|
discard_port_data(port);
|
|
|
kfree(port->name);
|
|
|
|
|
|
+ debugfs_remove(port->debugfs_file);
|
|
|
+
|
|
|
kfree(port);
|
|
|
return 0;
|
|
|
}
|
|
@@ -1021,6 +1073,7 @@ static void fill_queue(struct virtqueue *vq, spinlock_t *lock)
|
|
|
|
|
|
static int add_port(struct ports_device *portdev, u32 id)
|
|
|
{
|
|
|
+ char debugfs_name[16];
|
|
|
struct port *port;
|
|
|
struct port_buffer *inbuf;
|
|
|
dev_t devt;
|
|
@@ -1096,6 +1149,18 @@ static int add_port(struct ports_device *portdev, u32 id)
|
|
|
*/
|
|
|
send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
|
|
|
|
|
|
+ if (pdrvdata.debugfs_dir) {
|
|
|
+ /*
|
|
|
+ * Finally, create the debugfs file that we can use to
|
|
|
+ * inspect a port's state at any time
|
|
|
+ */
|
|
|
+ sprintf(debugfs_name, "vport%up%u",
|
|
|
+ port->portdev->drv_index, id);
|
|
|
+ port->debugfs_file = debugfs_create_file(debugfs_name, 0444,
|
|
|
+ pdrvdata.debugfs_dir,
|
|
|
+ port,
|
|
|
+ &port_debugfs_ops);
|
|
|
+ }
|
|
|
return 0;
|
|
|
|
|
|
free_inbuf:
|
|
@@ -1406,6 +1471,12 @@ static int __init init(void)
|
|
|
pr_err("Error %d creating virtio-ports class\n", err);
|
|
|
return err;
|
|
|
}
|
|
|
+
|
|
|
+ pdrvdata.debugfs_dir = debugfs_create_dir("virtio-ports", NULL);
|
|
|
+ if (!pdrvdata.debugfs_dir) {
|
|
|
+ pr_warning("Error %ld creating debugfs dir for virtio-ports\n",
|
|
|
+ PTR_ERR(pdrvdata.debugfs_dir));
|
|
|
+ }
|
|
|
INIT_LIST_HEAD(&pdrvdata.consoles);
|
|
|
|
|
|
return register_virtio_driver(&virtio_console);
|