um: virtio_uml: Allow probing from devicetree
Allow the virtio_uml device to be probed from the devicetree so that sub-devices can be specified using the standard virtio bindings, for example: virtio@1 { compatible = "virtio,uml"; socket-path = "i2c.sock"; virtio-device-id = <0x22>; i2c-controller { compatible = "virtio,device22"; #address-cells = <0x01>; #size-cells = <0x00>; light-sensor@01 { compatible = "ti,opt3001"; reg = <0x01>; }; }; }; Signed-off-by: Vincent Whitchurch <vincent.whitchurch@axis.com> Signed-off-by: Richard Weinberger <richard@nod.at>
This commit is contained in:
Родитель
b31297f04e
Коммит
db0dd9cee8
|
@ -21,6 +21,7 @@
|
||||||
* Based on Virtio MMIO driver by Pawel Moll, copyright 2011-2014, ARM Ltd.
|
* Based on Virtio MMIO driver by Pawel Moll, copyright 2011-2014, ARM Ltd.
|
||||||
*/
|
*/
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/virtio.h>
|
#include <linux/virtio.h>
|
||||||
|
@ -49,6 +50,7 @@ struct virtio_uml_platform_data {
|
||||||
struct virtio_uml_device {
|
struct virtio_uml_device {
|
||||||
struct virtio_device vdev;
|
struct virtio_device vdev;
|
||||||
struct platform_device *pdev;
|
struct platform_device *pdev;
|
||||||
|
struct virtio_uml_platform_data *pdata;
|
||||||
|
|
||||||
spinlock_t sock_lock;
|
spinlock_t sock_lock;
|
||||||
int sock, req_fd, irq;
|
int sock, req_fd, irq;
|
||||||
|
@ -149,7 +151,7 @@ static int vhost_user_recv(struct virtio_uml_device *vu_dev,
|
||||||
if (rc == -ECONNRESET && vu_dev->registered) {
|
if (rc == -ECONNRESET && vu_dev->registered) {
|
||||||
struct virtio_uml_platform_data *pdata;
|
struct virtio_uml_platform_data *pdata;
|
||||||
|
|
||||||
pdata = vu_dev->pdev->dev.platform_data;
|
pdata = vu_dev->pdata;
|
||||||
|
|
||||||
virtio_break_device(&vu_dev->vdev);
|
virtio_break_device(&vu_dev->vdev);
|
||||||
schedule_work(&pdata->conn_broken_wk);
|
schedule_work(&pdata->conn_broken_wk);
|
||||||
|
@ -1115,21 +1117,63 @@ void virtio_uml_set_no_vq_suspend(struct virtio_device *vdev,
|
||||||
no_vq_suspend ? "dis" : "en");
|
no_vq_suspend ? "dis" : "en");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void vu_of_conn_broken(struct work_struct *wk)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We can't remove the device from the devicetree so the only thing we
|
||||||
|
* can do is warn.
|
||||||
|
*/
|
||||||
|
WARN_ON(1);
|
||||||
|
}
|
||||||
|
|
||||||
/* Platform device */
|
/* Platform device */
|
||||||
|
|
||||||
|
static struct virtio_uml_platform_data *
|
||||||
|
virtio_uml_create_pdata(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device_node *np = pdev->dev.of_node;
|
||||||
|
struct virtio_uml_platform_data *pdata;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!np)
|
||||||
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
|
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||||
|
if (!pdata)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
INIT_WORK(&pdata->conn_broken_wk, vu_of_conn_broken);
|
||||||
|
pdata->pdev = pdev;
|
||||||
|
|
||||||
|
ret = of_property_read_string(np, "socket-path", &pdata->socket_path);
|
||||||
|
if (ret)
|
||||||
|
return ERR_PTR(ret);
|
||||||
|
|
||||||
|
ret = of_property_read_u32(np, "virtio-device-id",
|
||||||
|
&pdata->virtio_device_id);
|
||||||
|
if (ret)
|
||||||
|
return ERR_PTR(ret);
|
||||||
|
|
||||||
|
return pdata;
|
||||||
|
}
|
||||||
|
|
||||||
static int virtio_uml_probe(struct platform_device *pdev)
|
static int virtio_uml_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct virtio_uml_platform_data *pdata = pdev->dev.platform_data;
|
struct virtio_uml_platform_data *pdata = pdev->dev.platform_data;
|
||||||
struct virtio_uml_device *vu_dev;
|
struct virtio_uml_device *vu_dev;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (!pdata)
|
if (!pdata) {
|
||||||
return -EINVAL;
|
pdata = virtio_uml_create_pdata(pdev);
|
||||||
|
if (IS_ERR(pdata))
|
||||||
|
return PTR_ERR(pdata);
|
||||||
|
}
|
||||||
|
|
||||||
vu_dev = kzalloc(sizeof(*vu_dev), GFP_KERNEL);
|
vu_dev = kzalloc(sizeof(*vu_dev), GFP_KERNEL);
|
||||||
if (!vu_dev)
|
if (!vu_dev)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
vu_dev->pdata = pdata;
|
||||||
vu_dev->vdev.dev.parent = &pdev->dev;
|
vu_dev->vdev.dev.parent = &pdev->dev;
|
||||||
vu_dev->vdev.dev.release = virtio_uml_release_dev;
|
vu_dev->vdev.dev.release = virtio_uml_release_dev;
|
||||||
vu_dev->vdev.config = &virtio_uml_config_ops;
|
vu_dev->vdev.config = &virtio_uml_config_ops;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче