1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * |
4 | * device driver for philips saa7134 based TV cards |
5 | * video4linux video interface |
6 | * |
7 | * (c) 2001-03 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] |
8 | */ |
9 | |
10 | #include "saa7134.h" |
11 | #include "saa7134-reg.h" |
12 | |
13 | #include <linux/init.h> |
14 | #include <linux/list.h> |
15 | #include <linux/module.h> |
16 | #include <linux/kernel.h> |
17 | #include <linux/slab.h> |
18 | #include <linux/sort.h> |
19 | |
20 | #include <media/v4l2-common.h> |
21 | #include <media/v4l2-event.h> |
22 | #include <media/i2c/saa6588.h> |
23 | |
24 | /* ------------------------------------------------------------------ */ |
25 | |
26 | unsigned int video_debug; |
27 | static unsigned int gbuffers = 8; |
28 | static unsigned int noninterlaced; /* 0 */ |
29 | static unsigned int gbufsize = 720*576*4; |
30 | static unsigned int gbufsize_max = 720*576*4; |
31 | static char secam[] = "--" ; |
32 | module_param(video_debug, int, 0644); |
33 | MODULE_PARM_DESC(video_debug,"enable debug messages [video]" ); |
34 | module_param(gbuffers, int, 0444); |
35 | MODULE_PARM_DESC(gbuffers,"number of capture buffers, range 2-32" ); |
36 | module_param(noninterlaced, int, 0644); |
37 | MODULE_PARM_DESC(noninterlaced,"capture non interlaced video" ); |
38 | module_param_string(secam, secam, sizeof(secam), 0644); |
39 | MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc" ); |
40 | |
41 | |
42 | #define video_dbg(fmt, arg...) do { \ |
43 | if (video_debug & 0x04) \ |
44 | printk(KERN_DEBUG pr_fmt("video: " fmt), ## arg); \ |
45 | } while (0) |
46 | |
47 | /* ------------------------------------------------------------------ */ |
48 | /* Defines for Video Output Port Register at address 0x191 */ |
49 | |
50 | /* Bit 0: VIP code T bit polarity */ |
51 | |
52 | #define VP_T_CODE_P_NON_INVERTED 0x00 |
53 | #define VP_T_CODE_P_INVERTED 0x01 |
54 | |
55 | /* ------------------------------------------------------------------ */ |
56 | /* Defines for Video Output Port Register at address 0x195 */ |
57 | |
58 | /* Bit 2: Video output clock delay control */ |
59 | |
60 | #define VP_CLK_CTRL2_NOT_DELAYED 0x00 |
61 | #define VP_CLK_CTRL2_DELAYED 0x04 |
62 | |
63 | /* Bit 1: Video output clock invert control */ |
64 | |
65 | #define VP_CLK_CTRL1_NON_INVERTED 0x00 |
66 | #define VP_CLK_CTRL1_INVERTED 0x02 |
67 | |
68 | /* ------------------------------------------------------------------ */ |
69 | /* Defines for Video Output Port Register at address 0x196 */ |
70 | |
71 | /* Bits 2 to 0: VSYNC pin video vertical sync type */ |
72 | |
73 | #define VP_VS_TYPE_MASK 0x07 |
74 | |
75 | #define VP_VS_TYPE_OFF 0x00 |
76 | #define VP_VS_TYPE_V123 0x01 |
77 | #define VP_VS_TYPE_V_ITU 0x02 |
78 | #define VP_VS_TYPE_VGATE_L 0x03 |
79 | #define VP_VS_TYPE_RESERVED1 0x04 |
80 | #define VP_VS_TYPE_RESERVED2 0x05 |
81 | #define VP_VS_TYPE_F_ITU 0x06 |
82 | #define VP_VS_TYPE_SC_FID 0x07 |
83 | |
84 | /* ------------------------------------------------------------------ */ |
85 | /* data structs for video */ |
86 | |
87 | static int video_out[][9] = { |
88 | [CCIR656] = { 0x00, 0xb1, 0x00, 0xa1, 0x00, 0x04, 0x06, 0x00, 0x00 }, |
89 | }; |
90 | |
91 | static struct saa7134_format formats[] = { |
92 | { |
93 | .fourcc = V4L2_PIX_FMT_GREY, |
94 | .depth = 8, |
95 | .pm = 0x06, |
96 | },{ |
97 | .fourcc = V4L2_PIX_FMT_RGB555, |
98 | .depth = 16, |
99 | .pm = 0x13 | 0x80, |
100 | },{ |
101 | .fourcc = V4L2_PIX_FMT_RGB555X, |
102 | .depth = 16, |
103 | .pm = 0x13 | 0x80, |
104 | .bswap = 1, |
105 | },{ |
106 | .fourcc = V4L2_PIX_FMT_RGB565, |
107 | .depth = 16, |
108 | .pm = 0x10 | 0x80, |
109 | },{ |
110 | .fourcc = V4L2_PIX_FMT_RGB565X, |
111 | .depth = 16, |
112 | .pm = 0x10 | 0x80, |
113 | .bswap = 1, |
114 | },{ |
115 | .fourcc = V4L2_PIX_FMT_BGR24, |
116 | .depth = 24, |
117 | .pm = 0x11, |
118 | },{ |
119 | .fourcc = V4L2_PIX_FMT_RGB24, |
120 | .depth = 24, |
121 | .pm = 0x11, |
122 | .bswap = 1, |
123 | },{ |
124 | .fourcc = V4L2_PIX_FMT_BGR32, |
125 | .depth = 32, |
126 | .pm = 0x12, |
127 | },{ |
128 | .fourcc = V4L2_PIX_FMT_RGB32, |
129 | .depth = 32, |
130 | .pm = 0x12, |
131 | .bswap = 1, |
132 | .wswap = 1, |
133 | },{ |
134 | .fourcc = V4L2_PIX_FMT_YUYV, |
135 | .depth = 16, |
136 | .pm = 0x00, |
137 | .bswap = 1, |
138 | .yuv = 1, |
139 | },{ |
140 | .fourcc = V4L2_PIX_FMT_UYVY, |
141 | .depth = 16, |
142 | .pm = 0x00, |
143 | .yuv = 1, |
144 | },{ |
145 | .fourcc = V4L2_PIX_FMT_YUV422P, |
146 | .depth = 16, |
147 | .pm = 0x09, |
148 | .yuv = 1, |
149 | .planar = 1, |
150 | .hshift = 1, |
151 | .vshift = 0, |
152 | },{ |
153 | .fourcc = V4L2_PIX_FMT_YUV420, |
154 | .depth = 12, |
155 | .pm = 0x0a, |
156 | .yuv = 1, |
157 | .planar = 1, |
158 | .hshift = 1, |
159 | .vshift = 1, |
160 | },{ |
161 | .fourcc = V4L2_PIX_FMT_YVU420, |
162 | .depth = 12, |
163 | .pm = 0x0a, |
164 | .yuv = 1, |
165 | .planar = 1, |
166 | .uvswap = 1, |
167 | .hshift = 1, |
168 | .vshift = 1, |
169 | } |
170 | }; |
171 | #define FORMATS ARRAY_SIZE(formats) |
172 | |
173 | #define NORM_625_50 \ |
174 | .h_start = 0, \ |
175 | .h_stop = 719, \ |
176 | .video_v_start = 24, \ |
177 | .video_v_stop = 311, \ |
178 | .vbi_v_start_0 = 7, \ |
179 | .vbi_v_stop_0 = 23, \ |
180 | .vbi_v_start_1 = 319, \ |
181 | .src_timing = 4 |
182 | |
183 | #define NORM_525_60 \ |
184 | .h_start = 0, \ |
185 | .h_stop = 719, \ |
186 | .video_v_start = 23, \ |
187 | .video_v_stop = 262, \ |
188 | .vbi_v_start_0 = 10, \ |
189 | .vbi_v_stop_0 = 21, \ |
190 | .vbi_v_start_1 = 273, \ |
191 | .src_timing = 7 |
192 | |
193 | static struct saa7134_tvnorm tvnorms[] = { |
194 | { |
195 | .name = "PAL" , /* autodetect */ |
196 | .id = V4L2_STD_PAL, |
197 | NORM_625_50, |
198 | |
199 | .sync_control = 0x18, |
200 | .luma_control = 0x40, |
201 | .chroma_ctrl1 = 0x81, |
202 | .chroma_gain = 0x2a, |
203 | .chroma_ctrl2 = 0x06, |
204 | .vgate_misc = 0x1c, |
205 | |
206 | },{ |
207 | .name = "PAL-BG" , |
208 | .id = V4L2_STD_PAL_BG, |
209 | NORM_625_50, |
210 | |
211 | .sync_control = 0x18, |
212 | .luma_control = 0x40, |
213 | .chroma_ctrl1 = 0x81, |
214 | .chroma_gain = 0x2a, |
215 | .chroma_ctrl2 = 0x06, |
216 | .vgate_misc = 0x1c, |
217 | |
218 | },{ |
219 | .name = "PAL-I" , |
220 | .id = V4L2_STD_PAL_I, |
221 | NORM_625_50, |
222 | |
223 | .sync_control = 0x18, |
224 | .luma_control = 0x40, |
225 | .chroma_ctrl1 = 0x81, |
226 | .chroma_gain = 0x2a, |
227 | .chroma_ctrl2 = 0x06, |
228 | .vgate_misc = 0x1c, |
229 | |
230 | },{ |
231 | .name = "PAL-DK" , |
232 | .id = V4L2_STD_PAL_DK, |
233 | NORM_625_50, |
234 | |
235 | .sync_control = 0x18, |
236 | .luma_control = 0x40, |
237 | .chroma_ctrl1 = 0x81, |
238 | .chroma_gain = 0x2a, |
239 | .chroma_ctrl2 = 0x06, |
240 | .vgate_misc = 0x1c, |
241 | |
242 | },{ |
243 | .name = "NTSC" , |
244 | .id = V4L2_STD_NTSC, |
245 | NORM_525_60, |
246 | |
247 | .sync_control = 0x59, |
248 | .luma_control = 0x40, |
249 | .chroma_ctrl1 = 0x89, |
250 | .chroma_gain = 0x2a, |
251 | .chroma_ctrl2 = 0x0e, |
252 | .vgate_misc = 0x18, |
253 | |
254 | },{ |
255 | .name = "SECAM" , |
256 | .id = V4L2_STD_SECAM, |
257 | NORM_625_50, |
258 | |
259 | .sync_control = 0x18, |
260 | .luma_control = 0x1b, |
261 | .chroma_ctrl1 = 0xd1, |
262 | .chroma_gain = 0x80, |
263 | .chroma_ctrl2 = 0x00, |
264 | .vgate_misc = 0x1c, |
265 | |
266 | },{ |
267 | .name = "SECAM-DK" , |
268 | .id = V4L2_STD_SECAM_DK, |
269 | NORM_625_50, |
270 | |
271 | .sync_control = 0x18, |
272 | .luma_control = 0x1b, |
273 | .chroma_ctrl1 = 0xd1, |
274 | .chroma_gain = 0x80, |
275 | .chroma_ctrl2 = 0x00, |
276 | .vgate_misc = 0x1c, |
277 | |
278 | },{ |
279 | .name = "SECAM-L" , |
280 | .id = V4L2_STD_SECAM_L, |
281 | NORM_625_50, |
282 | |
283 | .sync_control = 0x18, |
284 | .luma_control = 0x1b, |
285 | .chroma_ctrl1 = 0xd1, |
286 | .chroma_gain = 0x80, |
287 | .chroma_ctrl2 = 0x00, |
288 | .vgate_misc = 0x1c, |
289 | |
290 | },{ |
291 | .name = "SECAM-Lc" , |
292 | .id = V4L2_STD_SECAM_LC, |
293 | NORM_625_50, |
294 | |
295 | .sync_control = 0x18, |
296 | .luma_control = 0x1b, |
297 | .chroma_ctrl1 = 0xd1, |
298 | .chroma_gain = 0x80, |
299 | .chroma_ctrl2 = 0x00, |
300 | .vgate_misc = 0x1c, |
301 | |
302 | },{ |
303 | .name = "PAL-M" , |
304 | .id = V4L2_STD_PAL_M, |
305 | NORM_525_60, |
306 | |
307 | .sync_control = 0x59, |
308 | .luma_control = 0x40, |
309 | .chroma_ctrl1 = 0xb9, |
310 | .chroma_gain = 0x2a, |
311 | .chroma_ctrl2 = 0x0e, |
312 | .vgate_misc = 0x18, |
313 | |
314 | },{ |
315 | .name = "PAL-Nc" , |
316 | .id = V4L2_STD_PAL_Nc, |
317 | NORM_625_50, |
318 | |
319 | .sync_control = 0x18, |
320 | .luma_control = 0x40, |
321 | .chroma_ctrl1 = 0xa1, |
322 | .chroma_gain = 0x2a, |
323 | .chroma_ctrl2 = 0x06, |
324 | .vgate_misc = 0x1c, |
325 | |
326 | },{ |
327 | .name = "PAL-60" , |
328 | .id = V4L2_STD_PAL_60, |
329 | |
330 | .h_start = 0, |
331 | .h_stop = 719, |
332 | .video_v_start = 23, |
333 | .video_v_stop = 262, |
334 | .vbi_v_start_0 = 10, |
335 | .vbi_v_stop_0 = 21, |
336 | .vbi_v_start_1 = 273, |
337 | .src_timing = 7, |
338 | |
339 | .sync_control = 0x18, |
340 | .luma_control = 0x40, |
341 | .chroma_ctrl1 = 0x81, |
342 | .chroma_gain = 0x2a, |
343 | .chroma_ctrl2 = 0x06, |
344 | .vgate_misc = 0x1c, |
345 | } |
346 | }; |
347 | #define TVNORMS ARRAY_SIZE(tvnorms) |
348 | |
349 | static struct saa7134_format* format_by_fourcc(unsigned int fourcc) |
350 | { |
351 | unsigned int i; |
352 | |
353 | for (i = 0; i < FORMATS; i++) |
354 | if (formats[i].fourcc == fourcc) |
355 | return formats+i; |
356 | return NULL; |
357 | } |
358 | |
359 | /* ------------------------------------------------------------------ */ |
360 | |
361 | static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) |
362 | { |
363 | video_dbg("set tv norm = %s\n" , norm->name); |
364 | dev->tvnorm = norm; |
365 | |
366 | /* setup cropping */ |
367 | dev->crop_bounds.left = norm->h_start; |
368 | dev->crop_defrect.left = norm->h_start; |
369 | dev->crop_bounds.width = norm->h_stop - norm->h_start +1; |
370 | dev->crop_defrect.width = norm->h_stop - norm->h_start +1; |
371 | |
372 | dev->crop_bounds.top = (norm->vbi_v_stop_0+1)*2; |
373 | dev->crop_defrect.top = norm->video_v_start*2; |
374 | dev->crop_bounds.height = ((norm->id & V4L2_STD_525_60) ? 524 : 624) |
375 | - dev->crop_bounds.top; |
376 | dev->crop_defrect.height = (norm->video_v_stop - norm->video_v_start +1)*2; |
377 | |
378 | dev->crop_current = dev->crop_defrect; |
379 | |
380 | saa7134_set_tvnorm_hw(dev); |
381 | } |
382 | |
383 | static void video_mux(struct saa7134_dev *dev, int input) |
384 | { |
385 | video_dbg("video input = %d [%s]\n" , |
386 | input, saa7134_input_name[card_in(dev, input).type]); |
387 | dev->ctl_input = input; |
388 | set_tvnorm(dev, norm: dev->tvnorm); |
389 | saa7134_tvaudio_setinput(dev, in: &card_in(dev, input)); |
390 | } |
391 | |
392 | |
393 | static void saa7134_set_decoder(struct saa7134_dev *dev) |
394 | { |
395 | int luma_control, sync_control, chroma_ctrl1, mux; |
396 | |
397 | struct saa7134_tvnorm *norm = dev->tvnorm; |
398 | mux = card_in(dev, dev->ctl_input).vmux; |
399 | |
400 | luma_control = norm->luma_control; |
401 | sync_control = norm->sync_control; |
402 | chroma_ctrl1 = norm->chroma_ctrl1; |
403 | |
404 | if (mux > 5) |
405 | luma_control |= 0x80; /* svideo */ |
406 | if (noninterlaced || dev->nosignal) |
407 | sync_control |= 0x20; |
408 | |
409 | /* switch on auto standard detection */ |
410 | sync_control |= SAA7134_SYNC_CTRL_AUFD; |
411 | chroma_ctrl1 |= SAA7134_CHROMA_CTRL1_AUTO0; |
412 | chroma_ctrl1 &= ~SAA7134_CHROMA_CTRL1_FCTC; |
413 | luma_control &= ~SAA7134_LUMA_CTRL_LDEL; |
414 | |
415 | /* setup video decoder */ |
416 | saa_writeb(SAA7134_INCR_DELAY, 0x08); |
417 | saa_writeb(SAA7134_ANALOG_IN_CTRL1, 0xc0 | mux); |
418 | saa_writeb(SAA7134_ANALOG_IN_CTRL2, 0x00); |
419 | |
420 | saa_writeb(SAA7134_ANALOG_IN_CTRL3, 0x90); |
421 | saa_writeb(SAA7134_ANALOG_IN_CTRL4, 0x90); |
422 | saa_writeb(SAA7134_HSYNC_START, 0xeb); |
423 | saa_writeb(SAA7134_HSYNC_STOP, 0xe0); |
424 | saa_writeb(SAA7134_SOURCE_TIMING1, norm->src_timing); |
425 | |
426 | saa_writeb(SAA7134_SYNC_CTRL, sync_control); |
427 | saa_writeb(SAA7134_LUMA_CTRL, luma_control); |
428 | saa_writeb(SAA7134_DEC_LUMA_BRIGHT, dev->ctl_bright); |
429 | |
430 | saa_writeb(SAA7134_DEC_LUMA_CONTRAST, |
431 | dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast); |
432 | |
433 | saa_writeb(SAA7134_DEC_CHROMA_SATURATION, |
434 | dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation); |
435 | |
436 | saa_writeb(SAA7134_DEC_CHROMA_HUE, dev->ctl_hue); |
437 | saa_writeb(SAA7134_CHROMA_CTRL1, chroma_ctrl1); |
438 | saa_writeb(SAA7134_CHROMA_GAIN, norm->chroma_gain); |
439 | |
440 | saa_writeb(SAA7134_CHROMA_CTRL2, norm->chroma_ctrl2); |
441 | saa_writeb(SAA7134_MODE_DELAY_CTRL, 0x00); |
442 | |
443 | saa_writeb(SAA7134_ANALOG_ADC, 0x01); |
444 | saa_writeb(SAA7134_VGATE_START, 0x11); |
445 | saa_writeb(SAA7134_VGATE_STOP, 0xfe); |
446 | saa_writeb(SAA7134_MISC_VGATE_MSB, norm->vgate_misc); |
447 | saa_writeb(SAA7134_RAW_DATA_GAIN, 0x40); |
448 | saa_writeb(SAA7134_RAW_DATA_OFFSET, 0x80); |
449 | } |
450 | |
451 | void saa7134_set_tvnorm_hw(struct saa7134_dev *dev) |
452 | { |
453 | saa7134_set_decoder(dev); |
454 | |
455 | saa_call_all(dev, video, s_std, dev->tvnorm->id); |
456 | /* Set the correct norm for the saa6752hs. This function |
457 | does nothing if there is no saa6752hs. */ |
458 | saa_call_empress(dev, video, s_std, dev->tvnorm->id); |
459 | } |
460 | |
461 | static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale) |
462 | { |
463 | static const struct { |
464 | int xpsc; |
465 | int xacl; |
466 | int xc2_1; |
467 | int xdcg; |
468 | int vpfy; |
469 | } vals[] = { |
470 | /* XPSC XACL XC2_1 XDCG VPFY */ |
471 | { 1, 0, 0, 0, 0 }, |
472 | { 2, 2, 1, 2, 2 }, |
473 | { 3, 4, 1, 3, 2 }, |
474 | { 4, 8, 1, 4, 2 }, |
475 | { 5, 8, 1, 4, 2 }, |
476 | { 6, 8, 1, 4, 3 }, |
477 | { 7, 8, 1, 4, 3 }, |
478 | { 8, 15, 0, 4, 3 }, |
479 | { 9, 15, 0, 4, 3 }, |
480 | { 10, 16, 1, 5, 3 }, |
481 | }; |
482 | static const int count = ARRAY_SIZE(vals); |
483 | int i; |
484 | |
485 | for (i = 0; i < count; i++) |
486 | if (vals[i].xpsc == prescale) |
487 | break; |
488 | if (i == count) |
489 | return; |
490 | |
491 | saa_writeb(SAA7134_H_PRESCALE(task), vals[i].xpsc); |
492 | saa_writeb(SAA7134_ACC_LENGTH(task), vals[i].xacl); |
493 | saa_writeb(SAA7134_LEVEL_CTRL(task), |
494 | (vals[i].xc2_1 << 3) | (vals[i].xdcg)); |
495 | saa_andorb(SAA7134_FIR_PREFILTER_CTRL(task), 0x0f, |
496 | (vals[i].vpfy << 2) | vals[i].vpfy); |
497 | } |
498 | |
499 | static void set_v_scale(struct saa7134_dev *dev, int task, int yscale) |
500 | { |
501 | int val,mirror; |
502 | |
503 | saa_writeb(SAA7134_V_SCALE_RATIO1(task), yscale & 0xff); |
504 | saa_writeb(SAA7134_V_SCALE_RATIO2(task), yscale >> 8); |
505 | |
506 | mirror = (dev->ctl_mirror) ? 0x02 : 0x00; |
507 | if (yscale < 2048) { |
508 | /* LPI */ |
509 | video_dbg("yscale LPI yscale=%d\n" , yscale); |
510 | saa_writeb(SAA7134_V_FILTER(task), 0x00 | mirror); |
511 | saa_writeb(SAA7134_LUMA_CONTRAST(task), 0x40); |
512 | saa_writeb(SAA7134_CHROMA_SATURATION(task), 0x40); |
513 | } else { |
514 | /* ACM */ |
515 | val = 0x40 * 1024 / yscale; |
516 | video_dbg("yscale ACM yscale=%d val=0x%x\n" , yscale, val); |
517 | saa_writeb(SAA7134_V_FILTER(task), 0x01 | mirror); |
518 | saa_writeb(SAA7134_LUMA_CONTRAST(task), val); |
519 | saa_writeb(SAA7134_CHROMA_SATURATION(task), val); |
520 | } |
521 | saa_writeb(SAA7134_LUMA_BRIGHT(task), 0x80); |
522 | } |
523 | |
524 | static void set_size(struct saa7134_dev *dev, int task, |
525 | int width, int height, int interlace) |
526 | { |
527 | int prescale,xscale,yscale,y_even,y_odd; |
528 | int h_start, h_stop, v_start, v_stop; |
529 | int div = interlace ? 2 : 1; |
530 | |
531 | /* setup video scaler */ |
532 | h_start = dev->crop_current.left; |
533 | v_start = dev->crop_current.top/2; |
534 | h_stop = (dev->crop_current.left + dev->crop_current.width -1); |
535 | v_stop = (dev->crop_current.top + dev->crop_current.height -1)/2; |
536 | |
537 | saa_writeb(SAA7134_VIDEO_H_START1(task), h_start & 0xff); |
538 | saa_writeb(SAA7134_VIDEO_H_START2(task), h_start >> 8); |
539 | saa_writeb(SAA7134_VIDEO_H_STOP1(task), h_stop & 0xff); |
540 | saa_writeb(SAA7134_VIDEO_H_STOP2(task), h_stop >> 8); |
541 | saa_writeb(SAA7134_VIDEO_V_START1(task), v_start & 0xff); |
542 | saa_writeb(SAA7134_VIDEO_V_START2(task), v_start >> 8); |
543 | saa_writeb(SAA7134_VIDEO_V_STOP1(task), v_stop & 0xff); |
544 | saa_writeb(SAA7134_VIDEO_V_STOP2(task), v_stop >> 8); |
545 | |
546 | prescale = dev->crop_current.width / width; |
547 | if (0 == prescale) |
548 | prescale = 1; |
549 | xscale = 1024 * dev->crop_current.width / prescale / width; |
550 | yscale = 512 * div * dev->crop_current.height / height; |
551 | video_dbg("prescale=%d xscale=%d yscale=%d\n" , |
552 | prescale, xscale, yscale); |
553 | set_h_prescale(dev,task,prescale); |
554 | saa_writeb(SAA7134_H_SCALE_INC1(task), xscale & 0xff); |
555 | saa_writeb(SAA7134_H_SCALE_INC2(task), xscale >> 8); |
556 | set_v_scale(dev,task,yscale); |
557 | |
558 | saa_writeb(SAA7134_VIDEO_PIXELS1(task), width & 0xff); |
559 | saa_writeb(SAA7134_VIDEO_PIXELS2(task), width >> 8); |
560 | saa_writeb(SAA7134_VIDEO_LINES1(task), height/div & 0xff); |
561 | saa_writeb(SAA7134_VIDEO_LINES2(task), height/div >> 8); |
562 | |
563 | /* deinterlace y offsets */ |
564 | y_odd = dev->ctl_y_odd; |
565 | y_even = dev->ctl_y_even; |
566 | saa_writeb(SAA7134_V_PHASE_OFFSET0(task), y_odd); |
567 | saa_writeb(SAA7134_V_PHASE_OFFSET1(task), y_even); |
568 | saa_writeb(SAA7134_V_PHASE_OFFSET2(task), y_odd); |
569 | saa_writeb(SAA7134_V_PHASE_OFFSET3(task), y_even); |
570 | } |
571 | |
572 | /* ------------------------------------------------------------------ */ |
573 | |
574 | /* |
575 | * Media Controller helper functions |
576 | */ |
577 | |
578 | static int saa7134_enable_analog_tuner(struct saa7134_dev *dev) |
579 | { |
580 | #ifdef CONFIG_MEDIA_CONTROLLER |
581 | struct media_device *mdev = dev->media_dev; |
582 | struct media_entity *source; |
583 | struct media_link *link, *found_link = NULL; |
584 | int ret, active_links = 0; |
585 | |
586 | if (!mdev || !dev->decoder) |
587 | return 0; |
588 | |
589 | /* |
590 | * This will find the tuner that is connected into the decoder. |
591 | * Technically, this is not 100% correct, as the device may be |
592 | * using an analog input instead of the tuner. However, as we can't |
593 | * do DVB streaming while the DMA engine is being used for V4L2, |
594 | * this should be enough for the actual needs. |
595 | */ |
596 | list_for_each_entry(link, &dev->decoder->links, list) { |
597 | if (link->sink->entity == dev->decoder) { |
598 | found_link = link; |
599 | if (link->flags & MEDIA_LNK_FL_ENABLED) |
600 | active_links++; |
601 | break; |
602 | } |
603 | } |
604 | |
605 | if (active_links == 1 || !found_link) |
606 | return 0; |
607 | |
608 | source = found_link->source->entity; |
609 | list_for_each_entry(link, &source->links, list) { |
610 | struct media_entity *sink; |
611 | int flags = 0; |
612 | |
613 | sink = link->sink->entity; |
614 | |
615 | if (sink == dev->decoder) |
616 | flags = MEDIA_LNK_FL_ENABLED; |
617 | |
618 | ret = media_entity_setup_link(link, flags); |
619 | if (ret) { |
620 | pr_err("Couldn't change link %s->%s to %s. Error %d\n" , |
621 | source->name, sink->name, |
622 | flags ? "enabled" : "disabled" , |
623 | ret); |
624 | return ret; |
625 | } |
626 | } |
627 | #endif |
628 | return 0; |
629 | } |
630 | |
631 | /* ------------------------------------------------------------------ */ |
632 | |
633 | static int buffer_activate(struct saa7134_dev *dev, |
634 | struct saa7134_buf *buf, |
635 | struct saa7134_buf *next) |
636 | { |
637 | struct saa7134_dmaqueue *dmaq = buf->vb2.vb2_buf.vb2_queue->drv_priv; |
638 | unsigned long base,control,bpl; |
639 | unsigned long bpl_uv, lines_uv, base2, base3; /* planar */ |
640 | |
641 | video_dbg("buffer_activate buf=%p\n" , buf); |
642 | buf->top_seen = 0; |
643 | |
644 | set_size(dev, TASK_A, width: dev->width, height: dev->height, |
645 | V4L2_FIELD_HAS_BOTH(dev->field)); |
646 | if (dev->fmt->yuv) |
647 | saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x03); |
648 | else |
649 | saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x01); |
650 | saa_writeb(SAA7134_OFMT_VIDEO_A, dev->fmt->pm); |
651 | |
652 | /* DMA: setup channel 0 (= Video Task A0) */ |
653 | base = saa7134_buffer_base(buf); |
654 | if (dev->fmt->planar) |
655 | bpl = dev->width; |
656 | else |
657 | bpl = (dev->width * dev->fmt->depth) / 8; |
658 | control = SAA7134_RS_CONTROL_BURST_16 | |
659 | SAA7134_RS_CONTROL_ME | |
660 | (dmaq->pt.dma >> 12); |
661 | if (dev->fmt->bswap) |
662 | control |= SAA7134_RS_CONTROL_BSWAP; |
663 | if (dev->fmt->wswap) |
664 | control |= SAA7134_RS_CONTROL_WSWAP; |
665 | if (V4L2_FIELD_HAS_BOTH(dev->field)) { |
666 | /* interlaced */ |
667 | saa_writel(SAA7134_RS_BA1(0),base); |
668 | saa_writel(SAA7134_RS_BA2(0),base+bpl); |
669 | saa_writel(SAA7134_RS_PITCH(0),bpl*2); |
670 | } else { |
671 | /* non-interlaced */ |
672 | saa_writel(SAA7134_RS_BA1(0),base); |
673 | saa_writel(SAA7134_RS_BA2(0),base); |
674 | saa_writel(SAA7134_RS_PITCH(0),bpl); |
675 | } |
676 | saa_writel(SAA7134_RS_CONTROL(0),control); |
677 | |
678 | if (dev->fmt->planar) { |
679 | /* DMA: setup channel 4+5 (= planar task A) */ |
680 | bpl_uv = bpl >> dev->fmt->hshift; |
681 | lines_uv = dev->height >> dev->fmt->vshift; |
682 | base2 = base + bpl * dev->height; |
683 | base3 = base2 + bpl_uv * lines_uv; |
684 | if (dev->fmt->uvswap) |
685 | swap(base2, base3); |
686 | video_dbg("uv: bpl=%ld lines=%ld base2/3=%ld/%ld\n" , |
687 | bpl_uv,lines_uv,base2,base3); |
688 | if (V4L2_FIELD_HAS_BOTH(dev->field)) { |
689 | /* interlaced */ |
690 | saa_writel(SAA7134_RS_BA1(4),base2); |
691 | saa_writel(SAA7134_RS_BA2(4),base2+bpl_uv); |
692 | saa_writel(SAA7134_RS_PITCH(4),bpl_uv*2); |
693 | saa_writel(SAA7134_RS_BA1(5),base3); |
694 | saa_writel(SAA7134_RS_BA2(5),base3+bpl_uv); |
695 | saa_writel(SAA7134_RS_PITCH(5),bpl_uv*2); |
696 | } else { |
697 | /* non-interlaced */ |
698 | saa_writel(SAA7134_RS_BA1(4),base2); |
699 | saa_writel(SAA7134_RS_BA2(4),base2); |
700 | saa_writel(SAA7134_RS_PITCH(4),bpl_uv); |
701 | saa_writel(SAA7134_RS_BA1(5),base3); |
702 | saa_writel(SAA7134_RS_BA2(5),base3); |
703 | saa_writel(SAA7134_RS_PITCH(5),bpl_uv); |
704 | } |
705 | saa_writel(SAA7134_RS_CONTROL(4),control); |
706 | saa_writel(SAA7134_RS_CONTROL(5),control); |
707 | } |
708 | |
709 | /* start DMA */ |
710 | saa7134_set_dmabits(dev); |
711 | mod_timer(timer: &dmaq->timeout, expires: jiffies + BUFFER_TIMEOUT); |
712 | return 0; |
713 | } |
714 | |
715 | static int buffer_init(struct vb2_buffer *vb2) |
716 | { |
717 | struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv; |
718 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2); |
719 | struct saa7134_buf *buf = container_of(vbuf, struct saa7134_buf, vb2); |
720 | |
721 | dmaq->curr = NULL; |
722 | buf->activate = buffer_activate; |
723 | return 0; |
724 | } |
725 | |
726 | static int buffer_prepare(struct vb2_buffer *vb2) |
727 | { |
728 | struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv; |
729 | struct saa7134_dev *dev = dmaq->dev; |
730 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2); |
731 | struct saa7134_buf *buf = container_of(vbuf, struct saa7134_buf, vb2); |
732 | struct sg_table *dma = vb2_dma_sg_plane_desc(vb: vb2, plane_no: 0); |
733 | unsigned int size; |
734 | |
735 | if (dma->sgl->offset) { |
736 | pr_err("The buffer is not page-aligned\n" ); |
737 | return -EINVAL; |
738 | } |
739 | size = (dev->width * dev->height * dev->fmt->depth) >> 3; |
740 | if (vb2_plane_size(vb: vb2, plane_no: 0) < size) |
741 | return -EINVAL; |
742 | |
743 | vb2_set_plane_payload(vb: vb2, plane_no: 0, size); |
744 | vbuf->field = dev->field; |
745 | |
746 | return saa7134_pgtable_build(pci: dev->pci, pt: &dmaq->pt, list: dma->sgl, length: dma->nents, |
747 | startpage: saa7134_buffer_startpage(buf)); |
748 | } |
749 | |
750 | static int queue_setup(struct vb2_queue *q, |
751 | unsigned int *nbuffers, unsigned int *nplanes, |
752 | unsigned int sizes[], struct device *alloc_devs[]) |
753 | { |
754 | struct saa7134_dmaqueue *dmaq = q->drv_priv; |
755 | struct saa7134_dev *dev = dmaq->dev; |
756 | int size = dev->fmt->depth * dev->width * dev->height >> 3; |
757 | |
758 | if (dev->width < 48 || |
759 | dev->height < 32 || |
760 | dev->width/4 > dev->crop_current.width || |
761 | dev->height/4 > dev->crop_current.height || |
762 | dev->width > dev->crop_bounds.width || |
763 | dev->height > dev->crop_bounds.height) |
764 | return -EINVAL; |
765 | |
766 | *nbuffers = saa7134_buffer_count(size, count: *nbuffers); |
767 | *nplanes = 1; |
768 | sizes[0] = size; |
769 | |
770 | saa7134_enable_analog_tuner(dev); |
771 | |
772 | return 0; |
773 | } |
774 | |
775 | /* |
776 | * move buffer to hardware queue |
777 | */ |
778 | void saa7134_vb2_buffer_queue(struct vb2_buffer *vb) |
779 | { |
780 | struct saa7134_dmaqueue *dmaq = vb->vb2_queue->drv_priv; |
781 | struct saa7134_dev *dev = dmaq->dev; |
782 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); |
783 | struct saa7134_buf *buf = container_of(vbuf, struct saa7134_buf, vb2); |
784 | |
785 | saa7134_buffer_queue(dev, q: dmaq, buf); |
786 | } |
787 | EXPORT_SYMBOL_GPL(saa7134_vb2_buffer_queue); |
788 | |
789 | int saa7134_vb2_start_streaming(struct vb2_queue *vq, unsigned int count) |
790 | { |
791 | struct saa7134_dmaqueue *dmaq = vq->drv_priv; |
792 | struct saa7134_dev *dev = dmaq->dev; |
793 | |
794 | /* |
795 | * Planar video capture and TS share the same DMA channel, |
796 | * so only one can be active at a time. |
797 | */ |
798 | if (card_is_empress(dev) && vb2_is_busy(q: &dev->empress_vbq) && |
799 | dmaq == &dev->video_q && dev->fmt->planar) { |
800 | struct saa7134_buf *buf, *tmp; |
801 | |
802 | list_for_each_entry_safe(buf, tmp, &dmaq->queue, entry) { |
803 | list_del(entry: &buf->entry); |
804 | vb2_buffer_done(vb: &buf->vb2.vb2_buf, |
805 | state: VB2_BUF_STATE_QUEUED); |
806 | } |
807 | if (dmaq->curr) { |
808 | vb2_buffer_done(vb: &dmaq->curr->vb2.vb2_buf, |
809 | state: VB2_BUF_STATE_QUEUED); |
810 | dmaq->curr = NULL; |
811 | } |
812 | return -EBUSY; |
813 | } |
814 | |
815 | /* The SAA7134 has a 1K FIFO; the datasheet suggests that when |
816 | * configured conservatively, there's 22 usec of buffering for video. |
817 | * We therefore request a DMA latency of 20 usec, giving us 2 usec of |
818 | * margin in case the FIFO is configured differently to the datasheet. |
819 | * Unfortunately, I lack register-level documentation to check the |
820 | * Linux FIFO setup and confirm the perfect value. |
821 | */ |
822 | if ((dmaq == &dev->video_q && !vb2_is_streaming(q: &dev->vbi_vbq)) || |
823 | (dmaq == &dev->vbi_q && !vb2_is_streaming(q: &dev->video_vbq))) |
824 | cpu_latency_qos_add_request(req: &dev->qos_request, value: 20); |
825 | dmaq->seq_nr = 0; |
826 | |
827 | return 0; |
828 | } |
829 | |
830 | void saa7134_vb2_stop_streaming(struct vb2_queue *vq) |
831 | { |
832 | struct saa7134_dmaqueue *dmaq = vq->drv_priv; |
833 | struct saa7134_dev *dev = dmaq->dev; |
834 | |
835 | saa7134_stop_streaming(dev, q: dmaq); |
836 | |
837 | if ((dmaq == &dev->video_q && !vb2_is_streaming(q: &dev->vbi_vbq)) || |
838 | (dmaq == &dev->vbi_q && !vb2_is_streaming(q: &dev->video_vbq))) |
839 | cpu_latency_qos_remove_request(req: &dev->qos_request); |
840 | } |
841 | |
842 | static const struct vb2_ops vb2_qops = { |
843 | .queue_setup = queue_setup, |
844 | .buf_init = buffer_init, |
845 | .buf_prepare = buffer_prepare, |
846 | .buf_queue = saa7134_vb2_buffer_queue, |
847 | .wait_prepare = vb2_ops_wait_prepare, |
848 | .wait_finish = vb2_ops_wait_finish, |
849 | .start_streaming = saa7134_vb2_start_streaming, |
850 | .stop_streaming = saa7134_vb2_stop_streaming, |
851 | }; |
852 | |
853 | /* ------------------------------------------------------------------ */ |
854 | |
855 | static int saa7134_s_ctrl(struct v4l2_ctrl *ctrl) |
856 | { |
857 | struct saa7134_dev *dev = container_of(ctrl->handler, struct saa7134_dev, ctrl_handler); |
858 | |
859 | switch (ctrl->id) { |
860 | case V4L2_CID_BRIGHTNESS: |
861 | dev->ctl_bright = ctrl->val; |
862 | saa_writeb(SAA7134_DEC_LUMA_BRIGHT, ctrl->val); |
863 | break; |
864 | case V4L2_CID_HUE: |
865 | dev->ctl_hue = ctrl->val; |
866 | saa_writeb(SAA7134_DEC_CHROMA_HUE, ctrl->val); |
867 | break; |
868 | case V4L2_CID_CONTRAST: |
869 | dev->ctl_contrast = ctrl->val; |
870 | saa_writeb(SAA7134_DEC_LUMA_CONTRAST, |
871 | dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast); |
872 | break; |
873 | case V4L2_CID_SATURATION: |
874 | dev->ctl_saturation = ctrl->val; |
875 | saa_writeb(SAA7134_DEC_CHROMA_SATURATION, |
876 | dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation); |
877 | break; |
878 | case V4L2_CID_AUDIO_MUTE: |
879 | dev->ctl_mute = ctrl->val; |
880 | saa7134_tvaudio_setmute(dev); |
881 | break; |
882 | case V4L2_CID_AUDIO_VOLUME: |
883 | dev->ctl_volume = ctrl->val; |
884 | saa7134_tvaudio_setvolume(dev,level: dev->ctl_volume); |
885 | break; |
886 | case V4L2_CID_PRIVATE_INVERT: |
887 | dev->ctl_invert = ctrl->val; |
888 | saa_writeb(SAA7134_DEC_LUMA_CONTRAST, |
889 | dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast); |
890 | saa_writeb(SAA7134_DEC_CHROMA_SATURATION, |
891 | dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation); |
892 | break; |
893 | case V4L2_CID_HFLIP: |
894 | dev->ctl_mirror = ctrl->val; |
895 | break; |
896 | case V4L2_CID_PRIVATE_Y_EVEN: |
897 | dev->ctl_y_even = ctrl->val; |
898 | break; |
899 | case V4L2_CID_PRIVATE_Y_ODD: |
900 | dev->ctl_y_odd = ctrl->val; |
901 | break; |
902 | case V4L2_CID_PRIVATE_AUTOMUTE: |
903 | { |
904 | struct v4l2_priv_tun_config tda9887_cfg; |
905 | |
906 | tda9887_cfg.tuner = TUNER_TDA9887; |
907 | tda9887_cfg.priv = &dev->tda9887_conf; |
908 | |
909 | dev->ctl_automute = ctrl->val; |
910 | if (dev->tda9887_conf) { |
911 | if (dev->ctl_automute) |
912 | dev->tda9887_conf |= TDA9887_AUTOMUTE; |
913 | else |
914 | dev->tda9887_conf &= ~TDA9887_AUTOMUTE; |
915 | |
916 | saa_call_all(dev, tuner, s_config, &tda9887_cfg); |
917 | } |
918 | break; |
919 | } |
920 | default: |
921 | return -EINVAL; |
922 | } |
923 | return 0; |
924 | } |
925 | |
926 | /* ------------------------------------------------------------------ */ |
927 | |
928 | static int video_open(struct file *file) |
929 | { |
930 | struct video_device *vdev = video_devdata(file); |
931 | struct saa7134_dev *dev = video_drvdata(file); |
932 | int ret = v4l2_fh_open(filp: file); |
933 | |
934 | if (ret < 0) |
935 | return ret; |
936 | |
937 | mutex_lock(&dev->lock); |
938 | if (vdev->vfl_type == VFL_TYPE_RADIO) { |
939 | /* switch to radio mode */ |
940 | saa7134_tvaudio_setinput(dev, in: &card(dev).radio); |
941 | saa_call_all(dev, tuner, s_radio); |
942 | } else { |
943 | /* switch to video/vbi mode */ |
944 | video_mux(dev, input: dev->ctl_input); |
945 | } |
946 | mutex_unlock(lock: &dev->lock); |
947 | |
948 | return 0; |
949 | } |
950 | |
951 | static int video_release(struct file *file) |
952 | { |
953 | struct video_device *vdev = video_devdata(file); |
954 | struct saa7134_dev *dev = video_drvdata(file); |
955 | struct saa6588_command cmd; |
956 | |
957 | mutex_lock(&dev->lock); |
958 | saa7134_tvaudio_close(dev); |
959 | |
960 | if (vdev->vfl_type == VFL_TYPE_RADIO) |
961 | v4l2_fh_release(filp: file); |
962 | else |
963 | _vb2_fop_release(file, NULL); |
964 | |
965 | /* ts-capture will not work in planar mode, so turn it off Hac: 04.05*/ |
966 | saa_andorb(SAA7134_OFMT_VIDEO_A, 0x1f, 0); |
967 | saa_andorb(SAA7134_OFMT_VIDEO_B, 0x1f, 0); |
968 | saa_andorb(SAA7134_OFMT_DATA_A, 0x1f, 0); |
969 | saa_andorb(SAA7134_OFMT_DATA_B, 0x1f, 0); |
970 | |
971 | saa_call_all(dev, tuner, standby); |
972 | if (vdev->vfl_type == VFL_TYPE_RADIO) |
973 | saa_call_all(dev, core, command, SAA6588_CMD_CLOSE, &cmd); |
974 | mutex_unlock(lock: &dev->lock); |
975 | |
976 | return 0; |
977 | } |
978 | |
979 | static ssize_t radio_read(struct file *file, char __user *data, |
980 | size_t count, loff_t *ppos) |
981 | { |
982 | struct saa7134_dev *dev = video_drvdata(file); |
983 | struct saa6588_command cmd; |
984 | |
985 | cmd.block_count = count/3; |
986 | cmd.nonblocking = file->f_flags & O_NONBLOCK; |
987 | cmd.buffer = data; |
988 | cmd.instance = file; |
989 | cmd.result = -ENODEV; |
990 | |
991 | mutex_lock(&dev->lock); |
992 | saa_call_all(dev, core, command, SAA6588_CMD_READ, &cmd); |
993 | mutex_unlock(lock: &dev->lock); |
994 | |
995 | return cmd.result; |
996 | } |
997 | |
998 | static __poll_t radio_poll(struct file *file, poll_table *wait) |
999 | { |
1000 | struct saa7134_dev *dev = video_drvdata(file); |
1001 | struct saa6588_command cmd; |
1002 | __poll_t rc = v4l2_ctrl_poll(file, wait); |
1003 | |
1004 | cmd.instance = file; |
1005 | cmd.event_list = wait; |
1006 | cmd.poll_mask = 0; |
1007 | mutex_lock(&dev->lock); |
1008 | saa_call_all(dev, core, command, SAA6588_CMD_POLL, &cmd); |
1009 | mutex_unlock(lock: &dev->lock); |
1010 | |
1011 | return rc | cmd.poll_mask; |
1012 | } |
1013 | |
1014 | /* ------------------------------------------------------------------ */ |
1015 | |
1016 | static int saa7134_try_get_set_fmt_vbi_cap(struct file *file, void *priv, |
1017 | struct v4l2_format *f) |
1018 | { |
1019 | struct saa7134_dev *dev = video_drvdata(file); |
1020 | struct saa7134_tvnorm *norm = dev->tvnorm; |
1021 | |
1022 | memset(&f->fmt.vbi.reserved, 0, sizeof(f->fmt.vbi.reserved)); |
1023 | f->fmt.vbi.sampling_rate = 6750000 * 4; |
1024 | f->fmt.vbi.samples_per_line = 2048 /* VBI_LINE_LENGTH */; |
1025 | f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; |
1026 | f->fmt.vbi.offset = 64 * 4; |
1027 | f->fmt.vbi.start[0] = norm->vbi_v_start_0; |
1028 | f->fmt.vbi.count[0] = norm->vbi_v_stop_0 - norm->vbi_v_start_0 +1; |
1029 | f->fmt.vbi.start[1] = norm->vbi_v_start_1; |
1030 | f->fmt.vbi.count[1] = f->fmt.vbi.count[0]; |
1031 | f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */ |
1032 | |
1033 | return 0; |
1034 | } |
1035 | |
1036 | static int saa7134_g_fmt_vid_cap(struct file *file, void *priv, |
1037 | struct v4l2_format *f) |
1038 | { |
1039 | struct saa7134_dev *dev = video_drvdata(file); |
1040 | |
1041 | f->fmt.pix.width = dev->width; |
1042 | f->fmt.pix.height = dev->height; |
1043 | f->fmt.pix.field = dev->field; |
1044 | f->fmt.pix.pixelformat = dev->fmt->fourcc; |
1045 | if (dev->fmt->planar) |
1046 | f->fmt.pix.bytesperline = f->fmt.pix.width; |
1047 | else |
1048 | f->fmt.pix.bytesperline = |
1049 | (f->fmt.pix.width * dev->fmt->depth) / 8; |
1050 | f->fmt.pix.sizeimage = |
1051 | (f->fmt.pix.height * f->fmt.pix.width * dev->fmt->depth) / 8; |
1052 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; |
1053 | return 0; |
1054 | } |
1055 | |
1056 | static int saa7134_try_fmt_vid_cap(struct file *file, void *priv, |
1057 | struct v4l2_format *f) |
1058 | { |
1059 | struct saa7134_dev *dev = video_drvdata(file); |
1060 | struct saa7134_format *fmt; |
1061 | enum v4l2_field field; |
1062 | unsigned int maxw, maxh; |
1063 | |
1064 | fmt = format_by_fourcc(fourcc: f->fmt.pix.pixelformat); |
1065 | if (NULL == fmt) |
1066 | return -EINVAL; |
1067 | |
1068 | field = f->fmt.pix.field; |
1069 | maxw = min(dev->crop_current.width*4, dev->crop_bounds.width); |
1070 | maxh = min(dev->crop_current.height*4, dev->crop_bounds.height); |
1071 | |
1072 | if (V4L2_FIELD_ANY == field) { |
1073 | field = (f->fmt.pix.height > maxh/2) |
1074 | ? V4L2_FIELD_INTERLACED |
1075 | : V4L2_FIELD_BOTTOM; |
1076 | } |
1077 | switch (field) { |
1078 | case V4L2_FIELD_TOP: |
1079 | case V4L2_FIELD_BOTTOM: |
1080 | maxh = maxh / 2; |
1081 | break; |
1082 | default: |
1083 | field = V4L2_FIELD_INTERLACED; |
1084 | break; |
1085 | } |
1086 | |
1087 | f->fmt.pix.field = field; |
1088 | if (f->fmt.pix.width < 48) |
1089 | f->fmt.pix.width = 48; |
1090 | if (f->fmt.pix.height < 32) |
1091 | f->fmt.pix.height = 32; |
1092 | if (f->fmt.pix.width > maxw) |
1093 | f->fmt.pix.width = maxw; |
1094 | if (f->fmt.pix.height > maxh) |
1095 | f->fmt.pix.height = maxh; |
1096 | f->fmt.pix.width &= ~0x03; |
1097 | if (fmt->planar) |
1098 | f->fmt.pix.bytesperline = f->fmt.pix.width; |
1099 | else |
1100 | f->fmt.pix.bytesperline = |
1101 | (f->fmt.pix.width * fmt->depth) / 8; |
1102 | f->fmt.pix.sizeimage = |
1103 | (f->fmt.pix.height * f->fmt.pix.width * fmt->depth) / 8; |
1104 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; |
1105 | |
1106 | return 0; |
1107 | } |
1108 | |
1109 | static int saa7134_s_fmt_vid_cap(struct file *file, void *priv, |
1110 | struct v4l2_format *f) |
1111 | { |
1112 | struct saa7134_dev *dev = video_drvdata(file); |
1113 | int err; |
1114 | |
1115 | err = saa7134_try_fmt_vid_cap(file, priv, f); |
1116 | if (0 != err) |
1117 | return err; |
1118 | |
1119 | dev->fmt = format_by_fourcc(fourcc: f->fmt.pix.pixelformat); |
1120 | dev->width = f->fmt.pix.width; |
1121 | dev->height = f->fmt.pix.height; |
1122 | dev->field = f->fmt.pix.field; |
1123 | return 0; |
1124 | } |
1125 | |
1126 | int saa7134_enum_input(struct file *file, void *priv, struct v4l2_input *i) |
1127 | { |
1128 | struct saa7134_dev *dev = video_drvdata(file); |
1129 | unsigned int n; |
1130 | |
1131 | n = i->index; |
1132 | if (n >= SAA7134_INPUT_MAX) |
1133 | return -EINVAL; |
1134 | if (card_in(dev, i->index).type == SAA7134_NO_INPUT) |
1135 | return -EINVAL; |
1136 | i->index = n; |
1137 | strscpy(i->name, saa7134_input_name[card_in(dev, n).type], |
1138 | sizeof(i->name)); |
1139 | switch (card_in(dev, n).type) { |
1140 | case SAA7134_INPUT_TV: |
1141 | case SAA7134_INPUT_TV_MONO: |
1142 | i->type = V4L2_INPUT_TYPE_TUNER; |
1143 | break; |
1144 | default: |
1145 | i->type = V4L2_INPUT_TYPE_CAMERA; |
1146 | break; |
1147 | } |
1148 | if (n == dev->ctl_input) { |
1149 | int v1 = saa_readb(SAA7134_STATUS_VIDEO1); |
1150 | int v2 = saa_readb(SAA7134_STATUS_VIDEO2); |
1151 | |
1152 | if (0 != (v1 & 0x40)) |
1153 | i->status |= V4L2_IN_ST_NO_H_LOCK; |
1154 | if (0 != (v2 & 0x40)) |
1155 | i->status |= V4L2_IN_ST_NO_SIGNAL; |
1156 | if (0 != (v2 & 0x0e)) |
1157 | i->status |= V4L2_IN_ST_MACROVISION; |
1158 | } |
1159 | i->std = SAA7134_NORMS; |
1160 | return 0; |
1161 | } |
1162 | EXPORT_SYMBOL_GPL(saa7134_enum_input); |
1163 | |
1164 | int saa7134_g_input(struct file *file, void *priv, unsigned int *i) |
1165 | { |
1166 | struct saa7134_dev *dev = video_drvdata(file); |
1167 | |
1168 | *i = dev->ctl_input; |
1169 | return 0; |
1170 | } |
1171 | EXPORT_SYMBOL_GPL(saa7134_g_input); |
1172 | |
1173 | int saa7134_s_input(struct file *file, void *priv, unsigned int i) |
1174 | { |
1175 | struct saa7134_dev *dev = video_drvdata(file); |
1176 | |
1177 | if (i >= SAA7134_INPUT_MAX) |
1178 | return -EINVAL; |
1179 | if (card_in(dev, i).type == SAA7134_NO_INPUT) |
1180 | return -EINVAL; |
1181 | video_mux(dev, input: i); |
1182 | return 0; |
1183 | } |
1184 | EXPORT_SYMBOL_GPL(saa7134_s_input); |
1185 | |
1186 | int saa7134_querycap(struct file *file, void *priv, |
1187 | struct v4l2_capability *cap) |
1188 | { |
1189 | struct saa7134_dev *dev = video_drvdata(file); |
1190 | |
1191 | strscpy(cap->driver, "saa7134" , sizeof(cap->driver)); |
1192 | strscpy(cap->card, saa7134_boards[dev->board].name, |
1193 | sizeof(cap->card)); |
1194 | cap->capabilities = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | |
1195 | V4L2_CAP_RADIO | V4L2_CAP_VIDEO_CAPTURE | |
1196 | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_DEVICE_CAPS; |
1197 | if (dev->tuner_type != TUNER_ABSENT && dev->tuner_type != UNSET) |
1198 | cap->capabilities |= V4L2_CAP_TUNER; |
1199 | if (dev->has_rds) |
1200 | cap->capabilities |= V4L2_CAP_RDS_CAPTURE; |
1201 | |
1202 | return 0; |
1203 | } |
1204 | EXPORT_SYMBOL_GPL(saa7134_querycap); |
1205 | |
1206 | int saa7134_s_std(struct file *file, void *priv, v4l2_std_id id) |
1207 | { |
1208 | struct saa7134_dev *dev = video_drvdata(file); |
1209 | unsigned int i; |
1210 | v4l2_std_id fixup; |
1211 | |
1212 | for (i = 0; i < TVNORMS; i++) |
1213 | if (id == tvnorms[i].id) |
1214 | break; |
1215 | |
1216 | if (i == TVNORMS) |
1217 | for (i = 0; i < TVNORMS; i++) |
1218 | if (id & tvnorms[i].id) |
1219 | break; |
1220 | if (i == TVNORMS) |
1221 | return -EINVAL; |
1222 | |
1223 | if ((id & V4L2_STD_SECAM) && (secam[0] != '-')) { |
1224 | if (secam[0] == 'L' || secam[0] == 'l') { |
1225 | if (secam[1] == 'C' || secam[1] == 'c') |
1226 | fixup = V4L2_STD_SECAM_LC; |
1227 | else |
1228 | fixup = V4L2_STD_SECAM_L; |
1229 | } else { |
1230 | if (secam[0] == 'D' || secam[0] == 'd') |
1231 | fixup = V4L2_STD_SECAM_DK; |
1232 | else |
1233 | fixup = V4L2_STD_SECAM; |
1234 | } |
1235 | for (i = 0; i < TVNORMS; i++) { |
1236 | if (fixup == tvnorms[i].id) |
1237 | break; |
1238 | } |
1239 | if (i == TVNORMS) |
1240 | return -EINVAL; |
1241 | } |
1242 | |
1243 | set_tvnorm(dev, norm: &tvnorms[i]); |
1244 | |
1245 | saa7134_tvaudio_do_scan(dev); |
1246 | return 0; |
1247 | } |
1248 | EXPORT_SYMBOL_GPL(saa7134_s_std); |
1249 | |
1250 | int saa7134_g_std(struct file *file, void *priv, v4l2_std_id *id) |
1251 | { |
1252 | struct saa7134_dev *dev = video_drvdata(file); |
1253 | |
1254 | *id = dev->tvnorm->id; |
1255 | return 0; |
1256 | } |
1257 | EXPORT_SYMBOL_GPL(saa7134_g_std); |
1258 | |
1259 | static v4l2_std_id saa7134_read_std(struct saa7134_dev *dev) |
1260 | { |
1261 | static v4l2_std_id stds[] = { |
1262 | V4L2_STD_UNKNOWN, |
1263 | V4L2_STD_NTSC, |
1264 | V4L2_STD_PAL, |
1265 | V4L2_STD_SECAM }; |
1266 | |
1267 | v4l2_std_id result = 0; |
1268 | |
1269 | u8 st1 = saa_readb(SAA7134_STATUS_VIDEO1); |
1270 | u8 st2 = saa_readb(SAA7134_STATUS_VIDEO2); |
1271 | |
1272 | if (!(st2 & 0x1)) /* RDCAP == 0 */ |
1273 | result = V4L2_STD_UNKNOWN; |
1274 | else |
1275 | result = stds[st1 & 0x03]; |
1276 | |
1277 | return result; |
1278 | } |
1279 | |
1280 | int saa7134_querystd(struct file *file, void *priv, v4l2_std_id *std) |
1281 | { |
1282 | struct saa7134_dev *dev = video_drvdata(file); |
1283 | *std &= saa7134_read_std(dev); |
1284 | return 0; |
1285 | } |
1286 | EXPORT_SYMBOL_GPL(saa7134_querystd); |
1287 | |
1288 | static int saa7134_g_pixelaspect(struct file *file, void *priv, |
1289 | int type, struct v4l2_fract *f) |
1290 | { |
1291 | struct saa7134_dev *dev = video_drvdata(file); |
1292 | |
1293 | if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1294 | return -EINVAL; |
1295 | |
1296 | if (dev->tvnorm->id & V4L2_STD_525_60) { |
1297 | f->numerator = 11; |
1298 | f->denominator = 10; |
1299 | } |
1300 | if (dev->tvnorm->id & V4L2_STD_625_50) { |
1301 | f->numerator = 54; |
1302 | f->denominator = 59; |
1303 | } |
1304 | return 0; |
1305 | } |
1306 | |
1307 | static int saa7134_g_selection(struct file *file, void *f, struct v4l2_selection *sel) |
1308 | { |
1309 | struct saa7134_dev *dev = video_drvdata(file); |
1310 | |
1311 | if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1312 | return -EINVAL; |
1313 | |
1314 | switch (sel->target) { |
1315 | case V4L2_SEL_TGT_CROP: |
1316 | sel->r = dev->crop_current; |
1317 | break; |
1318 | case V4L2_SEL_TGT_CROP_DEFAULT: |
1319 | sel->r = dev->crop_defrect; |
1320 | break; |
1321 | case V4L2_SEL_TGT_CROP_BOUNDS: |
1322 | sel->r = dev->crop_bounds; |
1323 | break; |
1324 | default: |
1325 | return -EINVAL; |
1326 | } |
1327 | return 0; |
1328 | } |
1329 | |
1330 | static int saa7134_s_selection(struct file *file, void *f, struct v4l2_selection *sel) |
1331 | { |
1332 | struct saa7134_dev *dev = video_drvdata(file); |
1333 | struct v4l2_rect *b = &dev->crop_bounds; |
1334 | struct v4l2_rect *c = &dev->crop_current; |
1335 | |
1336 | if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1337 | return -EINVAL; |
1338 | |
1339 | if (sel->target != V4L2_SEL_TGT_CROP) |
1340 | return -EINVAL; |
1341 | |
1342 | if (vb2_is_streaming(q: &dev->video_vbq)) |
1343 | return -EBUSY; |
1344 | |
1345 | *c = sel->r; |
1346 | if (c->top < b->top) |
1347 | c->top = b->top; |
1348 | if (c->top > b->top + b->height) |
1349 | c->top = b->top + b->height; |
1350 | if (c->height > b->top - c->top + b->height) |
1351 | c->height = b->top - c->top + b->height; |
1352 | |
1353 | if (c->left < b->left) |
1354 | c->left = b->left; |
1355 | if (c->left > b->left + b->width) |
1356 | c->left = b->left + b->width; |
1357 | if (c->width > b->left - c->left + b->width) |
1358 | c->width = b->left - c->left + b->width; |
1359 | sel->r = *c; |
1360 | return 0; |
1361 | } |
1362 | |
1363 | int saa7134_g_tuner(struct file *file, void *priv, |
1364 | struct v4l2_tuner *t) |
1365 | { |
1366 | struct saa7134_dev *dev = video_drvdata(file); |
1367 | int n; |
1368 | |
1369 | if (0 != t->index) |
1370 | return -EINVAL; |
1371 | memset(t, 0, sizeof(*t)); |
1372 | for (n = 0; n < SAA7134_INPUT_MAX; n++) { |
1373 | if (card_in(dev, n).type == SAA7134_INPUT_TV || |
1374 | card_in(dev, n).type == SAA7134_INPUT_TV_MONO) |
1375 | break; |
1376 | } |
1377 | if (n == SAA7134_INPUT_MAX) |
1378 | return -EINVAL; |
1379 | if (card_in(dev, n).type != SAA7134_NO_INPUT) { |
1380 | strscpy(t->name, "Television" , sizeof(t->name)); |
1381 | t->type = V4L2_TUNER_ANALOG_TV; |
1382 | saa_call_all(dev, tuner, g_tuner, t); |
1383 | t->capability = V4L2_TUNER_CAP_NORM | |
1384 | V4L2_TUNER_CAP_STEREO | |
1385 | V4L2_TUNER_CAP_LANG1 | |
1386 | V4L2_TUNER_CAP_LANG2; |
1387 | t->rxsubchans = saa7134_tvaudio_getstereo(dev); |
1388 | t->audmode = saa7134_tvaudio_rx2mode(rx: t->rxsubchans); |
1389 | } |
1390 | if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03)) |
1391 | t->signal = 0xffff; |
1392 | return 0; |
1393 | } |
1394 | EXPORT_SYMBOL_GPL(saa7134_g_tuner); |
1395 | |
1396 | int saa7134_s_tuner(struct file *file, void *priv, |
1397 | const struct v4l2_tuner *t) |
1398 | { |
1399 | struct saa7134_dev *dev = video_drvdata(file); |
1400 | int rx, mode; |
1401 | |
1402 | if (0 != t->index) |
1403 | return -EINVAL; |
1404 | |
1405 | mode = dev->thread.mode; |
1406 | if (UNSET == mode) { |
1407 | rx = saa7134_tvaudio_getstereo(dev); |
1408 | mode = saa7134_tvaudio_rx2mode(rx); |
1409 | } |
1410 | if (mode != t->audmode) |
1411 | dev->thread.mode = t->audmode; |
1412 | |
1413 | return 0; |
1414 | } |
1415 | EXPORT_SYMBOL_GPL(saa7134_s_tuner); |
1416 | |
1417 | int saa7134_g_frequency(struct file *file, void *priv, |
1418 | struct v4l2_frequency *f) |
1419 | { |
1420 | struct saa7134_dev *dev = video_drvdata(file); |
1421 | |
1422 | if (0 != f->tuner) |
1423 | return -EINVAL; |
1424 | |
1425 | saa_call_all(dev, tuner, g_frequency, f); |
1426 | |
1427 | return 0; |
1428 | } |
1429 | EXPORT_SYMBOL_GPL(saa7134_g_frequency); |
1430 | |
1431 | int saa7134_s_frequency(struct file *file, void *priv, |
1432 | const struct v4l2_frequency *f) |
1433 | { |
1434 | struct saa7134_dev *dev = video_drvdata(file); |
1435 | |
1436 | if (0 != f->tuner) |
1437 | return -EINVAL; |
1438 | |
1439 | saa_call_all(dev, tuner, s_frequency, f); |
1440 | |
1441 | saa7134_tvaudio_do_scan(dev); |
1442 | return 0; |
1443 | } |
1444 | EXPORT_SYMBOL_GPL(saa7134_s_frequency); |
1445 | |
1446 | static int saa7134_enum_fmt_vid_cap(struct file *file, void *priv, |
1447 | struct v4l2_fmtdesc *f) |
1448 | { |
1449 | if (f->index >= FORMATS) |
1450 | return -EINVAL; |
1451 | |
1452 | f->pixelformat = formats[f->index].fourcc; |
1453 | |
1454 | return 0; |
1455 | } |
1456 | |
1457 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
1458 | static int vidioc_g_register (struct file *file, void *priv, |
1459 | struct v4l2_dbg_register *reg) |
1460 | { |
1461 | struct saa7134_dev *dev = video_drvdata(file); |
1462 | |
1463 | reg->val = saa_readb(reg->reg & 0xffffff); |
1464 | reg->size = 1; |
1465 | return 0; |
1466 | } |
1467 | |
1468 | static int vidioc_s_register (struct file *file, void *priv, |
1469 | const struct v4l2_dbg_register *reg) |
1470 | { |
1471 | struct saa7134_dev *dev = video_drvdata(file); |
1472 | |
1473 | saa_writeb(reg->reg & 0xffffff, reg->val); |
1474 | return 0; |
1475 | } |
1476 | #endif |
1477 | |
1478 | static int radio_g_tuner(struct file *file, void *priv, |
1479 | struct v4l2_tuner *t) |
1480 | { |
1481 | struct saa7134_dev *dev = video_drvdata(file); |
1482 | |
1483 | if (0 != t->index) |
1484 | return -EINVAL; |
1485 | |
1486 | strscpy(t->name, "Radio" , sizeof(t->name)); |
1487 | |
1488 | saa_call_all(dev, tuner, g_tuner, t); |
1489 | t->audmode &= V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO; |
1490 | if (dev->input->amux == TV) { |
1491 | t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11); |
1492 | t->rxsubchans = (saa_readb(0x529) & 0x08) ? |
1493 | V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; |
1494 | } |
1495 | return 0; |
1496 | } |
1497 | static int radio_s_tuner(struct file *file, void *priv, |
1498 | const struct v4l2_tuner *t) |
1499 | { |
1500 | struct saa7134_dev *dev = video_drvdata(file); |
1501 | |
1502 | if (0 != t->index) |
1503 | return -EINVAL; |
1504 | |
1505 | saa_call_all(dev, tuner, s_tuner, t); |
1506 | return 0; |
1507 | } |
1508 | |
1509 | static const struct v4l2_file_operations video_fops = |
1510 | { |
1511 | .owner = THIS_MODULE, |
1512 | .open = video_open, |
1513 | .release = video_release, |
1514 | .read = vb2_fop_read, |
1515 | .poll = vb2_fop_poll, |
1516 | .mmap = vb2_fop_mmap, |
1517 | .unlocked_ioctl = video_ioctl2, |
1518 | }; |
1519 | |
1520 | static const struct v4l2_ioctl_ops video_ioctl_ops = { |
1521 | .vidioc_querycap = saa7134_querycap, |
1522 | .vidioc_enum_fmt_vid_cap = saa7134_enum_fmt_vid_cap, |
1523 | .vidioc_g_fmt_vid_cap = saa7134_g_fmt_vid_cap, |
1524 | .vidioc_try_fmt_vid_cap = saa7134_try_fmt_vid_cap, |
1525 | .vidioc_s_fmt_vid_cap = saa7134_s_fmt_vid_cap, |
1526 | .vidioc_g_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap, |
1527 | .vidioc_try_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap, |
1528 | .vidioc_s_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap, |
1529 | .vidioc_g_pixelaspect = saa7134_g_pixelaspect, |
1530 | .vidioc_reqbufs = vb2_ioctl_reqbufs, |
1531 | .vidioc_querybuf = vb2_ioctl_querybuf, |
1532 | .vidioc_qbuf = vb2_ioctl_qbuf, |
1533 | .vidioc_dqbuf = vb2_ioctl_dqbuf, |
1534 | .vidioc_expbuf = vb2_ioctl_expbuf, |
1535 | .vidioc_s_std = saa7134_s_std, |
1536 | .vidioc_g_std = saa7134_g_std, |
1537 | .vidioc_querystd = saa7134_querystd, |
1538 | .vidioc_enum_input = saa7134_enum_input, |
1539 | .vidioc_g_input = saa7134_g_input, |
1540 | .vidioc_s_input = saa7134_s_input, |
1541 | .vidioc_streamon = vb2_ioctl_streamon, |
1542 | .vidioc_streamoff = vb2_ioctl_streamoff, |
1543 | .vidioc_g_tuner = saa7134_g_tuner, |
1544 | .vidioc_s_tuner = saa7134_s_tuner, |
1545 | .vidioc_g_selection = saa7134_g_selection, |
1546 | .vidioc_s_selection = saa7134_s_selection, |
1547 | .vidioc_g_frequency = saa7134_g_frequency, |
1548 | .vidioc_s_frequency = saa7134_s_frequency, |
1549 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
1550 | .vidioc_g_register = vidioc_g_register, |
1551 | .vidioc_s_register = vidioc_s_register, |
1552 | #endif |
1553 | .vidioc_log_status = v4l2_ctrl_log_status, |
1554 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, |
1555 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, |
1556 | }; |
1557 | |
1558 | static const struct v4l2_file_operations radio_fops = { |
1559 | .owner = THIS_MODULE, |
1560 | .open = video_open, |
1561 | .read = radio_read, |
1562 | .release = video_release, |
1563 | .unlocked_ioctl = video_ioctl2, |
1564 | .poll = radio_poll, |
1565 | }; |
1566 | |
1567 | static const struct v4l2_ioctl_ops radio_ioctl_ops = { |
1568 | .vidioc_querycap = saa7134_querycap, |
1569 | .vidioc_g_tuner = radio_g_tuner, |
1570 | .vidioc_s_tuner = radio_s_tuner, |
1571 | .vidioc_g_frequency = saa7134_g_frequency, |
1572 | .vidioc_s_frequency = saa7134_s_frequency, |
1573 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, |
1574 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, |
1575 | }; |
1576 | |
1577 | /* ----------------------------------------------------------- */ |
1578 | /* exported stuff */ |
1579 | |
1580 | struct video_device saa7134_video_template = { |
1581 | .name = "saa7134-video" , |
1582 | .fops = &video_fops, |
1583 | .ioctl_ops = &video_ioctl_ops, |
1584 | .tvnorms = SAA7134_NORMS, |
1585 | }; |
1586 | |
1587 | struct video_device saa7134_radio_template = { |
1588 | .name = "saa7134-radio" , |
1589 | .fops = &radio_fops, |
1590 | .ioctl_ops = &radio_ioctl_ops, |
1591 | }; |
1592 | |
1593 | static const struct v4l2_ctrl_ops saa7134_ctrl_ops = { |
1594 | .s_ctrl = saa7134_s_ctrl, |
1595 | }; |
1596 | |
1597 | static const struct v4l2_ctrl_config saa7134_ctrl_invert = { |
1598 | .ops = &saa7134_ctrl_ops, |
1599 | .id = V4L2_CID_PRIVATE_INVERT, |
1600 | .name = "Invert" , |
1601 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
1602 | .min = 0, |
1603 | .max = 1, |
1604 | .step = 1, |
1605 | }; |
1606 | |
1607 | static const struct v4l2_ctrl_config saa7134_ctrl_y_odd = { |
1608 | .ops = &saa7134_ctrl_ops, |
1609 | .id = V4L2_CID_PRIVATE_Y_ODD, |
1610 | .name = "Y Offset Odd Field" , |
1611 | .type = V4L2_CTRL_TYPE_INTEGER, |
1612 | .min = 0, |
1613 | .max = 128, |
1614 | .step = 1, |
1615 | }; |
1616 | |
1617 | static const struct v4l2_ctrl_config saa7134_ctrl_y_even = { |
1618 | .ops = &saa7134_ctrl_ops, |
1619 | .id = V4L2_CID_PRIVATE_Y_EVEN, |
1620 | .name = "Y Offset Even Field" , |
1621 | .type = V4L2_CTRL_TYPE_INTEGER, |
1622 | .min = 0, |
1623 | .max = 128, |
1624 | .step = 1, |
1625 | }; |
1626 | |
1627 | static const struct v4l2_ctrl_config saa7134_ctrl_automute = { |
1628 | .ops = &saa7134_ctrl_ops, |
1629 | .id = V4L2_CID_PRIVATE_AUTOMUTE, |
1630 | .name = "Automute" , |
1631 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
1632 | .min = 0, |
1633 | .max = 1, |
1634 | .step = 1, |
1635 | .def = 1, |
1636 | }; |
1637 | |
1638 | int saa7134_video_init1(struct saa7134_dev *dev) |
1639 | { |
1640 | struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler; |
1641 | struct vb2_queue *q; |
1642 | int ret; |
1643 | |
1644 | /* sanitycheck insmod options */ |
1645 | if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME) |
1646 | gbuffers = 2; |
1647 | if (gbufsize > gbufsize_max) |
1648 | gbufsize = gbufsize_max; |
1649 | gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK; |
1650 | |
1651 | v4l2_ctrl_handler_init(hdl, 11); |
1652 | v4l2_ctrl_new_std(hdl, ops: &saa7134_ctrl_ops, |
1653 | V4L2_CID_BRIGHTNESS, min: 0, max: 255, step: 1, def: 128); |
1654 | v4l2_ctrl_new_std(hdl, ops: &saa7134_ctrl_ops, |
1655 | V4L2_CID_CONTRAST, min: 0, max: 127, step: 1, def: 68); |
1656 | v4l2_ctrl_new_std(hdl, ops: &saa7134_ctrl_ops, |
1657 | V4L2_CID_SATURATION, min: 0, max: 127, step: 1, def: 64); |
1658 | v4l2_ctrl_new_std(hdl, ops: &saa7134_ctrl_ops, |
1659 | V4L2_CID_HUE, min: -128, max: 127, step: 1, def: 0); |
1660 | v4l2_ctrl_new_std(hdl, ops: &saa7134_ctrl_ops, |
1661 | V4L2_CID_HFLIP, min: 0, max: 1, step: 1, def: 0); |
1662 | v4l2_ctrl_new_std(hdl, ops: &saa7134_ctrl_ops, |
1663 | V4L2_CID_AUDIO_MUTE, min: 0, max: 1, step: 1, def: 0); |
1664 | v4l2_ctrl_new_std(hdl, ops: &saa7134_ctrl_ops, |
1665 | V4L2_CID_AUDIO_VOLUME, min: -15, max: 15, step: 1, def: 0); |
1666 | v4l2_ctrl_new_custom(hdl, cfg: &saa7134_ctrl_invert, NULL); |
1667 | v4l2_ctrl_new_custom(hdl, cfg: &saa7134_ctrl_y_odd, NULL); |
1668 | v4l2_ctrl_new_custom(hdl, cfg: &saa7134_ctrl_y_even, NULL); |
1669 | v4l2_ctrl_new_custom(hdl, cfg: &saa7134_ctrl_automute, NULL); |
1670 | if (hdl->error) |
1671 | return hdl->error; |
1672 | if (card_has_radio(dev)) { |
1673 | hdl = &dev->radio_ctrl_handler; |
1674 | v4l2_ctrl_handler_init(hdl, 2); |
1675 | v4l2_ctrl_add_handler(hdl, add: &dev->ctrl_handler, |
1676 | filter: v4l2_ctrl_radio_filter, from_other_dev: false); |
1677 | if (hdl->error) |
1678 | return hdl->error; |
1679 | } |
1680 | dev->ctl_mute = 1; |
1681 | |
1682 | if (dev->tda9887_conf && saa7134_ctrl_automute.def) |
1683 | dev->tda9887_conf |= TDA9887_AUTOMUTE; |
1684 | dev->automute = 0; |
1685 | |
1686 | INIT_LIST_HEAD(list: &dev->video_q.queue); |
1687 | timer_setup(&dev->video_q.timeout, saa7134_buffer_timeout, 0); |
1688 | dev->video_q.dev = dev; |
1689 | dev->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); |
1690 | dev->width = 720; |
1691 | dev->height = 576; |
1692 | dev->field = V4L2_FIELD_INTERLACED; |
1693 | |
1694 | if (saa7134_boards[dev->board].video_out) |
1695 | saa7134_videoport_init(dev); |
1696 | |
1697 | q = &dev->video_vbq; |
1698 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
1699 | /* |
1700 | * Do not add VB2_USERPTR unless explicitly requested: the saa7134 DMA |
1701 | * engine cannot handle transfers that do not start at the beginning |
1702 | * of a page. A user-provided pointer can start anywhere in a page, so |
1703 | * USERPTR support is a no-go unless the application knows about these |
1704 | * limitations and has special support for this. |
1705 | */ |
1706 | q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; |
1707 | if (saa7134_userptr) |
1708 | q->io_modes |= VB2_USERPTR; |
1709 | q->drv_priv = &dev->video_q; |
1710 | q->ops = &vb2_qops; |
1711 | q->gfp_flags = GFP_DMA32; |
1712 | q->mem_ops = &vb2_dma_sg_memops; |
1713 | q->buf_struct_size = sizeof(struct saa7134_buf); |
1714 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
1715 | q->lock = &dev->lock; |
1716 | q->dev = &dev->pci->dev; |
1717 | ret = vb2_queue_init(q); |
1718 | if (ret) |
1719 | return ret; |
1720 | saa7134_pgtable_alloc(pci: dev->pci, pt: &dev->video_q.pt); |
1721 | |
1722 | q = &dev->vbi_vbq; |
1723 | q->type = V4L2_BUF_TYPE_VBI_CAPTURE; |
1724 | /* Don't add VB2_USERPTR, see comment above */ |
1725 | q->io_modes = VB2_MMAP | VB2_READ; |
1726 | if (saa7134_userptr) |
1727 | q->io_modes |= VB2_USERPTR; |
1728 | q->drv_priv = &dev->vbi_q; |
1729 | q->ops = &saa7134_vbi_qops; |
1730 | q->gfp_flags = GFP_DMA32; |
1731 | q->mem_ops = &vb2_dma_sg_memops; |
1732 | q->buf_struct_size = sizeof(struct saa7134_buf); |
1733 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
1734 | q->lock = &dev->lock; |
1735 | q->dev = &dev->pci->dev; |
1736 | ret = vb2_queue_init(q); |
1737 | if (ret) |
1738 | return ret; |
1739 | saa7134_pgtable_alloc(pci: dev->pci, pt: &dev->vbi_q.pt); |
1740 | |
1741 | return 0; |
1742 | } |
1743 | |
1744 | void saa7134_video_fini(struct saa7134_dev *dev) |
1745 | { |
1746 | del_timer_sync(timer: &dev->video_q.timeout); |
1747 | /* free stuff */ |
1748 | saa7134_pgtable_free(pci: dev->pci, pt: &dev->video_q.pt); |
1749 | saa7134_pgtable_free(pci: dev->pci, pt: &dev->vbi_q.pt); |
1750 | v4l2_ctrl_handler_free(hdl: &dev->ctrl_handler); |
1751 | if (card_has_radio(dev)) |
1752 | v4l2_ctrl_handler_free(hdl: &dev->radio_ctrl_handler); |
1753 | } |
1754 | |
1755 | int saa7134_videoport_init(struct saa7134_dev *dev) |
1756 | { |
1757 | /* enable video output */ |
1758 | int vo = saa7134_boards[dev->board].video_out; |
1759 | int video_reg; |
1760 | unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts; |
1761 | |
1762 | /* Configure videoport */ |
1763 | saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]); |
1764 | video_reg = video_out[vo][1]; |
1765 | if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED) |
1766 | video_reg &= ~VP_T_CODE_P_INVERTED; |
1767 | saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg); |
1768 | saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]); |
1769 | saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]); |
1770 | video_reg = video_out[vo][5]; |
1771 | if (vid_port_opts & SET_CLOCK_NOT_DELAYED) |
1772 | video_reg &= ~VP_CLK_CTRL2_DELAYED; |
1773 | if (vid_port_opts & SET_CLOCK_INVERTED) |
1774 | video_reg |= VP_CLK_CTRL1_INVERTED; |
1775 | saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_reg); |
1776 | video_reg = video_out[vo][6]; |
1777 | if (vid_port_opts & SET_VSYNC_OFF) { |
1778 | video_reg &= ~VP_VS_TYPE_MASK; |
1779 | video_reg |= VP_VS_TYPE_OFF; |
1780 | } |
1781 | saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_reg); |
1782 | saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]); |
1783 | saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]); |
1784 | |
1785 | /* Start videoport */ |
1786 | saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]); |
1787 | |
1788 | return 0; |
1789 | } |
1790 | |
1791 | int saa7134_video_init2(struct saa7134_dev *dev) |
1792 | { |
1793 | /* init video hw */ |
1794 | set_tvnorm(dev,norm: &tvnorms[0]); |
1795 | video_mux(dev,input: 0); |
1796 | v4l2_ctrl_handler_setup(hdl: &dev->ctrl_handler); |
1797 | saa7134_tvaudio_setmute(dev); |
1798 | saa7134_tvaudio_setvolume(dev,level: dev->ctl_volume); |
1799 | return 0; |
1800 | } |
1801 | |
1802 | void saa7134_irq_video_signalchange(struct saa7134_dev *dev) |
1803 | { |
1804 | static const char *st[] = { |
1805 | "(no signal)" , "NTSC" , "PAL" , "SECAM" }; |
1806 | u32 st1,st2; |
1807 | |
1808 | st1 = saa_readb(SAA7134_STATUS_VIDEO1); |
1809 | st2 = saa_readb(SAA7134_STATUS_VIDEO2); |
1810 | video_dbg("DCSDT: pll: %s, sync: %s, norm: %s\n" , |
1811 | (st1 & 0x40) ? "not locked" : "locked" , |
1812 | (st2 & 0x40) ? "no" : "yes" , |
1813 | st[st1 & 0x03]); |
1814 | dev->nosignal = (st1 & 0x40) || (st2 & 0x40) || !(st2 & 0x1); |
1815 | |
1816 | if (dev->nosignal) { |
1817 | /* no video signal -> mute audio */ |
1818 | if (dev->ctl_automute) |
1819 | dev->automute = 1; |
1820 | saa7134_tvaudio_setmute(dev); |
1821 | } else { |
1822 | /* wake up tvaudio audio carrier scan thread */ |
1823 | saa7134_tvaudio_do_scan(dev); |
1824 | } |
1825 | |
1826 | if ((st2 & 0x80) && !noninterlaced && !dev->nosignal) |
1827 | saa_clearb(SAA7134_SYNC_CTRL, 0x20); |
1828 | else |
1829 | saa_setb(SAA7134_SYNC_CTRL, 0x20); |
1830 | |
1831 | if (dev->mops && dev->mops->signal_change) |
1832 | dev->mops->signal_change(dev); |
1833 | } |
1834 | |
1835 | |
1836 | void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status) |
1837 | { |
1838 | enum v4l2_field field; |
1839 | |
1840 | spin_lock(lock: &dev->slock); |
1841 | if (dev->video_q.curr) { |
1842 | field = dev->field; |
1843 | if (V4L2_FIELD_HAS_BOTH(field)) { |
1844 | /* make sure we have seen both fields */ |
1845 | if ((status & 0x10) == 0x00) { |
1846 | dev->video_q.curr->top_seen = 1; |
1847 | goto done; |
1848 | } |
1849 | if (!dev->video_q.curr->top_seen) |
1850 | goto done; |
1851 | } else if (field == V4L2_FIELD_TOP) { |
1852 | if ((status & 0x10) != 0x10) |
1853 | goto done; |
1854 | } else if (field == V4L2_FIELD_BOTTOM) { |
1855 | if ((status & 0x10) != 0x00) |
1856 | goto done; |
1857 | } |
1858 | saa7134_buffer_finish(dev, q: &dev->video_q, state: VB2_BUF_STATE_DONE); |
1859 | } |
1860 | saa7134_buffer_next(dev, q: &dev->video_q); |
1861 | |
1862 | done: |
1863 | spin_unlock(lock: &dev->slock); |
1864 | } |
1865 | |