static int virtio_gpio_probe()

in gpio-virtio.c [540:628]


static int virtio_gpio_probe(struct virtio_device *vdev)
{
	struct virtio_gpio_config config;
	struct device *dev = &vdev->dev;
	struct virtio_gpio *vgpio;
	u32 gpio_names_size;
	u16 ngpio;
	int ret, i;

	vgpio = devm_kzalloc(dev, sizeof(*vgpio), GFP_KERNEL);
	if (!vgpio)
		return -ENOMEM;

	/* Read configuration */
	virtio_cread_bytes(vdev, 0, &config, sizeof(config));
	gpio_names_size = le32_to_cpu(config.gpio_names_size);
	ngpio = le16_to_cpu(config.ngpio);
	if (!ngpio) {
		dev_err(dev, "Number of GPIOs can't be zero\n");
		return -EINVAL;
	}

	vgpio->lines = devm_kcalloc(dev, ngpio, sizeof(*vgpio->lines), GFP_KERNEL);
	if (!vgpio->lines)
		return -ENOMEM;

	for (i = 0; i < ngpio; i++) {
		mutex_init(&vgpio->lines[i].lock);
		init_completion(&vgpio->lines[i].completion);
	}

	mutex_init(&vgpio->lock);
	vdev->priv = vgpio;

	vgpio->vdev			= vdev;
	vgpio->gc.free			= virtio_gpio_free;
	vgpio->gc.get_direction		= virtio_gpio_get_direction;
	vgpio->gc.direction_input	= virtio_gpio_direction_input;
	vgpio->gc.direction_output	= virtio_gpio_direction_output;
	vgpio->gc.get			= virtio_gpio_get;
	vgpio->gc.set			= virtio_gpio_set;
	vgpio->gc.ngpio			= ngpio;
	vgpio->gc.base			= -1; /* Allocate base dynamically */
	vgpio->gc.label			= dev_name(dev);
	vgpio->gc.parent		= dev;
	vgpio->gc.owner			= THIS_MODULE;
	vgpio->gc.can_sleep		= true;

	/* Interrupt support */
	if (virtio_has_feature(vdev, VIRTIO_GPIO_F_IRQ)) {
		vgpio->irq_lines = devm_kcalloc(dev, ngpio, sizeof(*vgpio->irq_lines), GFP_KERNEL);
		if (!vgpio->irq_lines)
			return -ENOMEM;

		/* The event comes from the outside so no parent handler */
		vgpio->gc.irq.parent_handler	= NULL;
		vgpio->gc.irq.num_parents	= 0;
		vgpio->gc.irq.parents		= NULL;
		vgpio->gc.irq.default_type	= IRQ_TYPE_NONE;
		vgpio->gc.irq.handler		= handle_level_irq;
		vgpio->gc.irq.chip		= &vgpio_irq_chip;

		for (i = 0; i < ngpio; i++) {
			vgpio->irq_lines[i].type = VIRTIO_GPIO_IRQ_TYPE_NONE;
			vgpio->irq_lines[i].disabled = true;
			vgpio->irq_lines[i].masked = true;
		}

		mutex_init(&vgpio->irq_lock);
		raw_spin_lock_init(&vgpio->eventq_lock);
	}

	ret = virtio_gpio_alloc_vqs(vgpio, vdev);
	if (ret)
		return ret;

	/* Mark the device ready to perform operations from within probe() */
	virtio_device_ready(vdev);

	vgpio->gc.names = virtio_gpio_get_names(vgpio, gpio_names_size, ngpio);

	ret = gpiochip_add_data(&vgpio->gc, vgpio);
	if (ret) {
		virtio_gpio_free_vqs(vdev);
		dev_err(dev, "Failed to add virtio-gpio controller\n");
	}

	return ret;
}