static int command_write()

in xen-pciback/conf_space_header.c [62:140]


static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
{
	struct xen_pcibk_dev_data *dev_data;
	int err;
	u16 val;
	struct pci_cmd_info *cmd = data;

	dev_data = pci_get_drvdata(dev);
	if (!pci_is_enabled(dev) && is_enable_cmd(value)) {
		dev_dbg(&dev->dev, "enable\n");
		err = pci_enable_device(dev);
		if (err)
			return err;
		if (dev_data)
			dev_data->enable_intx = 1;
	} else if (pci_is_enabled(dev) && !is_enable_cmd(value)) {
		dev_dbg(&dev->dev, "disable\n");
		pci_disable_device(dev);
		if (dev_data)
			dev_data->enable_intx = 0;
	}

	if (!dev->is_busmaster && is_master_cmd(value)) {
		dev_dbg(&dev->dev, "set bus master\n");
		pci_set_master(dev);
	} else if (dev->is_busmaster && !is_master_cmd(value)) {
		dev_dbg(&dev->dev, "clear bus master\n");
		pci_clear_master(dev);
	}

	if (!(cmd->val & PCI_COMMAND_INVALIDATE) &&
	    (value & PCI_COMMAND_INVALIDATE)) {
		dev_dbg(&dev->dev, "enable memory-write-invalidate\n");
		err = pci_set_mwi(dev);
		if (err) {
			dev_warn(&dev->dev, "cannot enable memory-write-invalidate (%d)\n",
				err);
			value &= ~PCI_COMMAND_INVALIDATE;
		}
	} else if ((cmd->val & PCI_COMMAND_INVALIDATE) &&
		   !(value & PCI_COMMAND_INVALIDATE)) {
		dev_dbg(&dev->dev, "disable memory-write-invalidate\n");
		pci_clear_mwi(dev);
	}

	if (dev_data && dev_data->allow_interrupt_control) {
		if ((cmd->val ^ value) & PCI_COMMAND_INTX_DISABLE) {
			if (value & PCI_COMMAND_INTX_DISABLE) {
				pci_intx(dev, 0);
			} else {
				/* Do not allow enabling INTx together with MSI or MSI-X. */
				switch (xen_pcibk_get_interrupt_type(dev)) {
				case INTERRUPT_TYPE_NONE:
					pci_intx(dev, 1);
					break;
				case INTERRUPT_TYPE_INTX:
					break;
				default:
					return PCIBIOS_SET_FAILED;
				}
			}
		}
	}

	cmd->val = value;

	if (!xen_pcibk_permissive && (!dev_data || !dev_data->permissive))
		return 0;

	/* Only allow the guest to control certain bits. */
	err = pci_read_config_word(dev, offset, &val);
	if (err || val == value)
		return err;

	value &= PCI_COMMAND_GUEST;
	value |= val & ~PCI_COMMAND_GUEST;

	return pci_write_config_word(dev, offset, value);
}