diff options
Diffstat (limited to 'drivers/media/video/em28xx/em28xx-vbi.c')
-rw-r--r-- | drivers/media/video/em28xx/em28xx-vbi.c | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/drivers/media/video/em28xx/em28xx-vbi.c b/drivers/media/video/em28xx/em28xx-vbi.c new file mode 100644 index 000000000000..b5802d4cb623 --- /dev/null +++ b/drivers/media/video/em28xx/em28xx-vbi.c | |||
@@ -0,0 +1,150 @@ | |||
1 | /* | ||
2 | em28xx-vbi.c - VBI driver for em28xx | ||
3 | |||
4 | Copyright (C) 2009 Devin Heitmueller <dheitmueller@kernellabs.com> | ||
5 | |||
6 | This work was sponsored by EyeMagnet Limited. | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2 of the License, or | ||
11 | (at your option) any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; if not, write to the Free Software | ||
20 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | 02110-1301, USA. | ||
22 | */ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/slab.h> | ||
28 | |||
29 | #include "em28xx.h" | ||
30 | |||
31 | static unsigned int vbibufs = 5; | ||
32 | module_param(vbibufs,int,0644); | ||
33 | MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32"); | ||
34 | |||
35 | static unsigned int vbi_debug; | ||
36 | module_param(vbi_debug,int,0644); | ||
37 | MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]"); | ||
38 | |||
39 | #define dprintk(level,fmt, arg...) if (vbi_debug >= level) \ | ||
40 | printk(KERN_DEBUG "%s: " fmt, dev->core->name , ## arg) | ||
41 | |||
42 | /* ------------------------------------------------------------------ */ | ||
43 | |||
44 | static void | ||
45 | free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf) | ||
46 | { | ||
47 | struct em28xx_fh *fh = vq->priv_data; | ||
48 | struct em28xx *dev = fh->dev; | ||
49 | unsigned long flags = 0; | ||
50 | if (in_interrupt()) | ||
51 | BUG(); | ||
52 | |||
53 | /* We used to wait for the buffer to finish here, but this didn't work | ||
54 | because, as we were keeping the state as VIDEOBUF_QUEUED, | ||
55 | videobuf_queue_cancel marked it as finished for us. | ||
56 | (Also, it could wedge forever if the hardware was misconfigured.) | ||
57 | |||
58 | This should be safe; by the time we get here, the buffer isn't | ||
59 | queued anymore. If we ever start marking the buffers as | ||
60 | VIDEOBUF_ACTIVE, it won't be, though. | ||
61 | */ | ||
62 | spin_lock_irqsave(&dev->slock, flags); | ||
63 | if (dev->isoc_ctl.vbi_buf == buf) | ||
64 | dev->isoc_ctl.vbi_buf = NULL; | ||
65 | spin_unlock_irqrestore(&dev->slock, flags); | ||
66 | |||
67 | videobuf_vmalloc_free(&buf->vb); | ||
68 | buf->vb.state = VIDEOBUF_NEEDS_INIT; | ||
69 | } | ||
70 | |||
71 | static int | ||
72 | vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) | ||
73 | { | ||
74 | *size = 720 * 12 * 2; | ||
75 | if (0 == *count) | ||
76 | *count = vbibufs; | ||
77 | if (*count < 2) | ||
78 | *count = 2; | ||
79 | if (*count > 32) | ||
80 | *count = 32; | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static int | ||
85 | vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, | ||
86 | enum v4l2_field field) | ||
87 | { | ||
88 | struct em28xx_fh *fh = q->priv_data; | ||
89 | struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb); | ||
90 | int rc = 0; | ||
91 | unsigned int size; | ||
92 | |||
93 | size = 720 * 12 * 2; | ||
94 | |||
95 | buf->vb.size = size; | ||
96 | |||
97 | if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) | ||
98 | return -EINVAL; | ||
99 | |||
100 | buf->vb.width = 720; | ||
101 | buf->vb.height = 12; | ||
102 | buf->vb.field = field; | ||
103 | |||
104 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { | ||
105 | rc = videobuf_iolock(q, &buf->vb, NULL); | ||
106 | if (rc < 0) | ||
107 | goto fail; | ||
108 | } | ||
109 | |||
110 | buf->vb.state = VIDEOBUF_PREPARED; | ||
111 | return 0; | ||
112 | |||
113 | fail: | ||
114 | free_buffer(q, buf); | ||
115 | return rc; | ||
116 | } | ||
117 | |||
118 | static void | ||
119 | vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) | ||
120 | { | ||
121 | struct em28xx_buffer *buf = container_of(vb, | ||
122 | struct em28xx_buffer, | ||
123 | vb); | ||
124 | struct em28xx_fh *fh = vq->priv_data; | ||
125 | struct em28xx *dev = fh->dev; | ||
126 | struct em28xx_dmaqueue *vbiq = &dev->vbiq; | ||
127 | |||
128 | buf->vb.state = VIDEOBUF_QUEUED; | ||
129 | list_add_tail(&buf->vb.queue, &vbiq->active); | ||
130 | } | ||
131 | |||
132 | static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb) | ||
133 | { | ||
134 | struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb); | ||
135 | free_buffer(q, buf); | ||
136 | } | ||
137 | |||
138 | struct videobuf_queue_ops em28xx_vbi_qops = { | ||
139 | .buf_setup = vbi_setup, | ||
140 | .buf_prepare = vbi_prepare, | ||
141 | .buf_queue = vbi_queue, | ||
142 | .buf_release = vbi_release, | ||
143 | }; | ||
144 | |||
145 | /* ------------------------------------------------------------------ */ | ||
146 | /* | ||
147 | * Local variables: | ||
148 | * c-basic-offset: 8 | ||
149 | * End: | ||
150 | */ | ||