]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/virtio/virtio.c
Virtio interface
[linux-2.6-omap-h63xx.git] / drivers / virtio / virtio.c
1 #include <linux/virtio.h>
2 #include <linux/spinlock.h>
3 #include <linux/virtio_config.h>
4
5 static ssize_t device_show(struct device *_d,
6                            struct device_attribute *attr, char *buf)
7 {
8         struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
9         return sprintf(buf, "%hu", dev->id.device);
10 }
11 static ssize_t vendor_show(struct device *_d,
12                            struct device_attribute *attr, char *buf)
13 {
14         struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
15         return sprintf(buf, "%hu", dev->id.vendor);
16 }
17 static ssize_t status_show(struct device *_d,
18                            struct device_attribute *attr, char *buf)
19 {
20         struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
21         return sprintf(buf, "0x%08x", dev->config->get_status(dev));
22 }
23 static struct device_attribute virtio_dev_attrs[] = {
24         __ATTR_RO(device),
25         __ATTR_RO(vendor),
26         __ATTR_RO(status),
27         __ATTR_NULL
28 };
29
30 static inline int virtio_id_match(const struct virtio_device *dev,
31                                   const struct virtio_device_id *id)
32 {
33         if (id->device != dev->id.device)
34                 return 0;
35
36         return id->vendor == VIRTIO_DEV_ANY_ID || id->vendor != dev->id.vendor;
37 }
38
39 /* This looks through all the IDs a driver claims to support.  If any of them
40  * match, we return 1 and the kernel will call virtio_dev_probe(). */
41 static int virtio_dev_match(struct device *_dv, struct device_driver *_dr)
42 {
43         unsigned int i;
44         struct virtio_device *dev = container_of(_dv,struct virtio_device,dev);
45         const struct virtio_device_id *ids;
46
47         ids = container_of(_dr, struct virtio_driver, driver)->id_table;
48         for (i = 0; ids[i].device; i++)
49                 if (virtio_id_match(dev, &ids[i]))
50                         return 1;
51         return 0;
52 }
53
54 static struct bus_type virtio_bus = {
55         .name  = "virtio",
56         .match = virtio_dev_match,
57         .dev_attrs = virtio_dev_attrs,
58 };
59
60 static void add_status(struct virtio_device *dev, unsigned status)
61 {
62         dev->config->set_status(dev, dev->config->get_status(dev) | status);
63 }
64
65 static int virtio_dev_probe(struct device *_d)
66 {
67         int err;
68         struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
69         struct virtio_driver *drv = container_of(dev->dev.driver,
70                                                  struct virtio_driver, driver);
71
72         add_status(dev, VIRTIO_CONFIG_S_DRIVER);
73         err = drv->probe(dev);
74         if (err)
75                 add_status(dev, VIRTIO_CONFIG_S_FAILED);
76         else
77                 add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
78         return err;
79 }
80
81 int register_virtio_driver(struct virtio_driver *driver)
82 {
83         driver->driver.bus = &virtio_bus;
84         driver->driver.probe = virtio_dev_probe;
85         return driver_register(&driver->driver);
86 }
87 EXPORT_SYMBOL_GPL(register_virtio_driver);
88
89 void unregister_virtio_driver(struct virtio_driver *driver)
90 {
91         driver_unregister(&driver->driver);
92 }
93 EXPORT_SYMBOL_GPL(unregister_virtio_driver);
94
95 int register_virtio_device(struct virtio_device *dev)
96 {
97         int err;
98
99         dev->dev.bus = &virtio_bus;
100         sprintf(dev->dev.bus_id, "%u", dev->index);
101
102         /* Acknowledge that we've seen the device. */
103         add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);
104
105         /* device_register() causes the bus infrastructure to look for a
106          * matching driver. */
107         err = device_register(&dev->dev);
108         if (err)
109                 add_status(dev, VIRTIO_CONFIG_S_FAILED);
110         return err;
111 }
112 EXPORT_SYMBOL_GPL(register_virtio_device);
113
114 void unregister_virtio_device(struct virtio_device *dev)
115 {
116         device_unregister(&dev->dev);
117 }
118 EXPORT_SYMBOL_GPL(unregister_virtio_device);
119
120 int __virtio_config_val(struct virtio_device *vdev,
121                         u8 type, void *val, size_t size)
122 {
123         void *token;
124         unsigned int len;
125
126         token = vdev->config->find(vdev, type, &len);
127         if (!token)
128                 return -ENOENT;
129
130         if (len != size)
131                 return -EIO;
132
133         vdev->config->get(vdev, token, val, size);
134         return 0;
135 }
136 EXPORT_SYMBOL_GPL(__virtio_config_val);
137
138 int virtio_use_bit(struct virtio_device *vdev,
139                    void *token, unsigned int len, unsigned int bitnum)
140 {
141         unsigned long bits[16];
142
143         /* This makes it convenient to pass-through find() results. */
144         if (!token)
145                 return 0;
146
147         /* bit not in range of this bitfield? */
148         if (bitnum * 8 >= len / 2)
149                 return 0;
150
151         /* Giant feature bitfields are silly. */
152         BUG_ON(len > sizeof(bits));
153         vdev->config->get(vdev, token, bits, len);
154
155         if (!test_bit(bitnum, bits))
156                 return 0;
157
158         /* Set acknowledge bit, and write it back. */
159         set_bit(bitnum + len * 8 / 2, bits);
160         vdev->config->set(vdev, token, bits, len);
161         return 1;
162 }
163 EXPORT_SYMBOL_GPL(virtio_use_bit);
164
165 static int virtio_init(void)
166 {
167         if (bus_register(&virtio_bus) != 0)
168                 panic("virtio bus registration failed");
169         return 0;
170 }
171 core_initcall(virtio_init);