static void virtio_pci_common_write(void *opaque, hwaddr addr,

                                    uint64_t val, unsigned size)

{

    VirtIOPCIProxy *proxy = opaque;

    VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);



    switch (addr) {

    case VIRTIO_PCI_COMMON_DFSELECT:

        proxy->dfselect = val;

        break;

    case VIRTIO_PCI_COMMON_GFSELECT:

        proxy->gfselect = val;

        break;

    case VIRTIO_PCI_COMMON_GF:

        if (proxy->gfselect <= ARRAY_SIZE(proxy->guest_features)) {

            proxy->guest_features[proxy->gfselect] = val;

            virtio_set_features(vdev,

                                (((uint64_t)proxy->guest_features[1]) << 32) |

                                proxy->guest_features[0]);

        }

        break;

    case VIRTIO_PCI_COMMON_MSIX:

        msix_vector_unuse(&proxy->pci_dev, vdev->config_vector);

        /* Make it possible for guest to discover an error took place. */

        if (msix_vector_use(&proxy->pci_dev, val) < 0) {

            val = VIRTIO_NO_VECTOR;

        }

        vdev->config_vector = val;

        break;

    case VIRTIO_PCI_COMMON_STATUS:

        if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) {

            virtio_pci_stop_ioeventfd(proxy);

        }



        virtio_set_status(vdev, val & 0xFF);



        if (val & VIRTIO_CONFIG_S_DRIVER_OK) {

            virtio_pci_start_ioeventfd(proxy);

        }



        if (vdev->status == 0) {

            virtio_reset(vdev);

            msix_unuse_all_vectors(&proxy->pci_dev);

        }



        break;

    case VIRTIO_PCI_COMMON_Q_SELECT:

        if (val < VIRTIO_QUEUE_MAX) {

            vdev->queue_sel = val;

        }

        break;

    case VIRTIO_PCI_COMMON_Q_SIZE:

        proxy->vqs[vdev->queue_sel].num = val;

        break;

    case VIRTIO_PCI_COMMON_Q_MSIX:

        msix_vector_unuse(&proxy->pci_dev,

                          virtio_queue_vector(vdev, vdev->queue_sel));

        /* Make it possible for guest to discover an error took place. */

        if (msix_vector_use(&proxy->pci_dev, val) < 0) {

            val = VIRTIO_NO_VECTOR;

        }

        virtio_queue_set_vector(vdev, vdev->queue_sel, val);

        break;

    case VIRTIO_PCI_COMMON_Q_ENABLE:

        /* TODO: need a way to put num back on reset. */

        virtio_queue_set_num(vdev, vdev->queue_sel,

                             proxy->vqs[vdev->queue_sel].num);

        virtio_queue_set_rings(vdev, vdev->queue_sel,

                       ((uint64_t)proxy->vqs[vdev->queue_sel].desc[1]) << 32 |

                       proxy->vqs[vdev->queue_sel].desc[0],

                       ((uint64_t)proxy->vqs[vdev->queue_sel].avail[1]) << 32 |

                       proxy->vqs[vdev->queue_sel].avail[0],

                       ((uint64_t)proxy->vqs[vdev->queue_sel].used[1]) << 32 |

                       proxy->vqs[vdev->queue_sel].used[0]);

        break;

    case VIRTIO_PCI_COMMON_Q_DESCLO:

        proxy->vqs[vdev->queue_sel].desc[0] = val;

        break;

    case VIRTIO_PCI_COMMON_Q_DESCHI:

        proxy->vqs[vdev->queue_sel].desc[1] = val;

        break;

    case VIRTIO_PCI_COMMON_Q_AVAILLO:

        proxy->vqs[vdev->queue_sel].avail[0] = val;

        break;

    case VIRTIO_PCI_COMMON_Q_AVAILHI:

        proxy->vqs[vdev->queue_sel].avail[1] = val;

        break;

    case VIRTIO_PCI_COMMON_Q_USEDLO:

        proxy->vqs[vdev->queue_sel].used[0] = val;

        break;

    case VIRTIO_PCI_COMMON_Q_USEDHI:

        proxy->vqs[vdev->queue_sel].used[1] = val;

        break;

    default:

        break;

    }

}
