drivers/gpio/gpio-virtio.c

Source file repositories/reference/linux-study-clean/drivers/gpio/gpio-virtio.c

File Facts

System
Linux kernel
Corpus path
drivers/gpio/gpio-virtio.c
Extension
.c
Size
17607 bytes
Lines
674
Domain
Driver Families
Bucket
drivers/gpio
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct virtio_gpio_line {
	struct mutex lock; /* Protects line operation */
	struct completion completion;

	unsigned int rxlen;

	__dma_from_device_group_begin();
	struct virtio_gpio_request req;
	struct virtio_gpio_response res;
	__dma_from_device_group_end();
};

struct vgpio_irq_line {
	u8 type;
	bool disabled;
	bool masked;
	bool queued;
	bool update_pending;
	bool queue_pending;

	__dma_from_device_group_begin();
	struct virtio_gpio_irq_request ireq;
	struct virtio_gpio_irq_response ires;
	__dma_from_device_group_end();
};

struct virtio_gpio {
	struct virtio_device *vdev;
	struct mutex lock; /* Protects virtqueue operation */
	struct gpio_chip gc;
	struct virtio_gpio_line *lines;
	struct virtqueue *request_vq;

	/* irq support */
	struct virtqueue *event_vq;
	struct mutex irq_lock; /* Protects irq operation */
	raw_spinlock_t eventq_lock; /* Protects queuing of the buffer */
	struct vgpio_irq_line *irq_lines;
};

static int _virtio_gpio_req(struct virtio_gpio *vgpio, u16 type, u16 gpio,
			    u8 txvalue, u8 *rxvalue, void *response, u32 rxlen)
{
	struct virtio_gpio_line *line = &vgpio->lines[gpio];
	struct virtio_gpio_request *req = &line->req;
	struct virtio_gpio_response *res = response;
	struct scatterlist *sgs[2], req_sg, res_sg;
	struct device *dev = &vgpio->vdev->dev;
	int ret;

	/*
	 * Prevent concurrent requests for the same line since we have
	 * pre-allocated request/response buffers for each GPIO line. Moreover
	 * Linux always accesses a GPIO line sequentially, so this locking shall
	 * always go through without any delays.
	 */
	mutex_lock(&line->lock);

	req->type = cpu_to_le16(type);
	req->gpio = cpu_to_le16(gpio);
	req->value = cpu_to_le32(txvalue);

	sg_init_one(&req_sg, req, sizeof(*req));
	sg_init_one(&res_sg, res, rxlen);
	sgs[0] = &req_sg;
	sgs[1] = &res_sg;

	line->rxlen = 0;
	reinit_completion(&line->completion);

	/*
	 * Virtqueue callers need to ensure they don't call its APIs with other
	 * virtqueue operations at the same time.
	 */
	mutex_lock(&vgpio->lock);
	ret = virtqueue_add_sgs(vgpio->request_vq, sgs, 1, 1, line, GFP_KERNEL);
	if (ret) {
		dev_err(dev, "failed to add request to vq\n");
		mutex_unlock(&vgpio->lock);
		goto out;
	}

	virtqueue_kick(vgpio->request_vq);
	mutex_unlock(&vgpio->lock);

	wait_for_completion(&line->completion);

	if (unlikely(res->status != VIRTIO_GPIO_STATUS_OK)) {
		dev_err(dev, "GPIO request failed: %d\n", gpio);
		ret = -EINVAL;

Annotation

Implementation Notes