151df0accSAmit Shah /* 251df0accSAmit Shah * Copyright (C) 2006, 2007, 2009 Rusty Russell, IBM Corporation 3ce86d35dSLinus Torvalds * Copyright (C) 2009, 2010, 2011 Red Hat, Inc. 4ce86d35dSLinus Torvalds * Copyright (C) 2009, 2010, 2011 Amit Shah <amit.shah@redhat.com> 551df0accSAmit Shah * 651df0accSAmit Shah * This program is free software; you can redistribute it and/or modify 751df0accSAmit Shah * it under the terms of the GNU General Public License as published by 851df0accSAmit Shah * the Free Software Foundation; either version 2 of the License, or 951df0accSAmit Shah * (at your option) any later version. 1051df0accSAmit Shah * 1151df0accSAmit Shah * This program is distributed in the hope that it will be useful, 1251df0accSAmit Shah * but WITHOUT ANY WARRANTY; without even the implied warranty of 1351df0accSAmit Shah * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1451df0accSAmit Shah * GNU General Public License for more details. 1551df0accSAmit Shah * 1651df0accSAmit Shah * You should have received a copy of the GNU General Public License 1751df0accSAmit Shah * along with this program; if not, write to the Free Software 1851df0accSAmit Shah * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 1951df0accSAmit Shah */ 2051df0accSAmit Shah #include <linux/cdev.h> 2151df0accSAmit Shah #include <linux/debugfs.h> 2251df0accSAmit Shah #include <linux/device.h> 2351df0accSAmit Shah #include <linux/err.h> 24a08fa92dSAmit Shah #include <linux/freezer.h> 2551df0accSAmit Shah #include <linux/fs.h> 2651df0accSAmit Shah #include <linux/init.h> 2751df0accSAmit Shah #include <linux/list.h> 2851df0accSAmit Shah #include <linux/poll.h> 2951df0accSAmit Shah #include <linux/sched.h> 3051df0accSAmit Shah #include <linux/slab.h> 3151df0accSAmit Shah #include <linux/spinlock.h> 3251df0accSAmit Shah #include <linux/virtio.h> 3351df0accSAmit Shah #include <linux/virtio_console.h> 3451df0accSAmit Shah #include <linux/wait.h> 3551df0accSAmit Shah #include <linux/workqueue.h> 3651df0accSAmit Shah #include "../tty/hvc/hvc_console.h" 3751df0accSAmit Shah 3851df0accSAmit Shah /* 3951df0accSAmit Shah * This is a global struct for storing common data for all the devices 4051df0accSAmit Shah * this driver handles. 4151df0accSAmit Shah * 4251df0accSAmit Shah * Mainly, it has a linked list for all the consoles in one place so 4351df0accSAmit Shah * that callbacks from hvc for get_chars(), put_chars() work properly 4451df0accSAmit Shah * across multiple devices and multiple ports per device. 4551df0accSAmit Shah */ 4651df0accSAmit Shah struct ports_driver_data { 4751df0accSAmit Shah /* Used for registering chardevs */ 4851df0accSAmit Shah struct class *class; 4951df0accSAmit Shah 5051df0accSAmit Shah /* Used for exporting per-port information to debugfs */ 5151df0accSAmit Shah struct dentry *debugfs_dir; 5251df0accSAmit Shah 5351df0accSAmit Shah /* List of all the devices we're handling */ 5451df0accSAmit Shah struct list_head portdevs; 5551df0accSAmit Shah 5651df0accSAmit Shah /* Number of devices this driver is handling */ 5751df0accSAmit Shah unsigned int index; 5851df0accSAmit Shah 5951df0accSAmit Shah /* 6051df0accSAmit Shah * This is used to keep track of the number of hvc consoles 6151df0accSAmit Shah * spawned by this driver. This number is given as the first 6251df0accSAmit Shah * argument to hvc_alloc(). To correctly map an initial 6351df0accSAmit Shah * console spawned via hvc_instantiate to the console being 6451df0accSAmit Shah * hooked up via hvc_alloc, we need to pass the same vtermno. 6551df0accSAmit Shah * 6651df0accSAmit Shah * We also just assume the first console being initialised was 6751df0accSAmit Shah * the first one that got used as the initial console. 6851df0accSAmit Shah */ 6951df0accSAmit Shah unsigned int next_vtermno; 7051df0accSAmit Shah 7151df0accSAmit Shah /* All the console devices handled by this driver */ 7251df0accSAmit Shah struct list_head consoles; 7351df0accSAmit Shah }; 7451df0accSAmit Shah static struct ports_driver_data pdrvdata; 7551df0accSAmit Shah 7651df0accSAmit Shah DEFINE_SPINLOCK(pdrvdata_lock); 7751df0accSAmit Shah 7851df0accSAmit Shah /* This struct holds information that's relevant only for console ports */ 7951df0accSAmit Shah struct console { 8051df0accSAmit Shah /* We'll place all consoles in a list in the pdrvdata struct */ 8151df0accSAmit Shah struct list_head list; 8251df0accSAmit Shah 8351df0accSAmit Shah /* The hvc device associated with this console port */ 8451df0accSAmit Shah struct hvc_struct *hvc; 8551df0accSAmit Shah 8651df0accSAmit Shah /* The size of the console */ 8751df0accSAmit Shah struct winsize ws; 8851df0accSAmit Shah 8951df0accSAmit Shah /* 9051df0accSAmit Shah * This number identifies the number that we used to register 9151df0accSAmit Shah * with hvc in hvc_instantiate() and hvc_alloc(); this is the 9251df0accSAmit Shah * number passed on by the hvc callbacks to us to 9351df0accSAmit Shah * differentiate between the other console ports handled by 9451df0accSAmit Shah * this driver 9551df0accSAmit Shah */ 9651df0accSAmit Shah u32 vtermno; 9751df0accSAmit Shah }; 9851df0accSAmit Shah 9951df0accSAmit Shah struct port_buffer { 10051df0accSAmit Shah char *buf; 10151df0accSAmit Shah 10251df0accSAmit Shah /* size of the buffer in *buf above */ 10351df0accSAmit Shah size_t size; 10451df0accSAmit Shah 10551df0accSAmit Shah /* used length of the buffer */ 10651df0accSAmit Shah size_t len; 10751df0accSAmit Shah /* offset in the buf from which to consume data */ 10851df0accSAmit Shah size_t offset; 10951df0accSAmit Shah }; 11051df0accSAmit Shah 11151df0accSAmit Shah /* 11251df0accSAmit Shah * This is a per-device struct that stores data common to all the 11351df0accSAmit Shah * ports for that device (vdev->priv). 11451df0accSAmit Shah */ 11551df0accSAmit Shah struct ports_device { 11651df0accSAmit Shah /* Next portdev in the list, head is in the pdrvdata struct */ 11751df0accSAmit Shah struct list_head list; 11851df0accSAmit Shah 11951df0accSAmit Shah /* 12051df0accSAmit Shah * Workqueue handlers where we process deferred work after 12151df0accSAmit Shah * notification 12251df0accSAmit Shah */ 12351df0accSAmit Shah struct work_struct control_work; 12451df0accSAmit Shah 12551df0accSAmit Shah struct list_head ports; 12651df0accSAmit Shah 12751df0accSAmit Shah /* To protect the list of ports */ 12851df0accSAmit Shah spinlock_t ports_lock; 12951df0accSAmit Shah 13051df0accSAmit Shah /* To protect the vq operations for the control channel */ 13151df0accSAmit Shah spinlock_t cvq_lock; 13251df0accSAmit Shah 13351df0accSAmit Shah /* The current config space is stored here */ 13451df0accSAmit Shah struct virtio_console_config config; 13551df0accSAmit Shah 13651df0accSAmit Shah /* The virtio device we're associated with */ 13751df0accSAmit Shah struct virtio_device *vdev; 13851df0accSAmit Shah 13951df0accSAmit Shah /* 14051df0accSAmit Shah * A couple of virtqueues for the control channel: one for 14151df0accSAmit Shah * guest->host transfers, one for host->guest transfers 14251df0accSAmit Shah */ 14351df0accSAmit Shah struct virtqueue *c_ivq, *c_ovq; 14451df0accSAmit Shah 14551df0accSAmit Shah /* Array of per-port IO virtqueues */ 14651df0accSAmit Shah struct virtqueue **in_vqs, **out_vqs; 14751df0accSAmit Shah 14851df0accSAmit Shah /* Used for numbering devices for sysfs and debugfs */ 14951df0accSAmit Shah unsigned int drv_index; 15051df0accSAmit Shah 15151df0accSAmit Shah /* Major number for this device. Ports will be created as minors. */ 15251df0accSAmit Shah int chr_major; 15351df0accSAmit Shah }; 15451df0accSAmit Shah 15551df0accSAmit Shah /* This struct holds the per-port data */ 15651df0accSAmit Shah struct port { 15751df0accSAmit Shah /* Next port in the list, head is in the ports_device */ 15851df0accSAmit Shah struct list_head list; 15951df0accSAmit Shah 16051df0accSAmit Shah /* Pointer to the parent virtio_console device */ 16151df0accSAmit Shah struct ports_device *portdev; 16251df0accSAmit Shah 16351df0accSAmit Shah /* The current buffer from which data has to be fed to readers */ 16451df0accSAmit Shah struct port_buffer *inbuf; 16551df0accSAmit Shah 16651df0accSAmit Shah /* 16751df0accSAmit Shah * To protect the operations on the in_vq associated with this 16851df0accSAmit Shah * port. Has to be a spinlock because it can be called from 16951df0accSAmit Shah * interrupt context (get_char()). 17051df0accSAmit Shah */ 17151df0accSAmit Shah spinlock_t inbuf_lock; 17251df0accSAmit Shah 17351df0accSAmit Shah /* Protect the operations on the out_vq. */ 17451df0accSAmit Shah spinlock_t outvq_lock; 17551df0accSAmit Shah 17651df0accSAmit Shah /* The IO vqs for this port */ 17751df0accSAmit Shah struct virtqueue *in_vq, *out_vq; 17851df0accSAmit Shah 17951df0accSAmit Shah /* File in the debugfs directory that exposes this port's information */ 18051df0accSAmit Shah struct dentry *debugfs_file; 18151df0accSAmit Shah 18251df0accSAmit Shah /* 18351df0accSAmit Shah * The entries in this struct will be valid if this port is 18451df0accSAmit Shah * hooked up to an hvc console 18551df0accSAmit Shah */ 18651df0accSAmit Shah struct console cons; 18751df0accSAmit Shah 18851df0accSAmit Shah /* Each port associates with a separate char device */ 18951df0accSAmit Shah struct cdev *cdev; 19051df0accSAmit Shah struct device *dev; 19151df0accSAmit Shah 19251df0accSAmit Shah /* Reference-counting to handle port hot-unplugs and file operations */ 19351df0accSAmit Shah struct kref kref; 19451df0accSAmit Shah 19551df0accSAmit Shah /* A waitqueue for poll() or blocking read operations */ 19651df0accSAmit Shah wait_queue_head_t waitqueue; 19751df0accSAmit Shah 19851df0accSAmit Shah /* The 'name' of the port that we expose via sysfs properties */ 19951df0accSAmit Shah char *name; 20051df0accSAmit Shah 20151df0accSAmit Shah /* We can notify apps of host connect / disconnect events via SIGIO */ 20251df0accSAmit Shah struct fasync_struct *async_queue; 20351df0accSAmit Shah 20451df0accSAmit Shah /* The 'id' to identify the port with the Host */ 20551df0accSAmit Shah u32 id; 20651df0accSAmit Shah 20751df0accSAmit Shah bool outvq_full; 20851df0accSAmit Shah 20951df0accSAmit Shah /* Is the host device open */ 21051df0accSAmit Shah bool host_connected; 21151df0accSAmit Shah 21251df0accSAmit Shah /* We should allow only one process to open a port */ 21351df0accSAmit Shah bool guest_connected; 21451df0accSAmit Shah }; 21551df0accSAmit Shah 21651df0accSAmit Shah /* This is the very early arch-specified put chars function. */ 21751df0accSAmit Shah static int (*early_put_chars)(u32, const char *, int); 21851df0accSAmit Shah 21951df0accSAmit Shah static struct port *find_port_by_vtermno(u32 vtermno) 22051df0accSAmit Shah { 22151df0accSAmit Shah struct port *port; 22251df0accSAmit Shah struct console *cons; 22351df0accSAmit Shah unsigned long flags; 22451df0accSAmit Shah 22551df0accSAmit Shah spin_lock_irqsave(&pdrvdata_lock, flags); 22651df0accSAmit Shah list_for_each_entry(cons, &pdrvdata.consoles, list) { 22751df0accSAmit Shah if (cons->vtermno == vtermno) { 22851df0accSAmit Shah port = container_of(cons, struct port, cons); 22951df0accSAmit Shah goto out; 23051df0accSAmit Shah } 23151df0accSAmit Shah } 23251df0accSAmit Shah port = NULL; 23351df0accSAmit Shah out: 23451df0accSAmit Shah spin_unlock_irqrestore(&pdrvdata_lock, flags); 23551df0accSAmit Shah return port; 23651df0accSAmit Shah } 23751df0accSAmit Shah 23851df0accSAmit Shah static struct port *find_port_by_devt_in_portdev(struct ports_device *portdev, 23951df0accSAmit Shah dev_t dev) 24051df0accSAmit Shah { 24151df0accSAmit Shah struct port *port; 24251df0accSAmit Shah unsigned long flags; 24351df0accSAmit Shah 24451df0accSAmit Shah spin_lock_irqsave(&portdev->ports_lock, flags); 24551df0accSAmit Shah list_for_each_entry(port, &portdev->ports, list) 24651df0accSAmit Shah if (port->cdev->dev == dev) 24751df0accSAmit Shah goto out; 24851df0accSAmit Shah port = NULL; 24951df0accSAmit Shah out: 25051df0accSAmit Shah spin_unlock_irqrestore(&portdev->ports_lock, flags); 25151df0accSAmit Shah 25251df0accSAmit Shah return port; 25351df0accSAmit Shah } 25451df0accSAmit Shah 25551df0accSAmit Shah static struct port *find_port_by_devt(dev_t dev) 25651df0accSAmit Shah { 25751df0accSAmit Shah struct ports_device *portdev; 25851df0accSAmit Shah struct port *port; 25951df0accSAmit Shah unsigned long flags; 26051df0accSAmit Shah 26151df0accSAmit Shah spin_lock_irqsave(&pdrvdata_lock, flags); 26251df0accSAmit Shah list_for_each_entry(portdev, &pdrvdata.portdevs, list) { 26351df0accSAmit Shah port = find_port_by_devt_in_portdev(portdev, dev); 26451df0accSAmit Shah if (port) 26551df0accSAmit Shah goto out; 26651df0accSAmit Shah } 26751df0accSAmit Shah port = NULL; 26851df0accSAmit Shah out: 26951df0accSAmit Shah spin_unlock_irqrestore(&pdrvdata_lock, flags); 27051df0accSAmit Shah return port; 27151df0accSAmit Shah } 27251df0accSAmit Shah 27351df0accSAmit Shah static struct port *find_port_by_id(struct ports_device *portdev, u32 id) 27451df0accSAmit Shah { 27551df0accSAmit Shah struct port *port; 27651df0accSAmit Shah unsigned long flags; 27751df0accSAmit Shah 27851df0accSAmit Shah spin_lock_irqsave(&portdev->ports_lock, flags); 27951df0accSAmit Shah list_for_each_entry(port, &portdev->ports, list) 28051df0accSAmit Shah if (port->id == id) 28151df0accSAmit Shah goto out; 28251df0accSAmit Shah port = NULL; 28351df0accSAmit Shah out: 28451df0accSAmit Shah spin_unlock_irqrestore(&portdev->ports_lock, flags); 28551df0accSAmit Shah 28651df0accSAmit Shah return port; 28751df0accSAmit Shah } 28851df0accSAmit Shah 28951df0accSAmit Shah static struct port *find_port_by_vq(struct ports_device *portdev, 29051df0accSAmit Shah struct virtqueue *vq) 29151df0accSAmit Shah { 29251df0accSAmit Shah struct port *port; 29351df0accSAmit Shah unsigned long flags; 29451df0accSAmit Shah 29551df0accSAmit Shah spin_lock_irqsave(&portdev->ports_lock, flags); 29651df0accSAmit Shah list_for_each_entry(port, &portdev->ports, list) 29751df0accSAmit Shah if (port->in_vq == vq || port->out_vq == vq) 29851df0accSAmit Shah goto out; 29951df0accSAmit Shah port = NULL; 30051df0accSAmit Shah out: 30151df0accSAmit Shah spin_unlock_irqrestore(&portdev->ports_lock, flags); 30251df0accSAmit Shah return port; 30351df0accSAmit Shah } 30451df0accSAmit Shah 30551df0accSAmit Shah static bool is_console_port(struct port *port) 30651df0accSAmit Shah { 30751df0accSAmit Shah if (port->cons.hvc) 30851df0accSAmit Shah return true; 30951df0accSAmit Shah return false; 31051df0accSAmit Shah } 31151df0accSAmit Shah 31251df0accSAmit Shah static inline bool use_multiport(struct ports_device *portdev) 31351df0accSAmit Shah { 31451df0accSAmit Shah /* 31551df0accSAmit Shah * This condition can be true when put_chars is called from 31651df0accSAmit Shah * early_init 31751df0accSAmit Shah */ 31851df0accSAmit Shah if (!portdev->vdev) 31951df0accSAmit Shah return 0; 32051df0accSAmit Shah return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT); 32151df0accSAmit Shah } 32251df0accSAmit Shah 32351df0accSAmit Shah static void free_buf(struct port_buffer *buf) 32451df0accSAmit Shah { 32551df0accSAmit Shah kfree(buf->buf); 32651df0accSAmit Shah kfree(buf); 32751df0accSAmit Shah } 32851df0accSAmit Shah 32951df0accSAmit Shah static struct port_buffer *alloc_buf(size_t buf_size) 33051df0accSAmit Shah { 33151df0accSAmit Shah struct port_buffer *buf; 33251df0accSAmit Shah 33351df0accSAmit Shah buf = kmalloc(sizeof(*buf), GFP_KERNEL); 33451df0accSAmit Shah if (!buf) 33551df0accSAmit Shah goto fail; 33651df0accSAmit Shah buf->buf = kzalloc(buf_size, GFP_KERNEL); 33751df0accSAmit Shah if (!buf->buf) 33851df0accSAmit Shah goto free_buf; 33951df0accSAmit Shah buf->len = 0; 34051df0accSAmit Shah buf->offset = 0; 34151df0accSAmit Shah buf->size = buf_size; 34251df0accSAmit Shah return buf; 34351df0accSAmit Shah 34451df0accSAmit Shah free_buf: 34551df0accSAmit Shah kfree(buf); 34651df0accSAmit Shah fail: 34751df0accSAmit Shah return NULL; 34851df0accSAmit Shah } 34951df0accSAmit Shah 35051df0accSAmit Shah /* Callers should take appropriate locks */ 351defde669SAmit Shah static struct port_buffer *get_inbuf(struct port *port) 35251df0accSAmit Shah { 35351df0accSAmit Shah struct port_buffer *buf; 35451df0accSAmit Shah unsigned int len; 35551df0accSAmit Shah 356*d25a9ddaSAmit Shah if (port->inbuf) 357*d25a9ddaSAmit Shah return port->inbuf; 358*d25a9ddaSAmit Shah 359*d25a9ddaSAmit Shah buf = virtqueue_get_buf(port->in_vq, &len); 36051df0accSAmit Shah if (buf) { 36151df0accSAmit Shah buf->len = len; 36251df0accSAmit Shah buf->offset = 0; 36351df0accSAmit Shah } 36451df0accSAmit Shah return buf; 36551df0accSAmit Shah } 36651df0accSAmit Shah 36751df0accSAmit Shah /* 36851df0accSAmit Shah * Create a scatter-gather list representing our input buffer and put 36951df0accSAmit Shah * it in the queue. 37051df0accSAmit Shah * 37151df0accSAmit Shah * Callers should take appropriate locks. 37251df0accSAmit Shah */ 37351df0accSAmit Shah static int add_inbuf(struct virtqueue *vq, struct port_buffer *buf) 37451df0accSAmit Shah { 37551df0accSAmit Shah struct scatterlist sg[1]; 37651df0accSAmit Shah int ret; 37751df0accSAmit Shah 37851df0accSAmit Shah sg_init_one(sg, buf->buf, buf->size); 37951df0accSAmit Shah 38051df0accSAmit Shah ret = virtqueue_add_buf(vq, sg, 0, 1, buf); 38151df0accSAmit Shah virtqueue_kick(vq); 38251df0accSAmit Shah return ret; 38351df0accSAmit Shah } 38451df0accSAmit Shah 38551df0accSAmit Shah /* Discard any unread data this port has. Callers lockers. */ 38651df0accSAmit Shah static void discard_port_data(struct port *port) 38751df0accSAmit Shah { 38851df0accSAmit Shah struct port_buffer *buf; 38951df0accSAmit Shah struct virtqueue *vq; 39051df0accSAmit Shah unsigned int len; 39151df0accSAmit Shah int ret; 39251df0accSAmit Shah 393d7a62cd0SAmit Shah if (!port->portdev) { 394d7a62cd0SAmit Shah /* Device has been unplugged. vqs are already gone. */ 395d7a62cd0SAmit Shah return; 396d7a62cd0SAmit Shah } 39751df0accSAmit Shah vq = port->in_vq; 39851df0accSAmit Shah if (port->inbuf) 39951df0accSAmit Shah buf = port->inbuf; 40051df0accSAmit Shah else 40151df0accSAmit Shah buf = virtqueue_get_buf(vq, &len); 40251df0accSAmit Shah 40351df0accSAmit Shah ret = 0; 40451df0accSAmit Shah while (buf) { 40551df0accSAmit Shah if (add_inbuf(vq, buf) < 0) { 40651df0accSAmit Shah ret++; 40751df0accSAmit Shah free_buf(buf); 40851df0accSAmit Shah } 40951df0accSAmit Shah buf = virtqueue_get_buf(vq, &len); 41051df0accSAmit Shah } 41151df0accSAmit Shah port->inbuf = NULL; 41251df0accSAmit Shah if (ret) 41351df0accSAmit Shah dev_warn(port->dev, "Errors adding %d buffers back to vq\n", 41451df0accSAmit Shah ret); 41551df0accSAmit Shah } 41651df0accSAmit Shah 41751df0accSAmit Shah static bool port_has_data(struct port *port) 41851df0accSAmit Shah { 41951df0accSAmit Shah unsigned long flags; 42051df0accSAmit Shah bool ret; 42151df0accSAmit Shah 42251df0accSAmit Shah ret = false; 423*d25a9ddaSAmit Shah spin_lock_irqsave(&port->inbuf_lock, flags); 424*d25a9ddaSAmit Shah port->inbuf = get_inbuf(port); 425*d25a9ddaSAmit Shah if (port->inbuf) 426*d25a9ddaSAmit Shah ret = true; 427*d25a9ddaSAmit Shah 42851df0accSAmit Shah spin_unlock_irqrestore(&port->inbuf_lock, flags); 42951df0accSAmit Shah return ret; 43051df0accSAmit Shah } 43151df0accSAmit Shah 43251df0accSAmit Shah static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id, 43351df0accSAmit Shah unsigned int event, unsigned int value) 43451df0accSAmit Shah { 43551df0accSAmit Shah struct scatterlist sg[1]; 43651df0accSAmit Shah struct virtio_console_control cpkt; 43751df0accSAmit Shah struct virtqueue *vq; 43851df0accSAmit Shah unsigned int len; 43951df0accSAmit Shah 44051df0accSAmit Shah if (!use_multiport(portdev)) 44151df0accSAmit Shah return 0; 44251df0accSAmit Shah 44351df0accSAmit Shah cpkt.id = port_id; 44451df0accSAmit Shah cpkt.event = event; 44551df0accSAmit Shah cpkt.value = value; 44651df0accSAmit Shah 44751df0accSAmit Shah vq = portdev->c_ovq; 44851df0accSAmit Shah 44951df0accSAmit Shah sg_init_one(sg, &cpkt, sizeof(cpkt)); 45051df0accSAmit Shah if (virtqueue_add_buf(vq, sg, 1, 0, &cpkt) >= 0) { 45151df0accSAmit Shah virtqueue_kick(vq); 45251df0accSAmit Shah while (!virtqueue_get_buf(vq, &len)) 45351df0accSAmit Shah cpu_relax(); 45451df0accSAmit Shah } 45551df0accSAmit Shah return 0; 45651df0accSAmit Shah } 45751df0accSAmit Shah 45851df0accSAmit Shah static ssize_t send_control_msg(struct port *port, unsigned int event, 45951df0accSAmit Shah unsigned int value) 46051df0accSAmit Shah { 46151df0accSAmit Shah /* Did the port get unplugged before userspace closed it? */ 46251df0accSAmit Shah if (port->portdev) 46351df0accSAmit Shah return __send_control_msg(port->portdev, port->id, event, value); 46451df0accSAmit Shah return 0; 46551df0accSAmit Shah } 46651df0accSAmit Shah 46751df0accSAmit Shah /* Callers must take the port->outvq_lock */ 46851df0accSAmit Shah static void reclaim_consumed_buffers(struct port *port) 46951df0accSAmit Shah { 47051df0accSAmit Shah void *buf; 47151df0accSAmit Shah unsigned int len; 47251df0accSAmit Shah 473d7a62cd0SAmit Shah if (!port->portdev) { 474d7a62cd0SAmit Shah /* Device has been unplugged. vqs are already gone. */ 475d7a62cd0SAmit Shah return; 476d7a62cd0SAmit Shah } 47751df0accSAmit Shah while ((buf = virtqueue_get_buf(port->out_vq, &len))) { 47851df0accSAmit Shah kfree(buf); 47951df0accSAmit Shah port->outvq_full = false; 48051df0accSAmit Shah } 48151df0accSAmit Shah } 48251df0accSAmit Shah 48351df0accSAmit Shah static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count, 48451df0accSAmit Shah bool nonblock) 48551df0accSAmit Shah { 48651df0accSAmit Shah struct scatterlist sg[1]; 48751df0accSAmit Shah struct virtqueue *out_vq; 48851df0accSAmit Shah ssize_t ret; 48951df0accSAmit Shah unsigned long flags; 49051df0accSAmit Shah unsigned int len; 49151df0accSAmit Shah 49251df0accSAmit Shah out_vq = port->out_vq; 49351df0accSAmit Shah 49451df0accSAmit Shah spin_lock_irqsave(&port->outvq_lock, flags); 49551df0accSAmit Shah 49651df0accSAmit Shah reclaim_consumed_buffers(port); 49751df0accSAmit Shah 49851df0accSAmit Shah sg_init_one(sg, in_buf, in_count); 49951df0accSAmit Shah ret = virtqueue_add_buf(out_vq, sg, 1, 0, in_buf); 50051df0accSAmit Shah 50151df0accSAmit Shah /* Tell Host to go! */ 50251df0accSAmit Shah virtqueue_kick(out_vq); 50351df0accSAmit Shah 50451df0accSAmit Shah if (ret < 0) { 50551df0accSAmit Shah in_count = 0; 50651df0accSAmit Shah goto done; 50751df0accSAmit Shah } 50851df0accSAmit Shah 50951df0accSAmit Shah if (ret == 0) 51051df0accSAmit Shah port->outvq_full = true; 51151df0accSAmit Shah 51251df0accSAmit Shah if (nonblock) 51351df0accSAmit Shah goto done; 51451df0accSAmit Shah 51551df0accSAmit Shah /* 51651df0accSAmit Shah * Wait till the host acknowledges it pushed out the data we 51751df0accSAmit Shah * sent. This is done for data from the hvc_console; the tty 51851df0accSAmit Shah * operations are performed with spinlocks held so we can't 51951df0accSAmit Shah * sleep here. An alternative would be to copy the data to a 52051df0accSAmit Shah * buffer and relax the spinning requirement. The downside is 52151df0accSAmit Shah * we need to kmalloc a GFP_ATOMIC buffer each time the 52251df0accSAmit Shah * console driver writes something out. 52351df0accSAmit Shah */ 52451df0accSAmit Shah while (!virtqueue_get_buf(out_vq, &len)) 52551df0accSAmit Shah cpu_relax(); 52651df0accSAmit Shah done: 52751df0accSAmit Shah spin_unlock_irqrestore(&port->outvq_lock, flags); 52851df0accSAmit Shah /* 52951df0accSAmit Shah * We're expected to return the amount of data we wrote -- all 53051df0accSAmit Shah * of it 53151df0accSAmit Shah */ 53251df0accSAmit Shah return in_count; 53351df0accSAmit Shah } 53451df0accSAmit Shah 53551df0accSAmit Shah /* 53651df0accSAmit Shah * Give out the data that's requested from the buffer that we have 53751df0accSAmit Shah * queued up. 53851df0accSAmit Shah */ 53951df0accSAmit Shah static ssize_t fill_readbuf(struct port *port, char *out_buf, size_t out_count, 54051df0accSAmit Shah bool to_user) 54151df0accSAmit Shah { 54251df0accSAmit Shah struct port_buffer *buf; 54351df0accSAmit Shah unsigned long flags; 54451df0accSAmit Shah 54551df0accSAmit Shah if (!out_count || !port_has_data(port)) 54651df0accSAmit Shah return 0; 54751df0accSAmit Shah 54851df0accSAmit Shah buf = port->inbuf; 54951df0accSAmit Shah out_count = min(out_count, buf->len - buf->offset); 55051df0accSAmit Shah 55151df0accSAmit Shah if (to_user) { 55251df0accSAmit Shah ssize_t ret; 55351df0accSAmit Shah 55451df0accSAmit Shah ret = copy_to_user(out_buf, buf->buf + buf->offset, out_count); 55551df0accSAmit Shah if (ret) 55651df0accSAmit Shah return -EFAULT; 55751df0accSAmit Shah } else { 55851df0accSAmit Shah memcpy(out_buf, buf->buf + buf->offset, out_count); 55951df0accSAmit Shah } 56051df0accSAmit Shah 56151df0accSAmit Shah buf->offset += out_count; 56251df0accSAmit Shah 56351df0accSAmit Shah if (buf->offset == buf->len) { 56451df0accSAmit Shah /* 56551df0accSAmit Shah * We're done using all the data in this buffer. 56651df0accSAmit Shah * Re-queue so that the Host can send us more data. 56751df0accSAmit Shah */ 56851df0accSAmit Shah spin_lock_irqsave(&port->inbuf_lock, flags); 56951df0accSAmit Shah port->inbuf = NULL; 57051df0accSAmit Shah 57151df0accSAmit Shah if (add_inbuf(port->in_vq, buf) < 0) 57251df0accSAmit Shah dev_warn(port->dev, "failed add_buf\n"); 57351df0accSAmit Shah 57451df0accSAmit Shah spin_unlock_irqrestore(&port->inbuf_lock, flags); 57551df0accSAmit Shah } 57651df0accSAmit Shah /* Return the number of bytes actually copied */ 57751df0accSAmit Shah return out_count; 57851df0accSAmit Shah } 57951df0accSAmit Shah 58051df0accSAmit Shah /* The condition that must be true for polling to end */ 58151df0accSAmit Shah static bool will_read_block(struct port *port) 58251df0accSAmit Shah { 58351df0accSAmit Shah if (!port->guest_connected) { 58451df0accSAmit Shah /* Port got hot-unplugged. Let's exit. */ 58551df0accSAmit Shah return false; 58651df0accSAmit Shah } 58751df0accSAmit Shah return !port_has_data(port) && port->host_connected; 58851df0accSAmit Shah } 58951df0accSAmit Shah 59051df0accSAmit Shah static bool will_write_block(struct port *port) 59151df0accSAmit Shah { 59251df0accSAmit Shah bool ret; 59351df0accSAmit Shah 59451df0accSAmit Shah if (!port->guest_connected) { 59551df0accSAmit Shah /* Port got hot-unplugged. Let's exit. */ 59651df0accSAmit Shah return false; 59751df0accSAmit Shah } 59851df0accSAmit Shah if (!port->host_connected) 59951df0accSAmit Shah return true; 60051df0accSAmit Shah 60151df0accSAmit Shah spin_lock_irq(&port->outvq_lock); 60251df0accSAmit Shah /* 60351df0accSAmit Shah * Check if the Host has consumed any buffers since we last 60451df0accSAmit Shah * sent data (this is only applicable for nonblocking ports). 60551df0accSAmit Shah */ 60651df0accSAmit Shah reclaim_consumed_buffers(port); 60751df0accSAmit Shah ret = port->outvq_full; 60851df0accSAmit Shah spin_unlock_irq(&port->outvq_lock); 60951df0accSAmit Shah 61051df0accSAmit Shah return ret; 61151df0accSAmit Shah } 61251df0accSAmit Shah 61351df0accSAmit Shah static ssize_t port_fops_read(struct file *filp, char __user *ubuf, 61451df0accSAmit Shah size_t count, loff_t *offp) 61551df0accSAmit Shah { 61651df0accSAmit Shah struct port *port; 61751df0accSAmit Shah ssize_t ret; 61851df0accSAmit Shah 61951df0accSAmit Shah port = filp->private_data; 62051df0accSAmit Shah 62151df0accSAmit Shah if (!port_has_data(port)) { 62251df0accSAmit Shah /* 62351df0accSAmit Shah * If nothing's connected on the host just return 0 in 62451df0accSAmit Shah * case of list_empty; this tells the userspace app 62551df0accSAmit Shah * that there's no connection 62651df0accSAmit Shah */ 62751df0accSAmit Shah if (!port->host_connected) 62851df0accSAmit Shah return 0; 62951df0accSAmit Shah if (filp->f_flags & O_NONBLOCK) 63051df0accSAmit Shah return -EAGAIN; 63151df0accSAmit Shah 632a08fa92dSAmit Shah ret = wait_event_freezable(port->waitqueue, 63351df0accSAmit Shah !will_read_block(port)); 63451df0accSAmit Shah if (ret < 0) 63551df0accSAmit Shah return ret; 63651df0accSAmit Shah } 63751df0accSAmit Shah /* Port got hot-unplugged. */ 63851df0accSAmit Shah if (!port->guest_connected) 63951df0accSAmit Shah return -ENODEV; 64051df0accSAmit Shah /* 64151df0accSAmit Shah * We could've received a disconnection message while we were 64251df0accSAmit Shah * waiting for more data. 64351df0accSAmit Shah * 64451df0accSAmit Shah * This check is not clubbed in the if() statement above as we 64551df0accSAmit Shah * might receive some data as well as the host could get 64651df0accSAmit Shah * disconnected after we got woken up from our wait. So we 64751df0accSAmit Shah * really want to give off whatever data we have and only then 64851df0accSAmit Shah * check for host_connected. 64951df0accSAmit Shah */ 65051df0accSAmit Shah if (!port_has_data(port) && !port->host_connected) 65151df0accSAmit Shah return 0; 65251df0accSAmit Shah 65351df0accSAmit Shah return fill_readbuf(port, ubuf, count, true); 65451df0accSAmit Shah } 65551df0accSAmit Shah 65651df0accSAmit Shah static ssize_t port_fops_write(struct file *filp, const char __user *ubuf, 65751df0accSAmit Shah size_t count, loff_t *offp) 65851df0accSAmit Shah { 65951df0accSAmit Shah struct port *port; 66051df0accSAmit Shah char *buf; 66151df0accSAmit Shah ssize_t ret; 66251df0accSAmit Shah bool nonblock; 66351df0accSAmit Shah 66451df0accSAmit Shah /* Userspace could be out to fool us */ 66551df0accSAmit Shah if (!count) 66651df0accSAmit Shah return 0; 66751df0accSAmit Shah 66851df0accSAmit Shah port = filp->private_data; 66951df0accSAmit Shah 67051df0accSAmit Shah nonblock = filp->f_flags & O_NONBLOCK; 67151df0accSAmit Shah 67251df0accSAmit Shah if (will_write_block(port)) { 67351df0accSAmit Shah if (nonblock) 67451df0accSAmit Shah return -EAGAIN; 67551df0accSAmit Shah 676a08fa92dSAmit Shah ret = wait_event_freezable(port->waitqueue, 67751df0accSAmit Shah !will_write_block(port)); 67851df0accSAmit Shah if (ret < 0) 67951df0accSAmit Shah return ret; 68051df0accSAmit Shah } 68151df0accSAmit Shah /* Port got hot-unplugged. */ 68251df0accSAmit Shah if (!port->guest_connected) 68351df0accSAmit Shah return -ENODEV; 68451df0accSAmit Shah 68551df0accSAmit Shah count = min((size_t)(32 * 1024), count); 68651df0accSAmit Shah 68751df0accSAmit Shah buf = kmalloc(count, GFP_KERNEL); 68851df0accSAmit Shah if (!buf) 68951df0accSAmit Shah return -ENOMEM; 69051df0accSAmit Shah 69151df0accSAmit Shah ret = copy_from_user(buf, ubuf, count); 69251df0accSAmit Shah if (ret) { 69351df0accSAmit Shah ret = -EFAULT; 69451df0accSAmit Shah goto free_buf; 69551df0accSAmit Shah } 69651df0accSAmit Shah 69751df0accSAmit Shah /* 69851df0accSAmit Shah * We now ask send_buf() to not spin for generic ports -- we 69951df0accSAmit Shah * can re-use the same code path that non-blocking file 70051df0accSAmit Shah * descriptors take for blocking file descriptors since the 70151df0accSAmit Shah * wait is already done and we're certain the write will go 70251df0accSAmit Shah * through to the host. 70351df0accSAmit Shah */ 70451df0accSAmit Shah nonblock = true; 70551df0accSAmit Shah ret = send_buf(port, buf, count, nonblock); 70651df0accSAmit Shah 70751df0accSAmit Shah if (nonblock && ret > 0) 70851df0accSAmit Shah goto out; 70951df0accSAmit Shah 71051df0accSAmit Shah free_buf: 71151df0accSAmit Shah kfree(buf); 71251df0accSAmit Shah out: 71351df0accSAmit Shah return ret; 71451df0accSAmit Shah } 71551df0accSAmit Shah 71651df0accSAmit Shah static unsigned int port_fops_poll(struct file *filp, poll_table *wait) 71751df0accSAmit Shah { 71851df0accSAmit Shah struct port *port; 71951df0accSAmit Shah unsigned int ret; 72051df0accSAmit Shah 72151df0accSAmit Shah port = filp->private_data; 72251df0accSAmit Shah poll_wait(filp, &port->waitqueue, wait); 72351df0accSAmit Shah 72451df0accSAmit Shah if (!port->guest_connected) { 72551df0accSAmit Shah /* Port got unplugged */ 72651df0accSAmit Shah return POLLHUP; 72751df0accSAmit Shah } 72851df0accSAmit Shah ret = 0; 72951df0accSAmit Shah if (!will_read_block(port)) 73051df0accSAmit Shah ret |= POLLIN | POLLRDNORM; 73151df0accSAmit Shah if (!will_write_block(port)) 73251df0accSAmit Shah ret |= POLLOUT; 73351df0accSAmit Shah if (!port->host_connected) 73451df0accSAmit Shah ret |= POLLHUP; 73551df0accSAmit Shah 73651df0accSAmit Shah return ret; 73751df0accSAmit Shah } 73851df0accSAmit Shah 73951df0accSAmit Shah static void remove_port(struct kref *kref); 74051df0accSAmit Shah 74151df0accSAmit Shah static int port_fops_release(struct inode *inode, struct file *filp) 74251df0accSAmit Shah { 74351df0accSAmit Shah struct port *port; 74451df0accSAmit Shah 74551df0accSAmit Shah port = filp->private_data; 74651df0accSAmit Shah 74751df0accSAmit Shah /* Notify host of port being closed */ 74851df0accSAmit Shah send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0); 74951df0accSAmit Shah 75051df0accSAmit Shah spin_lock_irq(&port->inbuf_lock); 75151df0accSAmit Shah port->guest_connected = false; 75251df0accSAmit Shah 75351df0accSAmit Shah discard_port_data(port); 75451df0accSAmit Shah 75551df0accSAmit Shah spin_unlock_irq(&port->inbuf_lock); 75651df0accSAmit Shah 75751df0accSAmit Shah spin_lock_irq(&port->outvq_lock); 75851df0accSAmit Shah reclaim_consumed_buffers(port); 75951df0accSAmit Shah spin_unlock_irq(&port->outvq_lock); 76051df0accSAmit Shah 76151df0accSAmit Shah /* 76251df0accSAmit Shah * Locks aren't necessary here as a port can't be opened after 76351df0accSAmit Shah * unplug, and if a port isn't unplugged, a kref would already 76451df0accSAmit Shah * exist for the port. Plus, taking ports_lock here would 76551df0accSAmit Shah * create a dependency on other locks taken by functions 76651df0accSAmit Shah * inside remove_port if we're the last holder of the port, 76751df0accSAmit Shah * creating many problems. 76851df0accSAmit Shah */ 76951df0accSAmit Shah kref_put(&port->kref, remove_port); 77051df0accSAmit Shah 77151df0accSAmit Shah return 0; 77251df0accSAmit Shah } 77351df0accSAmit Shah 77451df0accSAmit Shah static int port_fops_open(struct inode *inode, struct file *filp) 77551df0accSAmit Shah { 77651df0accSAmit Shah struct cdev *cdev = inode->i_cdev; 77751df0accSAmit Shah struct port *port; 77851df0accSAmit Shah int ret; 77951df0accSAmit Shah 78051df0accSAmit Shah port = find_port_by_devt(cdev->dev); 78151df0accSAmit Shah filp->private_data = port; 78251df0accSAmit Shah 78351df0accSAmit Shah /* Prevent against a port getting hot-unplugged at the same time */ 78451df0accSAmit Shah spin_lock_irq(&port->portdev->ports_lock); 78551df0accSAmit Shah kref_get(&port->kref); 78651df0accSAmit Shah spin_unlock_irq(&port->portdev->ports_lock); 78751df0accSAmit Shah 78851df0accSAmit Shah /* 78951df0accSAmit Shah * Don't allow opening of console port devices -- that's done 79051df0accSAmit Shah * via /dev/hvc 79151df0accSAmit Shah */ 79251df0accSAmit Shah if (is_console_port(port)) { 79351df0accSAmit Shah ret = -ENXIO; 79451df0accSAmit Shah goto out; 79551df0accSAmit Shah } 79651df0accSAmit Shah 79751df0accSAmit Shah /* Allow only one process to open a particular port at a time */ 79851df0accSAmit Shah spin_lock_irq(&port->inbuf_lock); 79951df0accSAmit Shah if (port->guest_connected) { 80051df0accSAmit Shah spin_unlock_irq(&port->inbuf_lock); 80151df0accSAmit Shah ret = -EMFILE; 80251df0accSAmit Shah goto out; 80351df0accSAmit Shah } 80451df0accSAmit Shah 80551df0accSAmit Shah port->guest_connected = true; 80651df0accSAmit Shah spin_unlock_irq(&port->inbuf_lock); 80751df0accSAmit Shah 80851df0accSAmit Shah spin_lock_irq(&port->outvq_lock); 80951df0accSAmit Shah /* 81051df0accSAmit Shah * There might be a chance that we missed reclaiming a few 81151df0accSAmit Shah * buffers in the window of the port getting previously closed 81251df0accSAmit Shah * and opening now. 81351df0accSAmit Shah */ 81451df0accSAmit Shah reclaim_consumed_buffers(port); 81551df0accSAmit Shah spin_unlock_irq(&port->outvq_lock); 81651df0accSAmit Shah 81751df0accSAmit Shah nonseekable_open(inode, filp); 81851df0accSAmit Shah 81951df0accSAmit Shah /* Notify host of port being opened */ 82051df0accSAmit Shah send_control_msg(filp->private_data, VIRTIO_CONSOLE_PORT_OPEN, 1); 82151df0accSAmit Shah 82251df0accSAmit Shah return 0; 82351df0accSAmit Shah out: 82451df0accSAmit Shah kref_put(&port->kref, remove_port); 82551df0accSAmit Shah return ret; 82651df0accSAmit Shah } 82751df0accSAmit Shah 82851df0accSAmit Shah static int port_fops_fasync(int fd, struct file *filp, int mode) 82951df0accSAmit Shah { 83051df0accSAmit Shah struct port *port; 83151df0accSAmit Shah 83251df0accSAmit Shah port = filp->private_data; 83351df0accSAmit Shah return fasync_helper(fd, filp, mode, &port->async_queue); 83451df0accSAmit Shah } 83551df0accSAmit Shah 83651df0accSAmit Shah /* 83751df0accSAmit Shah * The file operations that we support: programs in the guest can open 83851df0accSAmit Shah * a console device, read from it, write to it, poll for data and 83951df0accSAmit Shah * close it. The devices are at 84051df0accSAmit Shah * /dev/vport<device number>p<port number> 84151df0accSAmit Shah */ 84251df0accSAmit Shah static const struct file_operations port_fops = { 84351df0accSAmit Shah .owner = THIS_MODULE, 84451df0accSAmit Shah .open = port_fops_open, 84551df0accSAmit Shah .read = port_fops_read, 84651df0accSAmit Shah .write = port_fops_write, 84751df0accSAmit Shah .poll = port_fops_poll, 84851df0accSAmit Shah .release = port_fops_release, 84951df0accSAmit Shah .fasync = port_fops_fasync, 85051df0accSAmit Shah .llseek = no_llseek, 85151df0accSAmit Shah }; 85251df0accSAmit Shah 85351df0accSAmit Shah /* 85451df0accSAmit Shah * The put_chars() callback is pretty straightforward. 85551df0accSAmit Shah * 85651df0accSAmit Shah * We turn the characters into a scatter-gather list, add it to the 85751df0accSAmit Shah * output queue and then kick the Host. Then we sit here waiting for 85851df0accSAmit Shah * it to finish: inefficient in theory, but in practice 85951df0accSAmit Shah * implementations will do it immediately (lguest's Launcher does). 86051df0accSAmit Shah */ 86151df0accSAmit Shah static int put_chars(u32 vtermno, const char *buf, int count) 86251df0accSAmit Shah { 86351df0accSAmit Shah struct port *port; 86451df0accSAmit Shah 86551df0accSAmit Shah if (unlikely(early_put_chars)) 86651df0accSAmit Shah return early_put_chars(vtermno, buf, count); 86751df0accSAmit Shah 86851df0accSAmit Shah port = find_port_by_vtermno(vtermno); 86951df0accSAmit Shah if (!port) 87051df0accSAmit Shah return -EPIPE; 87151df0accSAmit Shah 87251df0accSAmit Shah return send_buf(port, (void *)buf, count, false); 87351df0accSAmit Shah } 87451df0accSAmit Shah 87551df0accSAmit Shah /* 87651df0accSAmit Shah * get_chars() is the callback from the hvc_console infrastructure 87751df0accSAmit Shah * when an interrupt is received. 87851df0accSAmit Shah * 87951df0accSAmit Shah * We call out to fill_readbuf that gets us the required data from the 88051df0accSAmit Shah * buffers that are queued up. 88151df0accSAmit Shah */ 88251df0accSAmit Shah static int get_chars(u32 vtermno, char *buf, int count) 88351df0accSAmit Shah { 88451df0accSAmit Shah struct port *port; 88551df0accSAmit Shah 88651df0accSAmit Shah /* If we've not set up the port yet, we have no input to give. */ 88751df0accSAmit Shah if (unlikely(early_put_chars)) 88851df0accSAmit Shah return 0; 88951df0accSAmit Shah 89051df0accSAmit Shah port = find_port_by_vtermno(vtermno); 89151df0accSAmit Shah if (!port) 89251df0accSAmit Shah return -EPIPE; 89351df0accSAmit Shah 89451df0accSAmit Shah /* If we don't have an input queue yet, we can't get input. */ 89551df0accSAmit Shah BUG_ON(!port->in_vq); 89651df0accSAmit Shah 89751df0accSAmit Shah return fill_readbuf(port, buf, count, false); 89851df0accSAmit Shah } 89951df0accSAmit Shah 90051df0accSAmit Shah static void resize_console(struct port *port) 90151df0accSAmit Shah { 90251df0accSAmit Shah struct virtio_device *vdev; 90351df0accSAmit Shah 90451df0accSAmit Shah /* The port could have been hot-unplugged */ 90551df0accSAmit Shah if (!port || !is_console_port(port)) 90651df0accSAmit Shah return; 90751df0accSAmit Shah 90851df0accSAmit Shah vdev = port->portdev->vdev; 90951df0accSAmit Shah if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE)) 91051df0accSAmit Shah hvc_resize(port->cons.hvc, port->cons.ws); 91151df0accSAmit Shah } 91251df0accSAmit Shah 91351df0accSAmit Shah /* We set the configuration at this point, since we now have a tty */ 91451df0accSAmit Shah static int notifier_add_vio(struct hvc_struct *hp, int data) 91551df0accSAmit Shah { 91651df0accSAmit Shah struct port *port; 91751df0accSAmit Shah 91851df0accSAmit Shah port = find_port_by_vtermno(hp->vtermno); 91951df0accSAmit Shah if (!port) 92051df0accSAmit Shah return -EINVAL; 92151df0accSAmit Shah 92251df0accSAmit Shah hp->irq_requested = 1; 92351df0accSAmit Shah resize_console(port); 92451df0accSAmit Shah 92551df0accSAmit Shah return 0; 92651df0accSAmit Shah } 92751df0accSAmit Shah 92851df0accSAmit Shah static void notifier_del_vio(struct hvc_struct *hp, int data) 92951df0accSAmit Shah { 93051df0accSAmit Shah hp->irq_requested = 0; 93151df0accSAmit Shah } 93251df0accSAmit Shah 93351df0accSAmit Shah /* The operations for console ports. */ 93451df0accSAmit Shah static const struct hv_ops hv_ops = { 93551df0accSAmit Shah .get_chars = get_chars, 93651df0accSAmit Shah .put_chars = put_chars, 93751df0accSAmit Shah .notifier_add = notifier_add_vio, 93851df0accSAmit Shah .notifier_del = notifier_del_vio, 93951df0accSAmit Shah .notifier_hangup = notifier_del_vio, 94051df0accSAmit Shah }; 94151df0accSAmit Shah 94251df0accSAmit Shah /* 94351df0accSAmit Shah * Console drivers are initialized very early so boot messages can go 94451df0accSAmit Shah * out, so we do things slightly differently from the generic virtio 94551df0accSAmit Shah * initialization of the net and block drivers. 94651df0accSAmit Shah * 94751df0accSAmit Shah * At this stage, the console is output-only. It's too early to set 94851df0accSAmit Shah * up a virtqueue, so we let the drivers do some boutique early-output 94951df0accSAmit Shah * thing. 95051df0accSAmit Shah */ 95151df0accSAmit Shah int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int)) 95251df0accSAmit Shah { 95351df0accSAmit Shah early_put_chars = put_chars; 95451df0accSAmit Shah return hvc_instantiate(0, 0, &hv_ops); 95551df0accSAmit Shah } 95651df0accSAmit Shah 95751df0accSAmit Shah int init_port_console(struct port *port) 95851df0accSAmit Shah { 95951df0accSAmit Shah int ret; 96051df0accSAmit Shah 96151df0accSAmit Shah /* 96251df0accSAmit Shah * The Host's telling us this port is a console port. Hook it 96351df0accSAmit Shah * up with an hvc console. 96451df0accSAmit Shah * 96551df0accSAmit Shah * To set up and manage our virtual console, we call 96651df0accSAmit Shah * hvc_alloc(). 96751df0accSAmit Shah * 96851df0accSAmit Shah * The first argument of hvc_alloc() is the virtual console 96951df0accSAmit Shah * number. The second argument is the parameter for the 97051df0accSAmit Shah * notification mechanism (like irq number). We currently 97151df0accSAmit Shah * leave this as zero, virtqueues have implicit notifications. 97251df0accSAmit Shah * 97351df0accSAmit Shah * The third argument is a "struct hv_ops" containing the 97451df0accSAmit Shah * put_chars() get_chars(), notifier_add() and notifier_del() 97551df0accSAmit Shah * pointers. The final argument is the output buffer size: we 97651df0accSAmit Shah * can do any size, so we put PAGE_SIZE here. 97751df0accSAmit Shah */ 97851df0accSAmit Shah port->cons.vtermno = pdrvdata.next_vtermno; 97951df0accSAmit Shah 98051df0accSAmit Shah port->cons.hvc = hvc_alloc(port->cons.vtermno, 0, &hv_ops, PAGE_SIZE); 98151df0accSAmit Shah if (IS_ERR(port->cons.hvc)) { 98251df0accSAmit Shah ret = PTR_ERR(port->cons.hvc); 98351df0accSAmit Shah dev_err(port->dev, 98451df0accSAmit Shah "error %d allocating hvc for port\n", ret); 98551df0accSAmit Shah port->cons.hvc = NULL; 98651df0accSAmit Shah return ret; 98751df0accSAmit Shah } 98851df0accSAmit Shah spin_lock_irq(&pdrvdata_lock); 98951df0accSAmit Shah pdrvdata.next_vtermno++; 99051df0accSAmit Shah list_add_tail(&port->cons.list, &pdrvdata.consoles); 99151df0accSAmit Shah spin_unlock_irq(&pdrvdata_lock); 99251df0accSAmit Shah port->guest_connected = true; 99351df0accSAmit Shah 99451df0accSAmit Shah /* 99551df0accSAmit Shah * Start using the new console output if this is the first 99651df0accSAmit Shah * console to come up. 99751df0accSAmit Shah */ 99851df0accSAmit Shah if (early_put_chars) 99951df0accSAmit Shah early_put_chars = NULL; 100051df0accSAmit Shah 100151df0accSAmit Shah /* Notify host of port being opened */ 100251df0accSAmit Shah send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1); 100351df0accSAmit Shah 100451df0accSAmit Shah return 0; 100551df0accSAmit Shah } 100651df0accSAmit Shah 100751df0accSAmit Shah static ssize_t show_port_name(struct device *dev, 100851df0accSAmit Shah struct device_attribute *attr, char *buffer) 100951df0accSAmit Shah { 101051df0accSAmit Shah struct port *port; 101151df0accSAmit Shah 101251df0accSAmit Shah port = dev_get_drvdata(dev); 101351df0accSAmit Shah 101451df0accSAmit Shah return sprintf(buffer, "%s\n", port->name); 101551df0accSAmit Shah } 101651df0accSAmit Shah 101751df0accSAmit Shah static DEVICE_ATTR(name, S_IRUGO, show_port_name, NULL); 101851df0accSAmit Shah 101951df0accSAmit Shah static struct attribute *port_sysfs_entries[] = { 102051df0accSAmit Shah &dev_attr_name.attr, 102151df0accSAmit Shah NULL 102251df0accSAmit Shah }; 102351df0accSAmit Shah 102451df0accSAmit Shah static struct attribute_group port_attribute_group = { 102551df0accSAmit Shah .name = NULL, /* put in device directory */ 102651df0accSAmit Shah .attrs = port_sysfs_entries, 102751df0accSAmit Shah }; 102851df0accSAmit Shah 102951df0accSAmit Shah static int debugfs_open(struct inode *inode, struct file *filp) 103051df0accSAmit Shah { 103151df0accSAmit Shah filp->private_data = inode->i_private; 103251df0accSAmit Shah return 0; 103351df0accSAmit Shah } 103451df0accSAmit Shah 103551df0accSAmit Shah static ssize_t debugfs_read(struct file *filp, char __user *ubuf, 103651df0accSAmit Shah size_t count, loff_t *offp) 103751df0accSAmit Shah { 103851df0accSAmit Shah struct port *port; 103951df0accSAmit Shah char *buf; 104051df0accSAmit Shah ssize_t ret, out_offset, out_count; 104151df0accSAmit Shah 104251df0accSAmit Shah out_count = 1024; 104351df0accSAmit Shah buf = kmalloc(out_count, GFP_KERNEL); 104451df0accSAmit Shah if (!buf) 104551df0accSAmit Shah return -ENOMEM; 104651df0accSAmit Shah 104751df0accSAmit Shah port = filp->private_data; 104851df0accSAmit Shah out_offset = 0; 104951df0accSAmit Shah out_offset += snprintf(buf + out_offset, out_count, 105051df0accSAmit Shah "name: %s\n", port->name ? port->name : ""); 105151df0accSAmit Shah out_offset += snprintf(buf + out_offset, out_count - out_offset, 105251df0accSAmit Shah "guest_connected: %d\n", port->guest_connected); 105351df0accSAmit Shah out_offset += snprintf(buf + out_offset, out_count - out_offset, 105451df0accSAmit Shah "host_connected: %d\n", port->host_connected); 105551df0accSAmit Shah out_offset += snprintf(buf + out_offset, out_count - out_offset, 105651df0accSAmit Shah "outvq_full: %d\n", port->outvq_full); 105751df0accSAmit Shah out_offset += snprintf(buf + out_offset, out_count - out_offset, 105851df0accSAmit Shah "is_console: %s\n", 105951df0accSAmit Shah is_console_port(port) ? "yes" : "no"); 106051df0accSAmit Shah out_offset += snprintf(buf + out_offset, out_count - out_offset, 106151df0accSAmit Shah "console_vtermno: %u\n", port->cons.vtermno); 106251df0accSAmit Shah 106351df0accSAmit Shah ret = simple_read_from_buffer(ubuf, count, offp, buf, out_offset); 106451df0accSAmit Shah kfree(buf); 106551df0accSAmit Shah return ret; 106651df0accSAmit Shah } 106751df0accSAmit Shah 106851df0accSAmit Shah static const struct file_operations port_debugfs_ops = { 106951df0accSAmit Shah .owner = THIS_MODULE, 107051df0accSAmit Shah .open = debugfs_open, 107151df0accSAmit Shah .read = debugfs_read, 107251df0accSAmit Shah }; 107351df0accSAmit Shah 107451df0accSAmit Shah static void set_console_size(struct port *port, u16 rows, u16 cols) 107551df0accSAmit Shah { 107651df0accSAmit Shah if (!port || !is_console_port(port)) 107751df0accSAmit Shah return; 107851df0accSAmit Shah 107951df0accSAmit Shah port->cons.ws.ws_row = rows; 108051df0accSAmit Shah port->cons.ws.ws_col = cols; 108151df0accSAmit Shah } 108251df0accSAmit Shah 108351df0accSAmit Shah static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock) 108451df0accSAmit Shah { 108551df0accSAmit Shah struct port_buffer *buf; 108651df0accSAmit Shah unsigned int nr_added_bufs; 108751df0accSAmit Shah int ret; 108851df0accSAmit Shah 108951df0accSAmit Shah nr_added_bufs = 0; 109051df0accSAmit Shah do { 109151df0accSAmit Shah buf = alloc_buf(PAGE_SIZE); 109251df0accSAmit Shah if (!buf) 109351df0accSAmit Shah break; 109451df0accSAmit Shah 109551df0accSAmit Shah spin_lock_irq(lock); 109651df0accSAmit Shah ret = add_inbuf(vq, buf); 109751df0accSAmit Shah if (ret < 0) { 109851df0accSAmit Shah spin_unlock_irq(lock); 109951df0accSAmit Shah free_buf(buf); 110051df0accSAmit Shah break; 110151df0accSAmit Shah } 110251df0accSAmit Shah nr_added_bufs++; 110351df0accSAmit Shah spin_unlock_irq(lock); 110451df0accSAmit Shah } while (ret > 0); 110551df0accSAmit Shah 110651df0accSAmit Shah return nr_added_bufs; 110751df0accSAmit Shah } 110851df0accSAmit Shah 110951df0accSAmit Shah static void send_sigio_to_port(struct port *port) 111051df0accSAmit Shah { 111151df0accSAmit Shah if (port->async_queue && port->guest_connected) 111251df0accSAmit Shah kill_fasync(&port->async_queue, SIGIO, POLL_OUT); 111351df0accSAmit Shah } 111451df0accSAmit Shah 111551df0accSAmit Shah static int add_port(struct ports_device *portdev, u32 id) 111651df0accSAmit Shah { 111751df0accSAmit Shah char debugfs_name[16]; 111851df0accSAmit Shah struct port *port; 111951df0accSAmit Shah struct port_buffer *buf; 112051df0accSAmit Shah dev_t devt; 112151df0accSAmit Shah unsigned int nr_added_bufs; 112251df0accSAmit Shah int err; 112351df0accSAmit Shah 112451df0accSAmit Shah port = kmalloc(sizeof(*port), GFP_KERNEL); 112551df0accSAmit Shah if (!port) { 112651df0accSAmit Shah err = -ENOMEM; 112751df0accSAmit Shah goto fail; 112851df0accSAmit Shah } 112951df0accSAmit Shah kref_init(&port->kref); 113051df0accSAmit Shah 113151df0accSAmit Shah port->portdev = portdev; 113251df0accSAmit Shah port->id = id; 113351df0accSAmit Shah 113451df0accSAmit Shah port->name = NULL; 113551df0accSAmit Shah port->inbuf = NULL; 113651df0accSAmit Shah port->cons.hvc = NULL; 113751df0accSAmit Shah port->async_queue = NULL; 113851df0accSAmit Shah 113951df0accSAmit Shah port->cons.ws.ws_row = port->cons.ws.ws_col = 0; 114051df0accSAmit Shah 114151df0accSAmit Shah port->host_connected = port->guest_connected = false; 114251df0accSAmit Shah 114351df0accSAmit Shah port->outvq_full = false; 114451df0accSAmit Shah 114551df0accSAmit Shah port->in_vq = portdev->in_vqs[port->id]; 114651df0accSAmit Shah port->out_vq = portdev->out_vqs[port->id]; 114751df0accSAmit Shah 114851df0accSAmit Shah port->cdev = cdev_alloc(); 114951df0accSAmit Shah if (!port->cdev) { 115051df0accSAmit Shah dev_err(&port->portdev->vdev->dev, "Error allocating cdev\n"); 115151df0accSAmit Shah err = -ENOMEM; 115251df0accSAmit Shah goto free_port; 115351df0accSAmit Shah } 115451df0accSAmit Shah port->cdev->ops = &port_fops; 115551df0accSAmit Shah 115651df0accSAmit Shah devt = MKDEV(portdev->chr_major, id); 115751df0accSAmit Shah err = cdev_add(port->cdev, devt, 1); 115851df0accSAmit Shah if (err < 0) { 115951df0accSAmit Shah dev_err(&port->portdev->vdev->dev, 116051df0accSAmit Shah "Error %d adding cdev for port %u\n", err, id); 116151df0accSAmit Shah goto free_cdev; 116251df0accSAmit Shah } 116351df0accSAmit Shah port->dev = device_create(pdrvdata.class, &port->portdev->vdev->dev, 116451df0accSAmit Shah devt, port, "vport%up%u", 116551df0accSAmit Shah port->portdev->drv_index, id); 116651df0accSAmit Shah if (IS_ERR(port->dev)) { 116751df0accSAmit Shah err = PTR_ERR(port->dev); 116851df0accSAmit Shah dev_err(&port->portdev->vdev->dev, 116951df0accSAmit Shah "Error %d creating device for port %u\n", 117051df0accSAmit Shah err, id); 117151df0accSAmit Shah goto free_cdev; 117251df0accSAmit Shah } 117351df0accSAmit Shah 117451df0accSAmit Shah spin_lock_init(&port->inbuf_lock); 117551df0accSAmit Shah spin_lock_init(&port->outvq_lock); 117651df0accSAmit Shah init_waitqueue_head(&port->waitqueue); 117751df0accSAmit Shah 117851df0accSAmit Shah /* Fill the in_vq with buffers so the host can send us data. */ 117951df0accSAmit Shah nr_added_bufs = fill_queue(port->in_vq, &port->inbuf_lock); 118051df0accSAmit Shah if (!nr_added_bufs) { 118151df0accSAmit Shah dev_err(port->dev, "Error allocating inbufs\n"); 118251df0accSAmit Shah err = -ENOMEM; 118351df0accSAmit Shah goto free_device; 118451df0accSAmit Shah } 118551df0accSAmit Shah 118651df0accSAmit Shah /* 118751df0accSAmit Shah * If we're not using multiport support, this has to be a console port 118851df0accSAmit Shah */ 118951df0accSAmit Shah if (!use_multiport(port->portdev)) { 119051df0accSAmit Shah err = init_port_console(port); 119151df0accSAmit Shah if (err) 119251df0accSAmit Shah goto free_inbufs; 119351df0accSAmit Shah } 119451df0accSAmit Shah 119551df0accSAmit Shah spin_lock_irq(&portdev->ports_lock); 119651df0accSAmit Shah list_add_tail(&port->list, &port->portdev->ports); 119751df0accSAmit Shah spin_unlock_irq(&portdev->ports_lock); 119851df0accSAmit Shah 119951df0accSAmit Shah /* 120051df0accSAmit Shah * Tell the Host we're set so that it can send us various 120151df0accSAmit Shah * configuration parameters for this port (eg, port name, 120251df0accSAmit Shah * caching, whether this is a console port, etc.) 120351df0accSAmit Shah */ 120451df0accSAmit Shah send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1); 120551df0accSAmit Shah 120651df0accSAmit Shah if (pdrvdata.debugfs_dir) { 120751df0accSAmit Shah /* 120851df0accSAmit Shah * Finally, create the debugfs file that we can use to 120951df0accSAmit Shah * inspect a port's state at any time 121051df0accSAmit Shah */ 121151df0accSAmit Shah sprintf(debugfs_name, "vport%up%u", 121251df0accSAmit Shah port->portdev->drv_index, id); 121351df0accSAmit Shah port->debugfs_file = debugfs_create_file(debugfs_name, 0444, 121451df0accSAmit Shah pdrvdata.debugfs_dir, 121551df0accSAmit Shah port, 121651df0accSAmit Shah &port_debugfs_ops); 121751df0accSAmit Shah } 121851df0accSAmit Shah return 0; 121951df0accSAmit Shah 122051df0accSAmit Shah free_inbufs: 122151df0accSAmit Shah while ((buf = virtqueue_detach_unused_buf(port->in_vq))) 122251df0accSAmit Shah free_buf(buf); 122351df0accSAmit Shah free_device: 122451df0accSAmit Shah device_destroy(pdrvdata.class, port->dev->devt); 122551df0accSAmit Shah free_cdev: 122651df0accSAmit Shah cdev_del(port->cdev); 122751df0accSAmit Shah free_port: 122851df0accSAmit Shah kfree(port); 122951df0accSAmit Shah fail: 123051df0accSAmit Shah /* The host might want to notify management sw about port add failure */ 123151df0accSAmit Shah __send_control_msg(portdev, id, VIRTIO_CONSOLE_PORT_READY, 0); 123251df0accSAmit Shah return err; 123351df0accSAmit Shah } 123451df0accSAmit Shah 123551df0accSAmit Shah /* No users remain, remove all port-specific data. */ 123651df0accSAmit Shah static void remove_port(struct kref *kref) 123751df0accSAmit Shah { 123851df0accSAmit Shah struct port *port; 123951df0accSAmit Shah 124051df0accSAmit Shah port = container_of(kref, struct port, kref); 124151df0accSAmit Shah 124251df0accSAmit Shah sysfs_remove_group(&port->dev->kobj, &port_attribute_group); 124351df0accSAmit Shah device_destroy(pdrvdata.class, port->dev->devt); 124451df0accSAmit Shah cdev_del(port->cdev); 124551df0accSAmit Shah 124651df0accSAmit Shah kfree(port->name); 124751df0accSAmit Shah 124851df0accSAmit Shah debugfs_remove(port->debugfs_file); 124951df0accSAmit Shah 125051df0accSAmit Shah kfree(port); 125151df0accSAmit Shah } 125251df0accSAmit Shah 125351df0accSAmit Shah /* 125451df0accSAmit Shah * Port got unplugged. Remove port from portdev's list and drop the 125551df0accSAmit Shah * kref reference. If no userspace has this port opened, it will 125651df0accSAmit Shah * result in immediate removal the port. 125751df0accSAmit Shah */ 125851df0accSAmit Shah static void unplug_port(struct port *port) 125951df0accSAmit Shah { 126051df0accSAmit Shah struct port_buffer *buf; 126151df0accSAmit Shah 126251df0accSAmit Shah spin_lock_irq(&port->portdev->ports_lock); 126351df0accSAmit Shah list_del(&port->list); 126451df0accSAmit Shah spin_unlock_irq(&port->portdev->ports_lock); 126551df0accSAmit Shah 126651df0accSAmit Shah if (port->guest_connected) { 126751df0accSAmit Shah port->guest_connected = false; 126851df0accSAmit Shah port->host_connected = false; 126951df0accSAmit Shah wake_up_interruptible(&port->waitqueue); 127051df0accSAmit Shah 127151df0accSAmit Shah /* Let the app know the port is going down. */ 127251df0accSAmit Shah send_sigio_to_port(port); 127351df0accSAmit Shah } 127451df0accSAmit Shah 127551df0accSAmit Shah if (is_console_port(port)) { 127651df0accSAmit Shah spin_lock_irq(&pdrvdata_lock); 127751df0accSAmit Shah list_del(&port->cons.list); 127851df0accSAmit Shah spin_unlock_irq(&pdrvdata_lock); 127951df0accSAmit Shah hvc_remove(port->cons.hvc); 128051df0accSAmit Shah } 128151df0accSAmit Shah 128251df0accSAmit Shah /* Remove unused data this port might have received. */ 128351df0accSAmit Shah discard_port_data(port); 128451df0accSAmit Shah 128551df0accSAmit Shah reclaim_consumed_buffers(port); 128651df0accSAmit Shah 128751df0accSAmit Shah /* Remove buffers we queued up for the Host to send us data in. */ 128851df0accSAmit Shah while ((buf = virtqueue_detach_unused_buf(port->in_vq))) 128951df0accSAmit Shah free_buf(buf); 129051df0accSAmit Shah 129151df0accSAmit Shah /* 129251df0accSAmit Shah * We should just assume the device itself has gone off -- 129351df0accSAmit Shah * else a close on an open port later will try to send out a 129451df0accSAmit Shah * control message. 129551df0accSAmit Shah */ 129651df0accSAmit Shah port->portdev = NULL; 129751df0accSAmit Shah 129851df0accSAmit Shah /* 129951df0accSAmit Shah * Locks around here are not necessary - a port can't be 130051df0accSAmit Shah * opened after we removed the port struct from ports_list 130151df0accSAmit Shah * above. 130251df0accSAmit Shah */ 130351df0accSAmit Shah kref_put(&port->kref, remove_port); 130451df0accSAmit Shah } 130551df0accSAmit Shah 130651df0accSAmit Shah /* Any private messages that the Host and Guest want to share */ 130751df0accSAmit Shah static void handle_control_message(struct ports_device *portdev, 130851df0accSAmit Shah struct port_buffer *buf) 130951df0accSAmit Shah { 131051df0accSAmit Shah struct virtio_console_control *cpkt; 131151df0accSAmit Shah struct port *port; 131251df0accSAmit Shah size_t name_size; 131351df0accSAmit Shah int err; 131451df0accSAmit Shah 131551df0accSAmit Shah cpkt = (struct virtio_console_control *)(buf->buf + buf->offset); 131651df0accSAmit Shah 131751df0accSAmit Shah port = find_port_by_id(portdev, cpkt->id); 131851df0accSAmit Shah if (!port && cpkt->event != VIRTIO_CONSOLE_PORT_ADD) { 131951df0accSAmit Shah /* No valid header at start of buffer. Drop it. */ 132051df0accSAmit Shah dev_dbg(&portdev->vdev->dev, 132151df0accSAmit Shah "Invalid index %u in control packet\n", cpkt->id); 132251df0accSAmit Shah return; 132351df0accSAmit Shah } 132451df0accSAmit Shah 132551df0accSAmit Shah switch (cpkt->event) { 132651df0accSAmit Shah case VIRTIO_CONSOLE_PORT_ADD: 132751df0accSAmit Shah if (port) { 132851df0accSAmit Shah dev_dbg(&portdev->vdev->dev, 132951df0accSAmit Shah "Port %u already added\n", port->id); 133051df0accSAmit Shah send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1); 133151df0accSAmit Shah break; 133251df0accSAmit Shah } 133351df0accSAmit Shah if (cpkt->id >= portdev->config.max_nr_ports) { 133451df0accSAmit Shah dev_warn(&portdev->vdev->dev, 133551df0accSAmit Shah "Request for adding port with out-of-bound id %u, max. supported id: %u\n", 133651df0accSAmit Shah cpkt->id, portdev->config.max_nr_ports - 1); 133751df0accSAmit Shah break; 133851df0accSAmit Shah } 133951df0accSAmit Shah add_port(portdev, cpkt->id); 134051df0accSAmit Shah break; 134151df0accSAmit Shah case VIRTIO_CONSOLE_PORT_REMOVE: 134251df0accSAmit Shah unplug_port(port); 134351df0accSAmit Shah break; 134451df0accSAmit Shah case VIRTIO_CONSOLE_CONSOLE_PORT: 134551df0accSAmit Shah if (!cpkt->value) 134651df0accSAmit Shah break; 134751df0accSAmit Shah if (is_console_port(port)) 134851df0accSAmit Shah break; 134951df0accSAmit Shah 135051df0accSAmit Shah init_port_console(port); 135151df0accSAmit Shah /* 135251df0accSAmit Shah * Could remove the port here in case init fails - but 135351df0accSAmit Shah * have to notify the host first. 135451df0accSAmit Shah */ 135551df0accSAmit Shah break; 135651df0accSAmit Shah case VIRTIO_CONSOLE_RESIZE: { 135751df0accSAmit Shah struct { 135851df0accSAmit Shah __u16 rows; 135951df0accSAmit Shah __u16 cols; 136051df0accSAmit Shah } size; 136151df0accSAmit Shah 136251df0accSAmit Shah if (!is_console_port(port)) 136351df0accSAmit Shah break; 136451df0accSAmit Shah 136551df0accSAmit Shah memcpy(&size, buf->buf + buf->offset + sizeof(*cpkt), 136651df0accSAmit Shah sizeof(size)); 136751df0accSAmit Shah set_console_size(port, size.rows, size.cols); 136851df0accSAmit Shah 136951df0accSAmit Shah port->cons.hvc->irq_requested = 1; 137051df0accSAmit Shah resize_console(port); 137151df0accSAmit Shah break; 137251df0accSAmit Shah } 137351df0accSAmit Shah case VIRTIO_CONSOLE_PORT_OPEN: 137451df0accSAmit Shah port->host_connected = cpkt->value; 137551df0accSAmit Shah wake_up_interruptible(&port->waitqueue); 137651df0accSAmit Shah /* 137751df0accSAmit Shah * If the host port got closed and the host had any 137851df0accSAmit Shah * unconsumed buffers, we'll be able to reclaim them 137951df0accSAmit Shah * now. 138051df0accSAmit Shah */ 138151df0accSAmit Shah spin_lock_irq(&port->outvq_lock); 138251df0accSAmit Shah reclaim_consumed_buffers(port); 138351df0accSAmit Shah spin_unlock_irq(&port->outvq_lock); 138451df0accSAmit Shah 138551df0accSAmit Shah /* 138651df0accSAmit Shah * If the guest is connected, it'll be interested in 138751df0accSAmit Shah * knowing the host connection state changed. 138851df0accSAmit Shah */ 138951df0accSAmit Shah send_sigio_to_port(port); 139051df0accSAmit Shah break; 139151df0accSAmit Shah case VIRTIO_CONSOLE_PORT_NAME: 139251df0accSAmit Shah /* 1393291024efSAmit Shah * If we woke up after hibernation, we can get this 1394291024efSAmit Shah * again. Skip it in that case. 1395291024efSAmit Shah */ 1396291024efSAmit Shah if (port->name) 1397291024efSAmit Shah break; 1398291024efSAmit Shah 1399291024efSAmit Shah /* 140051df0accSAmit Shah * Skip the size of the header and the cpkt to get the size 140151df0accSAmit Shah * of the name that was sent 140251df0accSAmit Shah */ 140351df0accSAmit Shah name_size = buf->len - buf->offset - sizeof(*cpkt) + 1; 140451df0accSAmit Shah 140551df0accSAmit Shah port->name = kmalloc(name_size, GFP_KERNEL); 140651df0accSAmit Shah if (!port->name) { 140751df0accSAmit Shah dev_err(port->dev, 140851df0accSAmit Shah "Not enough space to store port name\n"); 140951df0accSAmit Shah break; 141051df0accSAmit Shah } 141151df0accSAmit Shah strncpy(port->name, buf->buf + buf->offset + sizeof(*cpkt), 141251df0accSAmit Shah name_size - 1); 141351df0accSAmit Shah port->name[name_size - 1] = 0; 141451df0accSAmit Shah 141551df0accSAmit Shah /* 141651df0accSAmit Shah * Since we only have one sysfs attribute, 'name', 141751df0accSAmit Shah * create it only if we have a name for the port. 141851df0accSAmit Shah */ 141951df0accSAmit Shah err = sysfs_create_group(&port->dev->kobj, 142051df0accSAmit Shah &port_attribute_group); 142151df0accSAmit Shah if (err) { 142251df0accSAmit Shah dev_err(port->dev, 142351df0accSAmit Shah "Error %d creating sysfs device attributes\n", 142451df0accSAmit Shah err); 142551df0accSAmit Shah } else { 142651df0accSAmit Shah /* 142751df0accSAmit Shah * Generate a udev event so that appropriate 142851df0accSAmit Shah * symlinks can be created based on udev 142951df0accSAmit Shah * rules. 143051df0accSAmit Shah */ 143151df0accSAmit Shah kobject_uevent(&port->dev->kobj, KOBJ_CHANGE); 143251df0accSAmit Shah } 143351df0accSAmit Shah break; 143451df0accSAmit Shah } 143551df0accSAmit Shah } 143651df0accSAmit Shah 143751df0accSAmit Shah static void control_work_handler(struct work_struct *work) 143851df0accSAmit Shah { 143951df0accSAmit Shah struct ports_device *portdev; 144051df0accSAmit Shah struct virtqueue *vq; 144151df0accSAmit Shah struct port_buffer *buf; 144251df0accSAmit Shah unsigned int len; 144351df0accSAmit Shah 144451df0accSAmit Shah portdev = container_of(work, struct ports_device, control_work); 144551df0accSAmit Shah vq = portdev->c_ivq; 144651df0accSAmit Shah 144751df0accSAmit Shah spin_lock(&portdev->cvq_lock); 144851df0accSAmit Shah while ((buf = virtqueue_get_buf(vq, &len))) { 144951df0accSAmit Shah spin_unlock(&portdev->cvq_lock); 145051df0accSAmit Shah 145151df0accSAmit Shah buf->len = len; 145251df0accSAmit Shah buf->offset = 0; 145351df0accSAmit Shah 145451df0accSAmit Shah handle_control_message(portdev, buf); 145551df0accSAmit Shah 145651df0accSAmit Shah spin_lock(&portdev->cvq_lock); 145751df0accSAmit Shah if (add_inbuf(portdev->c_ivq, buf) < 0) { 145851df0accSAmit Shah dev_warn(&portdev->vdev->dev, 145951df0accSAmit Shah "Error adding buffer to queue\n"); 146051df0accSAmit Shah free_buf(buf); 146151df0accSAmit Shah } 146251df0accSAmit Shah } 146351df0accSAmit Shah spin_unlock(&portdev->cvq_lock); 146451df0accSAmit Shah } 146551df0accSAmit Shah 1466ce86d35dSLinus Torvalds static void out_intr(struct virtqueue *vq) 1467ce86d35dSLinus Torvalds { 1468ce86d35dSLinus Torvalds struct port *port; 1469ce86d35dSLinus Torvalds 1470ce86d35dSLinus Torvalds port = find_port_by_vq(vq->vdev->priv, vq); 1471ce86d35dSLinus Torvalds if (!port) 1472ce86d35dSLinus Torvalds return; 1473ce86d35dSLinus Torvalds 1474ce86d35dSLinus Torvalds wake_up_interruptible(&port->waitqueue); 1475ce86d35dSLinus Torvalds } 1476ce86d35dSLinus Torvalds 147751df0accSAmit Shah static void in_intr(struct virtqueue *vq) 147851df0accSAmit Shah { 147951df0accSAmit Shah struct port *port; 148051df0accSAmit Shah unsigned long flags; 148151df0accSAmit Shah 148251df0accSAmit Shah port = find_port_by_vq(vq->vdev->priv, vq); 148351df0accSAmit Shah if (!port) 148451df0accSAmit Shah return; 148551df0accSAmit Shah 148651df0accSAmit Shah spin_lock_irqsave(&port->inbuf_lock, flags); 148751df0accSAmit Shah port->inbuf = get_inbuf(port); 148851df0accSAmit Shah 148951df0accSAmit Shah /* 149051df0accSAmit Shah * Don't queue up data when port is closed. This condition 149151df0accSAmit Shah * can be reached when a console port is not yet connected (no 149251df0accSAmit Shah * tty is spawned) and the host sends out data to console 149351df0accSAmit Shah * ports. For generic serial ports, the host won't 149451df0accSAmit Shah * (shouldn't) send data till the guest is connected. 149551df0accSAmit Shah */ 149651df0accSAmit Shah if (!port->guest_connected) 149751df0accSAmit Shah discard_port_data(port); 149851df0accSAmit Shah 149951df0accSAmit Shah spin_unlock_irqrestore(&port->inbuf_lock, flags); 150051df0accSAmit Shah 150151df0accSAmit Shah wake_up_interruptible(&port->waitqueue); 150251df0accSAmit Shah 150351df0accSAmit Shah /* Send a SIGIO indicating new data in case the process asked for it */ 150451df0accSAmit Shah send_sigio_to_port(port); 150551df0accSAmit Shah 150651df0accSAmit Shah if (is_console_port(port) && hvc_poll(port->cons.hvc)) 150751df0accSAmit Shah hvc_kick(); 150851df0accSAmit Shah } 150951df0accSAmit Shah 151051df0accSAmit Shah static void control_intr(struct virtqueue *vq) 151151df0accSAmit Shah { 151251df0accSAmit Shah struct ports_device *portdev; 151351df0accSAmit Shah 151451df0accSAmit Shah portdev = vq->vdev->priv; 151551df0accSAmit Shah schedule_work(&portdev->control_work); 151651df0accSAmit Shah } 151751df0accSAmit Shah 151851df0accSAmit Shah static void config_intr(struct virtio_device *vdev) 151951df0accSAmit Shah { 152051df0accSAmit Shah struct ports_device *portdev; 152151df0accSAmit Shah 152251df0accSAmit Shah portdev = vdev->priv; 152351df0accSAmit Shah 152451df0accSAmit Shah if (!use_multiport(portdev)) { 152551df0accSAmit Shah struct port *port; 152651df0accSAmit Shah u16 rows, cols; 152751df0accSAmit Shah 152851df0accSAmit Shah vdev->config->get(vdev, 152951df0accSAmit Shah offsetof(struct virtio_console_config, cols), 153051df0accSAmit Shah &cols, sizeof(u16)); 153151df0accSAmit Shah vdev->config->get(vdev, 153251df0accSAmit Shah offsetof(struct virtio_console_config, rows), 153351df0accSAmit Shah &rows, sizeof(u16)); 153451df0accSAmit Shah 153551df0accSAmit Shah port = find_port_by_id(portdev, 0); 153651df0accSAmit Shah set_console_size(port, rows, cols); 153751df0accSAmit Shah 153851df0accSAmit Shah /* 153951df0accSAmit Shah * We'll use this way of resizing only for legacy 154051df0accSAmit Shah * support. For newer userspace 154151df0accSAmit Shah * (VIRTIO_CONSOLE_F_MULTPORT+), use control messages 154251df0accSAmit Shah * to indicate console size changes so that it can be 154351df0accSAmit Shah * done per-port. 154451df0accSAmit Shah */ 154551df0accSAmit Shah resize_console(port); 154651df0accSAmit Shah } 154751df0accSAmit Shah } 154851df0accSAmit Shah 154951df0accSAmit Shah static int init_vqs(struct ports_device *portdev) 155051df0accSAmit Shah { 155151df0accSAmit Shah vq_callback_t **io_callbacks; 155251df0accSAmit Shah char **io_names; 155351df0accSAmit Shah struct virtqueue **vqs; 155451df0accSAmit Shah u32 i, j, nr_ports, nr_queues; 155551df0accSAmit Shah int err; 155651df0accSAmit Shah 155751df0accSAmit Shah nr_ports = portdev->config.max_nr_ports; 155851df0accSAmit Shah nr_queues = use_multiport(portdev) ? (nr_ports + 1) * 2 : 2; 155951df0accSAmit Shah 156051df0accSAmit Shah vqs = kmalloc(nr_queues * sizeof(struct virtqueue *), GFP_KERNEL); 156151df0accSAmit Shah io_callbacks = kmalloc(nr_queues * sizeof(vq_callback_t *), GFP_KERNEL); 156251df0accSAmit Shah io_names = kmalloc(nr_queues * sizeof(char *), GFP_KERNEL); 156351df0accSAmit Shah portdev->in_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *), 156451df0accSAmit Shah GFP_KERNEL); 156551df0accSAmit Shah portdev->out_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *), 156651df0accSAmit Shah GFP_KERNEL); 156751df0accSAmit Shah if (!vqs || !io_callbacks || !io_names || !portdev->in_vqs || 156851df0accSAmit Shah !portdev->out_vqs) { 156951df0accSAmit Shah err = -ENOMEM; 157051df0accSAmit Shah goto free; 157151df0accSAmit Shah } 157251df0accSAmit Shah 157351df0accSAmit Shah /* 157451df0accSAmit Shah * For backward compat (newer host but older guest), the host 157551df0accSAmit Shah * spawns a console port first and also inits the vqs for port 157651df0accSAmit Shah * 0 before others. 157751df0accSAmit Shah */ 157851df0accSAmit Shah j = 0; 157951df0accSAmit Shah io_callbacks[j] = in_intr; 1580ce86d35dSLinus Torvalds io_callbacks[j + 1] = out_intr; 158151df0accSAmit Shah io_names[j] = "input"; 158251df0accSAmit Shah io_names[j + 1] = "output"; 158351df0accSAmit Shah j += 2; 158451df0accSAmit Shah 158551df0accSAmit Shah if (use_multiport(portdev)) { 158651df0accSAmit Shah io_callbacks[j] = control_intr; 158751df0accSAmit Shah io_callbacks[j + 1] = NULL; 158851df0accSAmit Shah io_names[j] = "control-i"; 158951df0accSAmit Shah io_names[j + 1] = "control-o"; 159051df0accSAmit Shah 159151df0accSAmit Shah for (i = 1; i < nr_ports; i++) { 159251df0accSAmit Shah j += 2; 159351df0accSAmit Shah io_callbacks[j] = in_intr; 1594ce86d35dSLinus Torvalds io_callbacks[j + 1] = out_intr; 159551df0accSAmit Shah io_names[j] = "input"; 159651df0accSAmit Shah io_names[j + 1] = "output"; 159751df0accSAmit Shah } 159851df0accSAmit Shah } 159951df0accSAmit Shah /* Find the queues. */ 160051df0accSAmit Shah err = portdev->vdev->config->find_vqs(portdev->vdev, nr_queues, vqs, 160151df0accSAmit Shah io_callbacks, 160251df0accSAmit Shah (const char **)io_names); 160351df0accSAmit Shah if (err) 160451df0accSAmit Shah goto free; 160551df0accSAmit Shah 160651df0accSAmit Shah j = 0; 160751df0accSAmit Shah portdev->in_vqs[0] = vqs[0]; 160851df0accSAmit Shah portdev->out_vqs[0] = vqs[1]; 160951df0accSAmit Shah j += 2; 161051df0accSAmit Shah if (use_multiport(portdev)) { 161151df0accSAmit Shah portdev->c_ivq = vqs[j]; 161251df0accSAmit Shah portdev->c_ovq = vqs[j + 1]; 161351df0accSAmit Shah 161451df0accSAmit Shah for (i = 1; i < nr_ports; i++) { 161551df0accSAmit Shah j += 2; 161651df0accSAmit Shah portdev->in_vqs[i] = vqs[j]; 161751df0accSAmit Shah portdev->out_vqs[i] = vqs[j + 1]; 161851df0accSAmit Shah } 161951df0accSAmit Shah } 162051df0accSAmit Shah kfree(io_names); 162151df0accSAmit Shah kfree(io_callbacks); 162251df0accSAmit Shah kfree(vqs); 162351df0accSAmit Shah 162451df0accSAmit Shah return 0; 162551df0accSAmit Shah 162651df0accSAmit Shah free: 162751df0accSAmit Shah kfree(portdev->out_vqs); 162851df0accSAmit Shah kfree(portdev->in_vqs); 162951df0accSAmit Shah kfree(io_names); 163051df0accSAmit Shah kfree(io_callbacks); 163151df0accSAmit Shah kfree(vqs); 163251df0accSAmit Shah 163351df0accSAmit Shah return err; 163451df0accSAmit Shah } 163551df0accSAmit Shah 163651df0accSAmit Shah static const struct file_operations portdev_fops = { 163751df0accSAmit Shah .owner = THIS_MODULE, 163851df0accSAmit Shah }; 163951df0accSAmit Shah 164051df0accSAmit Shah /* 164151df0accSAmit Shah * Once we're further in boot, we get probed like any other virtio 164251df0accSAmit Shah * device. 164351df0accSAmit Shah * 164451df0accSAmit Shah * If the host also supports multiple console ports, we check the 164551df0accSAmit Shah * config space to see how many ports the host has spawned. We 164651df0accSAmit Shah * initialize each port found. 164751df0accSAmit Shah */ 164851df0accSAmit Shah static int __devinit virtcons_probe(struct virtio_device *vdev) 164951df0accSAmit Shah { 165051df0accSAmit Shah struct ports_device *portdev; 165151df0accSAmit Shah int err; 165251df0accSAmit Shah bool multiport; 165351df0accSAmit Shah 165451df0accSAmit Shah portdev = kmalloc(sizeof(*portdev), GFP_KERNEL); 165551df0accSAmit Shah if (!portdev) { 165651df0accSAmit Shah err = -ENOMEM; 165751df0accSAmit Shah goto fail; 165851df0accSAmit Shah } 165951df0accSAmit Shah 166051df0accSAmit Shah /* Attach this portdev to this virtio_device, and vice-versa. */ 166151df0accSAmit Shah portdev->vdev = vdev; 166251df0accSAmit Shah vdev->priv = portdev; 166351df0accSAmit Shah 166451df0accSAmit Shah spin_lock_irq(&pdrvdata_lock); 166551df0accSAmit Shah portdev->drv_index = pdrvdata.index++; 166651df0accSAmit Shah spin_unlock_irq(&pdrvdata_lock); 166751df0accSAmit Shah 166851df0accSAmit Shah portdev->chr_major = register_chrdev(0, "virtio-portsdev", 166951df0accSAmit Shah &portdev_fops); 167051df0accSAmit Shah if (portdev->chr_major < 0) { 167151df0accSAmit Shah dev_err(&vdev->dev, 167251df0accSAmit Shah "Error %d registering chrdev for device %u\n", 167351df0accSAmit Shah portdev->chr_major, portdev->drv_index); 167451df0accSAmit Shah err = portdev->chr_major; 167551df0accSAmit Shah goto free; 167651df0accSAmit Shah } 167751df0accSAmit Shah 167851df0accSAmit Shah multiport = false; 167951df0accSAmit Shah portdev->config.max_nr_ports = 1; 168051c6d61aSSasha Levin if (virtio_config_val(vdev, VIRTIO_CONSOLE_F_MULTIPORT, 168151c6d61aSSasha Levin offsetof(struct virtio_console_config, 168251df0accSAmit Shah max_nr_ports), 168351c6d61aSSasha Levin &portdev->config.max_nr_ports) == 0) 168451c6d61aSSasha Levin multiport = true; 168551df0accSAmit Shah 168651df0accSAmit Shah err = init_vqs(portdev); 168751df0accSAmit Shah if (err < 0) { 168851df0accSAmit Shah dev_err(&vdev->dev, "Error %d initializing vqs\n", err); 168951df0accSAmit Shah goto free_chrdev; 169051df0accSAmit Shah } 169151df0accSAmit Shah 169251df0accSAmit Shah spin_lock_init(&portdev->ports_lock); 169351df0accSAmit Shah INIT_LIST_HEAD(&portdev->ports); 169451df0accSAmit Shah 169551df0accSAmit Shah if (multiport) { 169651df0accSAmit Shah unsigned int nr_added_bufs; 169751df0accSAmit Shah 169851df0accSAmit Shah spin_lock_init(&portdev->cvq_lock); 169951df0accSAmit Shah INIT_WORK(&portdev->control_work, &control_work_handler); 170051df0accSAmit Shah 170151df0accSAmit Shah nr_added_bufs = fill_queue(portdev->c_ivq, &portdev->cvq_lock); 170251df0accSAmit Shah if (!nr_added_bufs) { 170351df0accSAmit Shah dev_err(&vdev->dev, 170451df0accSAmit Shah "Error allocating buffers for control queue\n"); 170551df0accSAmit Shah err = -ENOMEM; 170651df0accSAmit Shah goto free_vqs; 170751df0accSAmit Shah } 170851df0accSAmit Shah } else { 170951df0accSAmit Shah /* 171051df0accSAmit Shah * For backward compatibility: Create a console port 171151df0accSAmit Shah * if we're running on older host. 171251df0accSAmit Shah */ 171351df0accSAmit Shah add_port(portdev, 0); 171451df0accSAmit Shah } 171551df0accSAmit Shah 171651df0accSAmit Shah spin_lock_irq(&pdrvdata_lock); 171751df0accSAmit Shah list_add_tail(&portdev->list, &pdrvdata.portdevs); 171851df0accSAmit Shah spin_unlock_irq(&pdrvdata_lock); 171951df0accSAmit Shah 172051df0accSAmit Shah __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID, 172151df0accSAmit Shah VIRTIO_CONSOLE_DEVICE_READY, 1); 172251df0accSAmit Shah return 0; 172351df0accSAmit Shah 172451df0accSAmit Shah free_vqs: 172551df0accSAmit Shah /* The host might want to notify mgmt sw about device add failure */ 172651df0accSAmit Shah __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID, 172751df0accSAmit Shah VIRTIO_CONSOLE_DEVICE_READY, 0); 172851df0accSAmit Shah vdev->config->del_vqs(vdev); 172951df0accSAmit Shah kfree(portdev->in_vqs); 173051df0accSAmit Shah kfree(portdev->out_vqs); 173151df0accSAmit Shah free_chrdev: 173251df0accSAmit Shah unregister_chrdev(portdev->chr_major, "virtio-portsdev"); 173351df0accSAmit Shah free: 173451df0accSAmit Shah kfree(portdev); 173551df0accSAmit Shah fail: 173651df0accSAmit Shah return err; 173751df0accSAmit Shah } 173851df0accSAmit Shah 173951df0accSAmit Shah static void virtcons_remove(struct virtio_device *vdev) 174051df0accSAmit Shah { 174151df0accSAmit Shah struct ports_device *portdev; 174251df0accSAmit Shah struct port *port, *port2; 174351df0accSAmit Shah 174451df0accSAmit Shah portdev = vdev->priv; 174551df0accSAmit Shah 174651df0accSAmit Shah spin_lock_irq(&pdrvdata_lock); 174751df0accSAmit Shah list_del(&portdev->list); 174851df0accSAmit Shah spin_unlock_irq(&pdrvdata_lock); 174951df0accSAmit Shah 175051df0accSAmit Shah /* Disable interrupts for vqs */ 175151df0accSAmit Shah vdev->config->reset(vdev); 175251df0accSAmit Shah /* Finish up work that's lined up */ 175351df0accSAmit Shah cancel_work_sync(&portdev->control_work); 175451df0accSAmit Shah 175551df0accSAmit Shah list_for_each_entry_safe(port, port2, &portdev->ports, list) 175651df0accSAmit Shah unplug_port(port); 175751df0accSAmit Shah 175851df0accSAmit Shah unregister_chrdev(portdev->chr_major, "virtio-portsdev"); 175951df0accSAmit Shah 176051df0accSAmit Shah /* 176151df0accSAmit Shah * When yanking out a device, we immediately lose the 176251df0accSAmit Shah * (device-side) queues. So there's no point in keeping the 176351df0accSAmit Shah * guest side around till we drop our final reference. This 176451df0accSAmit Shah * also means that any ports which are in an open state will 176551df0accSAmit Shah * have to just stop using the port, as the vqs are going 176651df0accSAmit Shah * away. 176751df0accSAmit Shah */ 176851df0accSAmit Shah if (use_multiport(portdev)) { 176951df0accSAmit Shah struct port_buffer *buf; 177051df0accSAmit Shah unsigned int len; 177151df0accSAmit Shah 177251df0accSAmit Shah while ((buf = virtqueue_get_buf(portdev->c_ivq, &len))) 177351df0accSAmit Shah free_buf(buf); 177451df0accSAmit Shah 177551df0accSAmit Shah while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq))) 177651df0accSAmit Shah free_buf(buf); 177751df0accSAmit Shah } 177851df0accSAmit Shah 177951df0accSAmit Shah vdev->config->del_vqs(vdev); 178051df0accSAmit Shah kfree(portdev->in_vqs); 178151df0accSAmit Shah kfree(portdev->out_vqs); 178251df0accSAmit Shah 178351df0accSAmit Shah kfree(portdev); 178451df0accSAmit Shah } 178551df0accSAmit Shah 178651df0accSAmit Shah static struct virtio_device_id id_table[] = { 178751df0accSAmit Shah { VIRTIO_ID_CONSOLE, VIRTIO_DEV_ANY_ID }, 178851df0accSAmit Shah { 0 }, 178951df0accSAmit Shah }; 179051df0accSAmit Shah 179151df0accSAmit Shah static unsigned int features[] = { 179251df0accSAmit Shah VIRTIO_CONSOLE_F_SIZE, 179351df0accSAmit Shah VIRTIO_CONSOLE_F_MULTIPORT, 179451df0accSAmit Shah }; 179551df0accSAmit Shah 179651df0accSAmit Shah static struct virtio_driver virtio_console = { 179751df0accSAmit Shah .feature_table = features, 179851df0accSAmit Shah .feature_table_size = ARRAY_SIZE(features), 179951df0accSAmit Shah .driver.name = KBUILD_MODNAME, 180051df0accSAmit Shah .driver.owner = THIS_MODULE, 180151df0accSAmit Shah .id_table = id_table, 180251df0accSAmit Shah .probe = virtcons_probe, 180351df0accSAmit Shah .remove = virtcons_remove, 180451df0accSAmit Shah .config_changed = config_intr, 180551df0accSAmit Shah }; 180651df0accSAmit Shah 180751df0accSAmit Shah static int __init init(void) 180851df0accSAmit Shah { 180951df0accSAmit Shah int err; 181051df0accSAmit Shah 181151df0accSAmit Shah pdrvdata.class = class_create(THIS_MODULE, "virtio-ports"); 181251df0accSAmit Shah if (IS_ERR(pdrvdata.class)) { 181351df0accSAmit Shah err = PTR_ERR(pdrvdata.class); 181451df0accSAmit Shah pr_err("Error %d creating virtio-ports class\n", err); 181551df0accSAmit Shah return err; 181651df0accSAmit Shah } 181751df0accSAmit Shah 181851df0accSAmit Shah pdrvdata.debugfs_dir = debugfs_create_dir("virtio-ports", NULL); 181951df0accSAmit Shah if (!pdrvdata.debugfs_dir) { 182051df0accSAmit Shah pr_warning("Error %ld creating debugfs dir for virtio-ports\n", 182151df0accSAmit Shah PTR_ERR(pdrvdata.debugfs_dir)); 182251df0accSAmit Shah } 182351df0accSAmit Shah INIT_LIST_HEAD(&pdrvdata.consoles); 182451df0accSAmit Shah INIT_LIST_HEAD(&pdrvdata.portdevs); 182551df0accSAmit Shah 182651df0accSAmit Shah return register_virtio_driver(&virtio_console); 182751df0accSAmit Shah } 182851df0accSAmit Shah 182951df0accSAmit Shah static void __exit fini(void) 183051df0accSAmit Shah { 183151df0accSAmit Shah unregister_virtio_driver(&virtio_console); 183251df0accSAmit Shah 183351df0accSAmit Shah class_destroy(pdrvdata.class); 183451df0accSAmit Shah if (pdrvdata.debugfs_dir) 183551df0accSAmit Shah debugfs_remove_recursive(pdrvdata.debugfs_dir); 183651df0accSAmit Shah } 183751df0accSAmit Shah module_init(init); 183851df0accSAmit Shah module_exit(fini); 183951df0accSAmit Shah 184051df0accSAmit Shah MODULE_DEVICE_TABLE(virtio, id_table); 184151df0accSAmit Shah MODULE_DESCRIPTION("Virtio console driver"); 184251df0accSAmit Shah MODULE_LICENSE("GPL"); 1843