This patch adds and uses #defines for PCI device classes and subclases, using a new pci_config_set_class() function, similar to the recently added pci_config_set_vendor_id() and pci_config_set_device_id(). Change since v1: fixed compilation of hw/sun4u.c Signed-off-by: Stuart Brady <stuart.brady@gmail.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6491 c046a42c-6fe2-441c-8c8c-71466251a162
		
			
				
	
	
		
			150 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			150 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Virtio Console Device
 | 
						|
 *
 | 
						|
 * Copyright IBM, Corp. 2008
 | 
						|
 *
 | 
						|
 * Authors:
 | 
						|
 *  Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
 | 
						|
 *
 | 
						|
 * This work is licensed under the terms of the GNU GPL, version 2.  See
 | 
						|
 * the COPYING file in the top-level directory.
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
#include "hw.h"
 | 
						|
#include "qemu-char.h"
 | 
						|
#include "virtio.h"
 | 
						|
#include "virtio-console.h"
 | 
						|
 | 
						|
 | 
						|
typedef struct VirtIOConsole
 | 
						|
{
 | 
						|
    VirtIODevice vdev;
 | 
						|
    VirtQueue *ivq, *dvq;
 | 
						|
    CharDriverState *chr;
 | 
						|
} VirtIOConsole;
 | 
						|
 | 
						|
static VirtIOConsole *to_virtio_console(VirtIODevice *vdev)
 | 
						|
{
 | 
						|
    return (VirtIOConsole *)vdev;
 | 
						|
}
 | 
						|
 | 
						|
static void virtio_console_handle_output(VirtIODevice *vdev, VirtQueue *vq)
 | 
						|
{
 | 
						|
    VirtIOConsole *s = to_virtio_console(vdev);
 | 
						|
    VirtQueueElement elem;
 | 
						|
 | 
						|
    while (virtqueue_pop(vq, &elem)) {
 | 
						|
        ssize_t len = 0;
 | 
						|
        int d;
 | 
						|
 | 
						|
        for (d=0; d < elem.out_num; d++)
 | 
						|
            len += qemu_chr_write(s->chr, elem.out_sg[d].iov_base,elem.out_sg[d].iov_len);
 | 
						|
        virtqueue_push(vq, &elem, len);
 | 
						|
        virtio_notify(vdev, vq);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void virtio_console_handle_input(VirtIODevice *vdev, VirtQueue *vq)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
static uint32_t virtio_console_get_features(VirtIODevice *vdev)
 | 
						|
{
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int vcon_can_read(void *opaque)
 | 
						|
{
 | 
						|
    VirtIOConsole *s = (VirtIOConsole *) opaque;
 | 
						|
 | 
						|
    if (!virtio_queue_ready(s->ivq) ||
 | 
						|
        !(s->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK) ||
 | 
						|
        virtio_queue_empty(s->ivq))
 | 
						|
        return 0;
 | 
						|
 | 
						|
    /* current implementations have a page sized buffer.
 | 
						|
     * We fall back to a one byte per read if there is not enough room.
 | 
						|
     * It would be cool to have a function that returns the available byte
 | 
						|
     * instead of checking for a limit */
 | 
						|
    if (virtqueue_avail_bytes(s->ivq, TARGET_PAGE_SIZE, 0))
 | 
						|
        return TARGET_PAGE_SIZE;
 | 
						|
    if (virtqueue_avail_bytes(s->ivq, 1, 0))
 | 
						|
        return 1;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
static void vcon_read(void *opaque, const uint8_t *buf, int size)
 | 
						|
{
 | 
						|
    VirtIOConsole *s = (VirtIOConsole *) opaque;
 | 
						|
    VirtQueueElement elem;
 | 
						|
    int offset = 0;
 | 
						|
 | 
						|
    /* The current kernel implementation has only one outstanding input
 | 
						|
     * buffer of PAGE_SIZE. Nevertheless, this function is prepared to
 | 
						|
     * handle multiple buffers with multiple sg element for input */
 | 
						|
    while (offset < size) {
 | 
						|
        int i = 0;
 | 
						|
        if (!virtqueue_pop(s->ivq, &elem))
 | 
						|
                break;
 | 
						|
        while (offset < size && i < elem.in_num) {
 | 
						|
            int len = MIN(elem.in_sg[i].iov_len, size - offset);
 | 
						|
            memcpy(elem.in_sg[i].iov_base, buf + offset, len);
 | 
						|
            offset += len;
 | 
						|
            i++;
 | 
						|
        }
 | 
						|
        virtqueue_push(s->ivq, &elem, size);
 | 
						|
    }
 | 
						|
    virtio_notify(&s->vdev, s->ivq);
 | 
						|
}
 | 
						|
 | 
						|
static void vcon_event(void *opaque, int event)
 | 
						|
{
 | 
						|
    /* we will ignore any event for the time being */
 | 
						|
}
 | 
						|
 | 
						|
static void virtio_console_save(QEMUFile *f, void *opaque)
 | 
						|
{
 | 
						|
    VirtIOConsole *s = opaque;
 | 
						|
 | 
						|
    virtio_save(&s->vdev, f);
 | 
						|
}
 | 
						|
 | 
						|
static int virtio_console_load(QEMUFile *f, void *opaque, int version_id)
 | 
						|
{
 | 
						|
    VirtIOConsole *s = opaque;
 | 
						|
 | 
						|
    if (version_id != 1)
 | 
						|
        return -EINVAL;
 | 
						|
 | 
						|
    virtio_load(&s->vdev, f);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
void *virtio_console_init(PCIBus *bus, CharDriverState *chr)
 | 
						|
{
 | 
						|
    VirtIOConsole *s;
 | 
						|
 | 
						|
    s = (VirtIOConsole *)virtio_init_pci(bus, "virtio-console",
 | 
						|
                                         PCI_VENDOR_ID_REDHAT_QUMRANET,
 | 
						|
                                         PCI_DEVICE_ID_VIRTIO_CONSOLE,
 | 
						|
                                         PCI_VENDOR_ID_REDHAT_QUMRANET,
 | 
						|
                                         VIRTIO_ID_CONSOLE,
 | 
						|
                                         PCI_CLASS_DISPLAY_OTHER, 0x00,
 | 
						|
                                         0, sizeof(VirtIOConsole));
 | 
						|
    if (s == NULL)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    s->vdev.get_features = virtio_console_get_features;
 | 
						|
 | 
						|
    s->ivq = virtio_add_queue(&s->vdev, 128, virtio_console_handle_input);
 | 
						|
    s->dvq = virtio_add_queue(&s->vdev, 128, virtio_console_handle_output);
 | 
						|
 | 
						|
    s->chr = chr;
 | 
						|
    qemu_chr_add_handlers(chr, vcon_can_read, vcon_read, vcon_event, s);
 | 
						|
 | 
						|
    register_savevm("virtio-console", -1, 1, virtio_console_save, virtio_console_load, s);
 | 
						|
 | 
						|
    return &s->vdev;
 | 
						|
}
 |