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;
}