1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | // |
3 | // em28xx-vbi.c - VBI driver for em28xx |
4 | // |
5 | // Copyright (C) 2009 Devin Heitmueller <dheitmueller@kernellabs.com> |
6 | // |
7 | // This work was sponsored by EyeMagnet Limited. |
8 | |
9 | #include "em28xx.h" |
10 | |
11 | #include <linux/kernel.h> |
12 | #include <linux/module.h> |
13 | #include <linux/hardirq.h> |
14 | #include <linux/init.h> |
15 | #include <linux/usb.h> |
16 | |
17 | #include "em28xx-v4l.h" |
18 | |
19 | /* ------------------------------------------------------------------ */ |
20 | |
21 | static int vbi_queue_setup(struct vb2_queue *vq, |
22 | unsigned int *nbuffers, unsigned int *nplanes, |
23 | unsigned int sizes[], struct device *alloc_devs[]) |
24 | { |
25 | struct em28xx *dev = vb2_get_drv_priv(q: vq); |
26 | struct em28xx_v4l2 *v4l2 = dev->v4l2; |
27 | unsigned long size = v4l2->vbi_width * v4l2->vbi_height * 2; |
28 | |
29 | if (*nbuffers < 2) |
30 | *nbuffers = 2; |
31 | |
32 | if (*nplanes) { |
33 | if (sizes[0] < size) |
34 | return -EINVAL; |
35 | size = sizes[0]; |
36 | } |
37 | |
38 | *nplanes = 1; |
39 | sizes[0] = size; |
40 | |
41 | return 0; |
42 | } |
43 | |
44 | static int vbi_buffer_prepare(struct vb2_buffer *vb) |
45 | { |
46 | struct em28xx *dev = vb2_get_drv_priv(q: vb->vb2_queue); |
47 | struct em28xx_v4l2 *v4l2 = dev->v4l2; |
48 | unsigned long size; |
49 | |
50 | size = v4l2->vbi_width * v4l2->vbi_height * 2; |
51 | |
52 | if (vb2_plane_size(vb, plane_no: 0) < size) { |
53 | dev_info(&dev->intf->dev, |
54 | "%s data will not fit into plane (%lu < %lu)\n" , |
55 | __func__, vb2_plane_size(vb, 0), size); |
56 | return -EINVAL; |
57 | } |
58 | vb2_set_plane_payload(vb, plane_no: 0, size); |
59 | |
60 | return 0; |
61 | } |
62 | |
63 | static void |
64 | vbi_buffer_queue(struct vb2_buffer *vb) |
65 | { |
66 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); |
67 | struct em28xx *dev = vb2_get_drv_priv(q: vb->vb2_queue); |
68 | struct em28xx_buffer *buf = |
69 | container_of(vbuf, struct em28xx_buffer, vb); |
70 | struct em28xx_dmaqueue *vbiq = &dev->vbiq; |
71 | unsigned long flags = 0; |
72 | |
73 | buf->mem = vb2_plane_vaddr(vb, plane_no: 0); |
74 | buf->length = vb2_plane_size(vb, plane_no: 0); |
75 | |
76 | spin_lock_irqsave(&dev->slock, flags); |
77 | list_add_tail(new: &buf->list, head: &vbiq->active); |
78 | spin_unlock_irqrestore(lock: &dev->slock, flags); |
79 | } |
80 | |
81 | const struct vb2_ops em28xx_vbi_qops = { |
82 | .queue_setup = vbi_queue_setup, |
83 | .buf_prepare = vbi_buffer_prepare, |
84 | .buf_queue = vbi_buffer_queue, |
85 | .start_streaming = em28xx_start_analog_streaming, |
86 | .stop_streaming = em28xx_stop_vbi_streaming, |
87 | .wait_prepare = vb2_ops_wait_prepare, |
88 | .wait_finish = vb2_ops_wait_finish, |
89 | }; |
90 | |