Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
1da177e4 LT |
2 | * |
3 | * device driver for philips saa7134 based TV cards | |
4 | * video4linux video interface | |
5 | * | |
6 | * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] | |
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., 675 Mass Ave, Cambridge, MA 02139, USA. | |
21 | */ | |
22 | ||
9a12ccfc MCC |
23 | #include "saa7134.h" |
24 | #include "saa7134-reg.h" | |
25 | ||
1da177e4 LT |
26 | #include <linux/init.h> |
27 | #include <linux/list.h> | |
28 | #include <linux/module.h> | |
1da177e4 | 29 | #include <linux/kernel.h> |
1da177e4 | 30 | |
1da177e4 LT |
31 | /* ------------------------------------------------------------------ */ |
32 | ||
ff699e6b | 33 | static unsigned int vbi_debug; |
1da177e4 LT |
34 | module_param(vbi_debug, int, 0644); |
35 | MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]"); | |
36 | ||
37 | static unsigned int vbibufs = 4; | |
38 | module_param(vbibufs, int, 0444); | |
39 | MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32"); | |
40 | ||
45f38cb3 MCC |
41 | #define vbi_dbg(fmt, arg...) do { \ |
42 | if (vbi_debug) \ | |
43 | printk(KERN_DEBUG pr_fmt("vbi: " fmt), ## arg); \ | |
44 | } while (0) | |
1da177e4 LT |
45 | |
46 | /* ------------------------------------------------------------------ */ | |
47 | ||
033d0088 | 48 | #define VBI_LINE_COUNT 17 |
1da177e4 LT |
49 | #define VBI_LINE_LENGTH 2048 |
50 | #define VBI_SCALE 0x200 | |
51 | ||
52 | static void task_init(struct saa7134_dev *dev, struct saa7134_buf *buf, | |
53 | int task) | |
54 | { | |
55 | struct saa7134_tvnorm *norm = dev->tvnorm; | |
56 | ||
57 | /* setup video scaler */ | |
58 | saa_writeb(SAA7134_VBI_H_START1(task), norm->h_start & 0xff); | |
59 | saa_writeb(SAA7134_VBI_H_START2(task), norm->h_start >> 8); | |
60 | saa_writeb(SAA7134_VBI_H_STOP1(task), norm->h_stop & 0xff); | |
61 | saa_writeb(SAA7134_VBI_H_STOP2(task), norm->h_stop >> 8); | |
f246a817 MS |
62 | saa_writeb(SAA7134_VBI_V_START1(task), norm->vbi_v_start_0 & 0xff); |
63 | saa_writeb(SAA7134_VBI_V_START2(task), norm->vbi_v_start_0 >> 8); | |
64 | saa_writeb(SAA7134_VBI_V_STOP1(task), norm->vbi_v_stop_0 & 0xff); | |
65 | saa_writeb(SAA7134_VBI_V_STOP2(task), norm->vbi_v_stop_0 >> 8); | |
1da177e4 LT |
66 | |
67 | saa_writeb(SAA7134_VBI_H_SCALE_INC1(task), VBI_SCALE & 0xff); | |
68 | saa_writeb(SAA7134_VBI_H_SCALE_INC2(task), VBI_SCALE >> 8); | |
69 | saa_writeb(SAA7134_VBI_PHASE_OFFSET_LUMA(task), 0x00); | |
70 | saa_writeb(SAA7134_VBI_PHASE_OFFSET_CHROMA(task), 0x00); | |
71 | ||
01c3a846 HV |
72 | saa_writeb(SAA7134_VBI_H_LEN1(task), dev->vbi_hlen & 0xff); |
73 | saa_writeb(SAA7134_VBI_H_LEN2(task), dev->vbi_hlen >> 8); | |
74 | saa_writeb(SAA7134_VBI_V_LEN1(task), dev->vbi_vlen & 0xff); | |
75 | saa_writeb(SAA7134_VBI_V_LEN2(task), dev->vbi_vlen >> 8); | |
1da177e4 LT |
76 | |
77 | saa_andorb(SAA7134_DATA_PATH(task), 0xc0, 0x00); | |
78 | } | |
79 | ||
80 | /* ------------------------------------------------------------------ */ | |
81 | ||
82 | static int buffer_activate(struct saa7134_dev *dev, | |
83 | struct saa7134_buf *buf, | |
84 | struct saa7134_buf *next) | |
85 | { | |
2d700715 | 86 | struct saa7134_dmaqueue *dmaq = buf->vb2.vb2_buf.vb2_queue->drv_priv; |
e72936d2 | 87 | unsigned long control, base; |
1da177e4 | 88 | |
630983b7 | 89 | vbi_dbg("buffer_activate [%p]\n", buf); |
1da177e4 LT |
90 | buf->top_seen = 0; |
91 | ||
e72936d2 HV |
92 | task_init(dev, buf, TASK_A); |
93 | task_init(dev, buf, TASK_B); | |
1da177e4 LT |
94 | saa_writeb(SAA7134_OFMT_DATA_A, 0x06); |
95 | saa_writeb(SAA7134_OFMT_DATA_B, 0x06); | |
96 | ||
97 | /* DMA: setup channel 2+3 (= VBI Task A+B) */ | |
98 | base = saa7134_buffer_base(buf); | |
99 | control = SAA7134_RS_CONTROL_BURST_16 | | |
100 | SAA7134_RS_CONTROL_ME | | |
2ada815f | 101 | (dmaq->pt.dma >> 12); |
e72936d2 | 102 | saa_writel(SAA7134_RS_BA1(2), base); |
01c3a846 HV |
103 | saa_writel(SAA7134_RS_BA2(2), base + dev->vbi_hlen * dev->vbi_vlen); |
104 | saa_writel(SAA7134_RS_PITCH(2), dev->vbi_hlen); | |
e72936d2 HV |
105 | saa_writel(SAA7134_RS_CONTROL(2), control); |
106 | saa_writel(SAA7134_RS_BA1(3), base); | |
01c3a846 HV |
107 | saa_writel(SAA7134_RS_BA2(3), base + dev->vbi_hlen * dev->vbi_vlen); |
108 | saa_writel(SAA7134_RS_PITCH(3), dev->vbi_hlen); | |
e72936d2 | 109 | saa_writel(SAA7134_RS_CONTROL(3), control); |
1da177e4 LT |
110 | |
111 | /* start DMA */ | |
112 | saa7134_set_dmabits(dev); | |
2ada815f | 113 | mod_timer(&dmaq->timeout, jiffies + BUFFER_TIMEOUT); |
1da177e4 LT |
114 | |
115 | return 0; | |
116 | } | |
117 | ||
2ada815f | 118 | static int buffer_prepare(struct vb2_buffer *vb2) |
1da177e4 | 119 | { |
2ada815f | 120 | struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv; |
a00e6888 | 121 | struct saa7134_dev *dev = dmaq->dev; |
2d700715 JS |
122 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2); |
123 | struct saa7134_buf *buf = container_of(vbuf, struct saa7134_buf, vb2); | |
124 | struct sg_table *dma = vb2_dma_sg_plane_desc(vb2, 0); | |
01c3a846 | 125 | unsigned int size; |
1da177e4 | 126 | |
a3f415ab HV |
127 | if (dma->sgl->offset) { |
128 | pr_err("The buffer is not page-aligned\n"); | |
129 | return -EINVAL; | |
130 | } | |
01c3a846 | 131 | size = dev->vbi_hlen * dev->vbi_vlen * 2; |
2ada815f | 132 | if (vb2_plane_size(vb2, 0) < size) |
1da177e4 LT |
133 | return -EINVAL; |
134 | ||
2ada815f | 135 | vb2_set_plane_payload(vb2, 0, size); |
1da177e4 | 136 | |
2ada815f HV |
137 | return saa7134_pgtable_build(dev->pci, &dmaq->pt, dma->sgl, dma->nents, |
138 | saa7134_buffer_startpage(buf)); | |
1da177e4 LT |
139 | } |
140 | ||
33119e80 | 141 | static int queue_setup(struct vb2_queue *q, const void *parg, |
2ada815f HV |
142 | unsigned int *nbuffers, unsigned int *nplanes, |
143 | unsigned int sizes[], void *alloc_ctxs[]) | |
1da177e4 | 144 | { |
2ada815f | 145 | struct saa7134_dmaqueue *dmaq = q->drv_priv; |
a00e6888 | 146 | struct saa7134_dev *dev = dmaq->dev; |
2ada815f | 147 | unsigned int size; |
1da177e4 | 148 | |
01c3a846 HV |
149 | dev->vbi_vlen = dev->tvnorm->vbi_v_stop_0 - dev->tvnorm->vbi_v_start_0 + 1; |
150 | if (dev->vbi_vlen > VBI_LINE_COUNT) | |
151 | dev->vbi_vlen = VBI_LINE_COUNT; | |
152 | dev->vbi_hlen = VBI_LINE_LENGTH; | |
2ada815f HV |
153 | size = dev->vbi_hlen * dev->vbi_vlen * 2; |
154 | ||
155 | *nbuffers = saa7134_buffer_count(size, *nbuffers); | |
156 | *nplanes = 1; | |
157 | sizes[0] = size; | |
0c3a14c1 | 158 | alloc_ctxs[0] = dev->alloc_ctx; |
1da177e4 LT |
159 | return 0; |
160 | } | |
161 | ||
2ada815f | 162 | static int buffer_init(struct vb2_buffer *vb2) |
1da177e4 | 163 | { |
2ada815f | 164 | struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv; |
2d700715 JS |
165 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2); |
166 | struct saa7134_buf *buf = container_of(vbuf, struct saa7134_buf, vb2); | |
1da177e4 | 167 | |
2ada815f HV |
168 | dmaq->curr = NULL; |
169 | buf->activate = buffer_activate; | |
170 | return 0; | |
1da177e4 LT |
171 | } |
172 | ||
2ada815f HV |
173 | struct vb2_ops saa7134_vbi_qops = { |
174 | .queue_setup = queue_setup, | |
175 | .buf_init = buffer_init, | |
176 | .buf_prepare = buffer_prepare, | |
2ada815f HV |
177 | .buf_queue = saa7134_vb2_buffer_queue, |
178 | .wait_prepare = vb2_ops_wait_prepare, | |
179 | .wait_finish = vb2_ops_wait_finish, | |
180 | .start_streaming = saa7134_vb2_start_streaming, | |
181 | .stop_streaming = saa7134_vb2_stop_streaming, | |
1da177e4 LT |
182 | }; |
183 | ||
184 | /* ------------------------------------------------------------------ */ | |
185 | ||
186 | int saa7134_vbi_init1(struct saa7134_dev *dev) | |
187 | { | |
188 | INIT_LIST_HEAD(&dev->vbi_q.queue); | |
189 | init_timer(&dev->vbi_q.timeout); | |
190 | dev->vbi_q.timeout.function = saa7134_buffer_timeout; | |
191 | dev->vbi_q.timeout.data = (unsigned long)(&dev->vbi_q); | |
192 | dev->vbi_q.dev = dev; | |
193 | ||
194 | if (vbibufs < 2) | |
195 | vbibufs = 2; | |
196 | if (vbibufs > VIDEO_MAX_FRAME) | |
197 | vbibufs = VIDEO_MAX_FRAME; | |
198 | return 0; | |
199 | } | |
200 | ||
201 | int saa7134_vbi_fini(struct saa7134_dev *dev) | |
202 | { | |
203 | /* nothing */ | |
204 | return 0; | |
205 | } | |
206 | ||
207 | void saa7134_irq_vbi_done(struct saa7134_dev *dev, unsigned long status) | |
208 | { | |
209 | spin_lock(&dev->slock); | |
210 | if (dev->vbi_q.curr) { | |
1da177e4 LT |
211 | /* make sure we have seen both fields */ |
212 | if ((status & 0x10) == 0x00) { | |
213 | dev->vbi_q.curr->top_seen = 1; | |
214 | goto done; | |
215 | } | |
216 | if (!dev->vbi_q.curr->top_seen) | |
217 | goto done; | |
218 | ||
2ada815f | 219 | saa7134_buffer_finish(dev, &dev->vbi_q, VB2_BUF_STATE_DONE); |
1da177e4 | 220 | } |
e72936d2 | 221 | saa7134_buffer_next(dev, &dev->vbi_q); |
1da177e4 LT |
222 | |
223 | done: | |
224 | spin_unlock(&dev->slock); | |
225 | } |