virtio.c 4.3 KB
Newer Older
R
Rusty Russell 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
#include <linux/virtio.h>
#include <linux/spinlock.h>
#include <linux/virtio_config.h>

static ssize_t device_show(struct device *_d,
			   struct device_attribute *attr, char *buf)
{
	struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
	return sprintf(buf, "%hu", dev->id.device);
}
static ssize_t vendor_show(struct device *_d,
			   struct device_attribute *attr, char *buf)
{
	struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
	return sprintf(buf, "%hu", dev->id.vendor);
}
static ssize_t status_show(struct device *_d,
			   struct device_attribute *attr, char *buf)
{
	struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
	return sprintf(buf, "0x%08x", dev->config->get_status(dev));
}
23 24 25 26 27 28 29 30
static ssize_t modalias_show(struct device *_d,
			     struct device_attribute *attr, char *buf)
{
	struct virtio_device *dev = container_of(_d,struct virtio_device,dev);

	return sprintf(buf, "virtio:d%08Xv%08X\n",
		       dev->id.device, dev->id.vendor);
}
R
Rusty Russell 已提交
31 32 33 34
static struct device_attribute virtio_dev_attrs[] = {
	__ATTR_RO(device),
	__ATTR_RO(vendor),
	__ATTR_RO(status),
35
	__ATTR_RO(modalias),
R
Rusty Russell 已提交
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
	__ATTR_NULL
};

static inline int virtio_id_match(const struct virtio_device *dev,
				  const struct virtio_device_id *id)
{
	if (id->device != dev->id.device)
		return 0;

	return id->vendor == VIRTIO_DEV_ANY_ID || id->vendor != dev->id.vendor;
}

/* This looks through all the IDs a driver claims to support.  If any of them
 * match, we return 1 and the kernel will call virtio_dev_probe(). */
static int virtio_dev_match(struct device *_dv, struct device_driver *_dr)
{
	unsigned int i;
	struct virtio_device *dev = container_of(_dv,struct virtio_device,dev);
	const struct virtio_device_id *ids;

	ids = container_of(_dr, struct virtio_driver, driver)->id_table;
	for (i = 0; ids[i].device; i++)
		if (virtio_id_match(dev, &ids[i]))
			return 1;
	return 0;
}

63 64 65 66 67 68 69 70
static int virtio_uevent(struct device *_dv, struct kobj_uevent_env *env)
{
	struct virtio_device *dev = container_of(_dv,struct virtio_device,dev);

	return add_uevent_var(env, "MODALIAS=virtio:d%08Xv%08X",
			      dev->id.device, dev->id.vendor);
}

R
Rusty Russell 已提交
71 72 73 74
static struct bus_type virtio_bus = {
	.name  = "virtio",
	.match = virtio_dev_match,
	.dev_attrs = virtio_dev_attrs,
75
	.uevent = virtio_uevent,
R
Rusty Russell 已提交
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
};

static void add_status(struct virtio_device *dev, unsigned status)
{
	dev->config->set_status(dev, dev->config->get_status(dev) | status);
}

static int virtio_dev_probe(struct device *_d)
{
	int err;
	struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
	struct virtio_driver *drv = container_of(dev->dev.driver,
						 struct virtio_driver, driver);

	add_status(dev, VIRTIO_CONFIG_S_DRIVER);
	err = drv->probe(dev);
	if (err)
		add_status(dev, VIRTIO_CONFIG_S_FAILED);
	else
		add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
	return err;
}

99 100 101 102 103 104 105 106 107 108 109 110
static int virtio_dev_remove(struct device *_d)
{
	struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
	struct virtio_driver *drv = container_of(dev->dev.driver,
						 struct virtio_driver, driver);

	dev->config->set_status(dev, dev->config->get_status(dev)
				& ~VIRTIO_CONFIG_S_DRIVER);
	drv->remove(dev);
	return 0;
}

R
Rusty Russell 已提交
111 112 113 114
int register_virtio_driver(struct virtio_driver *driver)
{
	driver->driver.bus = &virtio_bus;
	driver->driver.probe = virtio_dev_probe;
115
	driver->driver.remove = virtio_dev_remove;
R
Rusty Russell 已提交
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
	return driver_register(&driver->driver);
}
EXPORT_SYMBOL_GPL(register_virtio_driver);

void unregister_virtio_driver(struct virtio_driver *driver)
{
	driver_unregister(&driver->driver);
}
EXPORT_SYMBOL_GPL(unregister_virtio_driver);

int register_virtio_device(struct virtio_device *dev)
{
	int err;

	dev->dev.bus = &virtio_bus;
	sprintf(dev->dev.bus_id, "%u", dev->index);

	/* Acknowledge that we've seen the device. */
	add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);

	/* device_register() causes the bus infrastructure to look for a
	 * matching driver. */
	err = device_register(&dev->dev);
	if (err)
		add_status(dev, VIRTIO_CONFIG_S_FAILED);
	return err;
}
EXPORT_SYMBOL_GPL(register_virtio_device);

void unregister_virtio_device(struct virtio_device *dev)
{
	device_unregister(&dev->dev);
}
EXPORT_SYMBOL_GPL(unregister_virtio_device);

static int virtio_init(void)
{
	if (bus_register(&virtio_bus) != 0)
		panic("virtio bus registration failed");
	return 0;
}
core_initcall(virtio_init);