linux/drivers/char/virtio_console.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright (C) 2006, 2007, 2009 Rusty Russell, IBM Corporation
 * Copyright (C) 2009, 2010, 2011 Red Hat, Inc.
 * Copyright (C) 2009, 2010, 2011 Amit Shah <[email protected]>
 */
#include <linux/cdev.h>
#include <linux/debugfs.h>
#include <linux/completion.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/freezer.h>
#include <linux/fs.h>
#include <linux/splice.h>
#include <linux/pagemap.h>
#include <linux/idr.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/virtio.h>
#include <linux/virtio_console.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
#include <linux/module.h>
#include <linux/dma-mapping.h>
#include "../tty/hvc/hvc_console.h"

#define is_rproc_enabled
#define VIRTCONS_MAX_PORTS

/*
 * This is a global struct for storing common data for all the devices
 * this driver handles.
 *
 * Mainly, it has a linked list for all the consoles in one place so
 * that callbacks from hvc for get_chars(), put_chars() work properly
 * across multiple devices and multiple ports per device.
 */
struct ports_driver_data {};

static struct ports_driver_data pdrvdata;

static const struct class port_class =;

static DEFINE_SPINLOCK(pdrvdata_lock);
static DECLARE_COMPLETION(early_console_added);

/* This struct holds information that's relevant only for console ports */
struct console {};

static DEFINE_IDA(vtermno_ida);

struct port_buffer {};

/*
 * This is a per-device struct that stores data common to all the
 * ports for that device (vdev->priv).
 */
struct ports_device {};

struct port_stats {};

/* This struct holds the per-port data */
struct port {};

static struct port *find_port_by_vtermno(u32 vtermno)
{}

static struct port *find_port_by_devt_in_portdev(struct ports_device *portdev,
						 dev_t dev)
{}

static struct port *find_port_by_devt(dev_t dev)
{}

static struct port *find_port_by_id(struct ports_device *portdev, u32 id)
{}

static struct port *find_port_by_vq(struct ports_device *portdev,
				    struct virtqueue *vq)
{}

static bool is_console_port(struct port *port)
{}

static bool is_rproc_serial(const struct virtio_device *vdev)
{}

static inline bool use_multiport(struct ports_device *portdev)
{}

static DEFINE_SPINLOCK(dma_bufs_lock);
static LIST_HEAD(pending_free_dma_bufs);

static void free_buf(struct port_buffer *buf, bool can_sleep)
{}

static void reclaim_dma_bufs(void)
{}

static struct port_buffer *alloc_buf(struct virtio_device *vdev, size_t buf_size,
				     int pages)
{}

/* Callers should take appropriate locks */
static struct port_buffer *get_inbuf(struct port *port)
{}

/*
 * Create a scatter-gather list representing our input buffer and put
 * it in the queue.
 *
 * Callers should take appropriate locks.
 */
static int add_inbuf(struct virtqueue *vq, struct port_buffer *buf)
{}

/* Discard any unread data this port has. Callers lockers. */
static void discard_port_data(struct port *port)
{}

static bool port_has_data(struct port *port)
{}

static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id,
				  unsigned int event, unsigned int value)
{}

static ssize_t send_control_msg(struct port *port, unsigned int event,
				unsigned int value)
{}


/* Callers must take the port->outvq_lock */
static void reclaim_consumed_buffers(struct port *port)
{}

static ssize_t __send_to_port(struct port *port, struct scatterlist *sg,
			      int nents, size_t in_count,
			      void *data, bool nonblock)
{}

/*
 * Give out the data that's requested from the buffer that we have
 * queued up.
 */
static ssize_t fill_readbuf(struct port *port, u8 __user *out_buf,
			    size_t out_count, bool to_user)
{}

/* The condition that must be true for polling to end */
static bool will_read_block(struct port *port)
{}

static bool will_write_block(struct port *port)
{}

static ssize_t port_fops_read(struct file *filp, char __user *ubuf,
			      size_t count, loff_t *offp)
{}

static int wait_port_writable(struct port *port, bool nonblock)
{}

static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
			       size_t count, loff_t *offp)
{}

struct sg_list {};

static int pipe_to_sg(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
			struct splice_desc *sd)
{}

/* Faster zero-copy write by splicing */
static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe,
				      struct file *filp, loff_t *ppos,
				      size_t len, unsigned int flags)
{}

static __poll_t port_fops_poll(struct file *filp, poll_table *wait)
{}

static void remove_port(struct kref *kref);

static int port_fops_release(struct inode *inode, struct file *filp)
{}

static int port_fops_open(struct inode *inode, struct file *filp)
{}

static int port_fops_fasync(int fd, struct file *filp, int mode)
{}

/*
 * The file operations that we support: programs in the guest can open
 * a console device, read from it, write to it, poll for data and
 * close it.  The devices are at
 *   /dev/vport<device number>p<port number>
 */
static const struct file_operations port_fops =;

/*
 * The put_chars() callback is pretty straightforward.
 *
 * We turn the characters into a scatter-gather list, add it to the
 * output queue and then kick the Host.  Then we sit here waiting for
 * it to finish: inefficient in theory, but in practice
 * implementations will do it immediately.
 */
static ssize_t put_chars(u32 vtermno, const u8 *buf, size_t count)
{}

/*
 * get_chars() is the callback from the hvc_console infrastructure
 * when an interrupt is received.
 *
 * We call out to fill_readbuf that gets us the required data from the
 * buffers that are queued up.
 */
static ssize_t get_chars(u32 vtermno, u8 *buf, size_t count)
{}

static void resize_console(struct port *port)
{}

/* We set the configuration at this point, since we now have a tty */
static int notifier_add_vio(struct hvc_struct *hp, int data)
{}

static void notifier_del_vio(struct hvc_struct *hp, int data)
{}

/* The operations for console ports. */
static const struct hv_ops hv_ops =;

static int init_port_console(struct port *port)
{}

static ssize_t show_port_name(struct device *dev,
			      struct device_attribute *attr, char *buffer)
{}

static DEVICE_ATTR(name, S_IRUGO, show_port_name, NULL);

static struct attribute *port_sysfs_entries[] =;

static const struct attribute_group port_attribute_group =;

static int port_debugfs_show(struct seq_file *s, void *data)
{}

DEFINE_SHOW_ATTRIBUTE();

static void set_console_size(struct port *port, u16 rows, u16 cols)
{}

static int fill_queue(struct virtqueue *vq, spinlock_t *lock)
{}

static void send_sigio_to_port(struct port *port)
{}

static int add_port(struct ports_device *portdev, u32 id)
{}

/* No users remain, remove all port-specific data. */
static void remove_port(struct kref *kref)
{}

static void remove_port_data(struct port *port)
{}

/*
 * Port got unplugged.  Remove port from portdev's list and drop the
 * kref reference.  If no userspace has this port opened, it will
 * result in immediate removal the port.
 */
static void unplug_port(struct port *port)
{}

/* Any private messages that the Host and Guest want to share */
static void handle_control_message(struct virtio_device *vdev,
				   struct ports_device *portdev,
				   struct port_buffer *buf)
{}

static void control_work_handler(struct work_struct *work)
{}

static void flush_bufs(struct virtqueue *vq, bool can_sleep)
{}

static void out_intr(struct virtqueue *vq)
{}

static void in_intr(struct virtqueue *vq)
{}

static void control_intr(struct virtqueue *vq)
{}

static void config_intr(struct virtio_device *vdev)
{}

static void config_work_handler(struct work_struct *work)
{}

static int init_vqs(struct ports_device *portdev)
{}

static const struct file_operations portdev_fops =;

static void remove_vqs(struct ports_device *portdev)
{}

static void virtcons_remove(struct virtio_device *vdev)
{}

/*
 * Once we're further in boot, we get probed like any other virtio
 * device.
 *
 * If the host also supports multiple console ports, we check the
 * config space to see how many ports the host has spawned.  We
 * initialize each port found.
 */
static int virtcons_probe(struct virtio_device *vdev)
{}

static const struct virtio_device_id id_table[] =;
MODULE_DEVICE_TABLE(virtio, id_table);

static const unsigned int features[] =;

static const struct virtio_device_id rproc_serial_id_table[] =;
MODULE_DEVICE_TABLE(virtio, rproc_serial_id_table);

static const unsigned int rproc_serial_features[] =;

#ifdef CONFIG_PM_SLEEP
static int virtcons_freeze(struct virtio_device *vdev)
{}

static int virtcons_restore(struct virtio_device *vdev)
{}
#endif

static struct virtio_driver virtio_console =;

static struct virtio_driver virtio_rproc_serial =;

static int __init virtio_console_init(void)
{}

static void __exit virtio_console_fini(void)
{}
module_init();
module_exit(virtio_console_fini);

MODULE_DESCRIPTION();
MODULE_LICENSE();