1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Zoran zr36057/zr36067 PCI controller driver, for the |
4 | * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux |
5 | * Media Labs LML33/LML33R10. |
6 | * |
7 | * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx> |
8 | * |
9 | * Changes for BUZ by Wolfgang Scherr <scherr@net4you.net> |
10 | * |
11 | * Changes for DC10/DC30 by Laurent Pinchart <laurent.pinchart@skynet.be> |
12 | * |
13 | * Changes for LML33R10 by Maxim Yevtyushkin <max@linuxmedialabs.com> |
14 | * |
15 | * Changes for videodev2/v4l2 by Ronald Bultje <rbultje@ronald.bitfreak.net> |
16 | * |
17 | * Based on |
18 | * |
19 | * Miro DC10 driver |
20 | * Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net> |
21 | * |
22 | * Iomega Buz driver version 1.0 |
23 | * Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de> |
24 | * |
25 | * buz.0.0.3 |
26 | * Copyright (C) 1998 Dave Perks <dperks@ibm.net> |
27 | * |
28 | * bttv - Bt848 frame grabber driver |
29 | * Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) |
30 | * & Marcus Metzler (mocm@thp.uni-koeln.de) |
31 | */ |
32 | |
33 | #include <linux/init.h> |
34 | #include <linux/module.h> |
35 | #include <linux/delay.h> |
36 | #include <linux/slab.h> |
37 | #include <linux/pci.h> |
38 | #include <linux/wait.h> |
39 | |
40 | #include <linux/interrupt.h> |
41 | #include <linux/i2c.h> |
42 | #include <linux/i2c-algo-bit.h> |
43 | |
44 | #include <linux/spinlock.h> |
45 | |
46 | #include <linux/videodev2.h> |
47 | #include <media/v4l2-common.h> |
48 | #include <media/v4l2-ioctl.h> |
49 | #include <media/v4l2-event.h> |
50 | #include "videocodec.h" |
51 | |
52 | #include <linux/io.h> |
53 | #include <linux/uaccess.h> |
54 | |
55 | #include <linux/mutex.h> |
56 | #include "zoran.h" |
57 | #include "zoran_device.h" |
58 | #include "zoran_card.h" |
59 | |
60 | const struct zoran_format zoran_formats[] = { |
61 | { |
62 | .name = "15-bit RGB LE" , |
63 | .fourcc = V4L2_PIX_FMT_RGB555, |
64 | .colorspace = V4L2_COLORSPACE_SRGB, |
65 | .depth = 15, |
66 | .flags = ZORAN_FORMAT_CAPTURE, |
67 | .vfespfr = ZR36057_VFESPFR_RGB555 | ZR36057_VFESPFR_ERR_DIF | |
68 | ZR36057_VFESPFR_LITTLE_ENDIAN, |
69 | }, { |
70 | .name = "15-bit RGB BE" , |
71 | .fourcc = V4L2_PIX_FMT_RGB555X, |
72 | .colorspace = V4L2_COLORSPACE_SRGB, |
73 | .depth = 15, |
74 | .flags = ZORAN_FORMAT_CAPTURE, |
75 | .vfespfr = ZR36057_VFESPFR_RGB555 | ZR36057_VFESPFR_ERR_DIF, |
76 | }, { |
77 | .name = "16-bit RGB LE" , |
78 | .fourcc = V4L2_PIX_FMT_RGB565, |
79 | .colorspace = V4L2_COLORSPACE_SRGB, |
80 | .depth = 16, |
81 | .flags = ZORAN_FORMAT_CAPTURE, |
82 | .vfespfr = ZR36057_VFESPFR_RGB565 | ZR36057_VFESPFR_ERR_DIF | |
83 | ZR36057_VFESPFR_LITTLE_ENDIAN, |
84 | }, { |
85 | .name = "16-bit RGB BE" , |
86 | .fourcc = V4L2_PIX_FMT_RGB565X, |
87 | .colorspace = V4L2_COLORSPACE_SRGB, |
88 | .depth = 16, |
89 | .flags = ZORAN_FORMAT_CAPTURE, |
90 | .vfespfr = ZR36057_VFESPFR_RGB565 | ZR36057_VFESPFR_ERR_DIF, |
91 | }, { |
92 | .name = "24-bit RGB" , |
93 | .fourcc = V4L2_PIX_FMT_BGR24, |
94 | .colorspace = V4L2_COLORSPACE_SRGB, |
95 | .depth = 24, |
96 | .flags = ZORAN_FORMAT_CAPTURE, |
97 | .vfespfr = ZR36057_VFESPFR_RGB888 | ZR36057_VFESPFR_PACK24, |
98 | }, { |
99 | .name = "32-bit RGB LE" , |
100 | .fourcc = V4L2_PIX_FMT_BGR32, |
101 | .colorspace = V4L2_COLORSPACE_SRGB, |
102 | .depth = 32, |
103 | .flags = ZORAN_FORMAT_CAPTURE, |
104 | .vfespfr = ZR36057_VFESPFR_RGB888 | ZR36057_VFESPFR_LITTLE_ENDIAN, |
105 | }, { |
106 | .name = "32-bit RGB BE" , |
107 | .fourcc = V4L2_PIX_FMT_RGB32, |
108 | .colorspace = V4L2_COLORSPACE_SRGB, |
109 | .depth = 32, |
110 | .flags = ZORAN_FORMAT_CAPTURE, |
111 | .vfespfr = ZR36057_VFESPFR_RGB888, |
112 | }, { |
113 | .name = "4:2:2, packed, YUYV" , |
114 | .fourcc = V4L2_PIX_FMT_YUYV, |
115 | .colorspace = V4L2_COLORSPACE_SMPTE170M, |
116 | .depth = 16, |
117 | .flags = ZORAN_FORMAT_CAPTURE, |
118 | .vfespfr = ZR36057_VFESPFR_YUV422, |
119 | }, { |
120 | .name = "4:2:2, packed, UYVY" , |
121 | .fourcc = V4L2_PIX_FMT_UYVY, |
122 | .colorspace = V4L2_COLORSPACE_SMPTE170M, |
123 | .depth = 16, |
124 | .flags = ZORAN_FORMAT_CAPTURE, |
125 | .vfespfr = ZR36057_VFESPFR_YUV422 | ZR36057_VFESPFR_LITTLE_ENDIAN, |
126 | }, { |
127 | .name = "Hardware-encoded Motion-JPEG" , |
128 | .fourcc = V4L2_PIX_FMT_MJPEG, |
129 | .colorspace = V4L2_COLORSPACE_SMPTE170M, |
130 | .depth = 0, |
131 | .flags = ZORAN_FORMAT_CAPTURE | |
132 | ZORAN_FORMAT_PLAYBACK | |
133 | ZORAN_FORMAT_COMPRESSED, |
134 | } |
135 | }; |
136 | |
137 | #define NUM_FORMATS ARRAY_SIZE(zoran_formats) |
138 | |
139 | /* |
140 | * small helper function for calculating buffersizes for v4l2 |
141 | * we calculate the nearest higher power-of-two, which |
142 | * will be the recommended buffersize |
143 | */ |
144 | static __u32 zoran_v4l2_calc_bufsize(struct zoran_jpg_settings *settings) |
145 | { |
146 | __u8 div = settings->ver_dcm * settings->hor_dcm * settings->tmp_dcm; |
147 | __u32 num = (1024 * 512) / (div); |
148 | __u32 result = 2; |
149 | |
150 | num--; |
151 | while (num) { |
152 | num >>= 1; |
153 | result <<= 1; |
154 | } |
155 | |
156 | if (result < 8192) |
157 | return 8192; |
158 | |
159 | return result; |
160 | } |
161 | |
162 | /* |
163 | * V4L Buffer grabbing |
164 | */ |
165 | static int zoran_v4l_set_format(struct zoran *zr, int width, int height, |
166 | const struct zoran_format *format) |
167 | { |
168 | int bpp; |
169 | |
170 | /* Check size and format of the grab wanted */ |
171 | |
172 | if (height < BUZ_MIN_HEIGHT || width < BUZ_MIN_WIDTH || |
173 | height > BUZ_MAX_HEIGHT || width > BUZ_MAX_WIDTH) { |
174 | pci_dbg(zr->pci_dev, "%s - wrong frame size (%dx%d)\n" , __func__, width, height); |
175 | return -EINVAL; |
176 | } |
177 | |
178 | bpp = (format->depth + 7) / 8; |
179 | |
180 | zr->buffer_size = height * width * bpp; |
181 | |
182 | /* Check against available buffer size */ |
183 | if (height * width * bpp > zr->buffer_size) { |
184 | pci_dbg(zr->pci_dev, "%s - video buffer size (%d kB) is too small\n" , |
185 | __func__, zr->buffer_size >> 10); |
186 | return -EINVAL; |
187 | } |
188 | |
189 | /* The video front end needs 4-byte alinged line sizes */ |
190 | |
191 | if ((bpp == 2 && (width & 1)) || (bpp == 3 && (width & 3))) { |
192 | pci_dbg(zr->pci_dev, "%s - wrong frame alignment\n" , __func__); |
193 | return -EINVAL; |
194 | } |
195 | |
196 | zr->v4l_settings.width = width; |
197 | zr->v4l_settings.height = height; |
198 | zr->v4l_settings.format = format; |
199 | zr->v4l_settings.bytesperline = bpp * zr->v4l_settings.width; |
200 | |
201 | return 0; |
202 | } |
203 | |
204 | static int zoran_set_norm(struct zoran *zr, v4l2_std_id norm) |
205 | { |
206 | if (!(norm & zr->card.norms)) { |
207 | pci_dbg(zr->pci_dev, "%s - unsupported norm %llx\n" , __func__, norm); |
208 | return -EINVAL; |
209 | } |
210 | |
211 | if (norm & V4L2_STD_SECAM) |
212 | zr->timing = zr->card.tvn[ZR_NORM_SECAM]; |
213 | else if (norm & V4L2_STD_NTSC) |
214 | zr->timing = zr->card.tvn[ZR_NORM_NTSC]; |
215 | else |
216 | zr->timing = zr->card.tvn[ZR_NORM_PAL]; |
217 | |
218 | decoder_call(zr, video, s_std, norm); |
219 | encoder_call(zr, video, s_std_output, norm); |
220 | |
221 | /* Make sure the changes come into effect */ |
222 | zr->norm = norm; |
223 | |
224 | return 0; |
225 | } |
226 | |
227 | static int zoran_set_input(struct zoran *zr, int input) |
228 | { |
229 | if (input == zr->input) |
230 | return 0; |
231 | |
232 | if (input < 0 || input >= zr->card.inputs) { |
233 | pci_dbg(zr->pci_dev, "%s - unsupported input %d\n" , __func__, input); |
234 | return -EINVAL; |
235 | } |
236 | |
237 | zr->input = input; |
238 | |
239 | decoder_call(zr, video, s_routing, zr->card.input[input].muxsel, 0, 0); |
240 | |
241 | return 0; |
242 | } |
243 | |
244 | /* |
245 | * ioctl routine |
246 | */ |
247 | |
248 | static int zoran_querycap(struct file *file, void *__fh, struct v4l2_capability *cap) |
249 | { |
250 | struct zoran *zr = video_drvdata(file); |
251 | |
252 | strscpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card)); |
253 | strscpy(cap->driver, "zoran" , sizeof(cap->driver)); |
254 | snprintf(buf: cap->bus_info, size: sizeof(cap->bus_info), fmt: "PCI:%s" , pci_name(pdev: zr->pci_dev)); |
255 | return 0; |
256 | } |
257 | |
258 | static int zoran_enum_fmt(struct zoran *zr, struct v4l2_fmtdesc *fmt, int flag) |
259 | { |
260 | unsigned int num, i; |
261 | |
262 | if (fmt->index >= ARRAY_SIZE(zoran_formats)) |
263 | return -EINVAL; |
264 | if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
265 | return -EINVAL; |
266 | |
267 | for (num = i = 0; i < NUM_FORMATS; i++) { |
268 | if (zoran_formats[i].flags & flag && num++ == fmt->index) { |
269 | strscpy(fmt->description, zoran_formats[i].name, |
270 | sizeof(fmt->description)); |
271 | /* fmt struct pre-zeroed, so adding '\0' not needed */ |
272 | fmt->pixelformat = zoran_formats[i].fourcc; |
273 | if (zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED) |
274 | fmt->flags |= V4L2_FMT_FLAG_COMPRESSED; |
275 | return 0; |
276 | } |
277 | } |
278 | return -EINVAL; |
279 | } |
280 | |
281 | static int zoran_enum_fmt_vid_cap(struct file *file, void *__fh, |
282 | struct v4l2_fmtdesc *f) |
283 | { |
284 | struct zoran *zr = video_drvdata(file); |
285 | |
286 | return zoran_enum_fmt(zr, fmt: f, ZORAN_FORMAT_CAPTURE); |
287 | } |
288 | |
289 | static int zoran_g_fmt_vid_out(struct file *file, void *__fh, |
290 | struct v4l2_format *fmt) |
291 | { |
292 | struct zoran *zr = video_drvdata(file); |
293 | |
294 | fmt->fmt.pix.width = zr->jpg_settings.img_width / zr->jpg_settings.hor_dcm; |
295 | fmt->fmt.pix.height = zr->jpg_settings.img_height * 2 / |
296 | (zr->jpg_settings.ver_dcm * zr->jpg_settings.tmp_dcm); |
297 | fmt->fmt.pix.sizeimage = zr->buffer_size; |
298 | fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; |
299 | if (zr->jpg_settings.tmp_dcm == 1) |
300 | fmt->fmt.pix.field = (zr->jpg_settings.odd_even ? |
301 | V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT); |
302 | else |
303 | fmt->fmt.pix.field = (zr->jpg_settings.odd_even ? |
304 | V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); |
305 | fmt->fmt.pix.bytesperline = 0; |
306 | fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; |
307 | |
308 | return 0; |
309 | } |
310 | |
311 | static int zoran_g_fmt_vid_cap(struct file *file, void *__fh, |
312 | struct v4l2_format *fmt) |
313 | { |
314 | struct zoran *zr = video_drvdata(file); |
315 | |
316 | if (zr->map_mode != ZORAN_MAP_MODE_RAW) |
317 | return zoran_g_fmt_vid_out(file, __fh, fmt); |
318 | fmt->fmt.pix.width = zr->v4l_settings.width; |
319 | fmt->fmt.pix.height = zr->v4l_settings.height; |
320 | fmt->fmt.pix.sizeimage = zr->buffer_size; |
321 | fmt->fmt.pix.pixelformat = zr->v4l_settings.format->fourcc; |
322 | fmt->fmt.pix.colorspace = zr->v4l_settings.format->colorspace; |
323 | fmt->fmt.pix.bytesperline = zr->v4l_settings.bytesperline; |
324 | if (BUZ_MAX_HEIGHT < (zr->v4l_settings.height * 2)) |
325 | fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; |
326 | else |
327 | fmt->fmt.pix.field = V4L2_FIELD_TOP; |
328 | return 0; |
329 | } |
330 | |
331 | static int zoran_try_fmt_vid_out(struct file *file, void *__fh, |
332 | struct v4l2_format *fmt) |
333 | { |
334 | struct zoran *zr = video_drvdata(file); |
335 | struct zoran_jpg_settings settings; |
336 | int res = 0; |
337 | |
338 | if (fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG) |
339 | return -EINVAL; |
340 | |
341 | settings = zr->jpg_settings; |
342 | |
343 | /* we actually need to set 'real' parameters now */ |
344 | if ((fmt->fmt.pix.height * 2) > BUZ_MAX_HEIGHT) |
345 | settings.tmp_dcm = 1; |
346 | else |
347 | settings.tmp_dcm = 2; |
348 | settings.decimation = 0; |
349 | if (fmt->fmt.pix.height <= zr->jpg_settings.img_height / 2) |
350 | settings.ver_dcm = 2; |
351 | else |
352 | settings.ver_dcm = 1; |
353 | if (fmt->fmt.pix.width <= zr->jpg_settings.img_width / 4) |
354 | settings.hor_dcm = 4; |
355 | else if (fmt->fmt.pix.width <= zr->jpg_settings.img_width / 2) |
356 | settings.hor_dcm = 2; |
357 | else |
358 | settings.hor_dcm = 1; |
359 | if (settings.tmp_dcm == 1) |
360 | settings.field_per_buff = 2; |
361 | else |
362 | settings.field_per_buff = 1; |
363 | |
364 | if (settings.hor_dcm > 1) { |
365 | settings.img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0; |
366 | settings.img_width = (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH; |
367 | } else { |
368 | settings.img_x = 0; |
369 | settings.img_width = BUZ_MAX_WIDTH; |
370 | } |
371 | |
372 | /* check */ |
373 | res = zoran_check_jpg_settings(zr, settings: &settings, try: 1); |
374 | if (res) |
375 | return res; |
376 | |
377 | /* tell the user what we actually did */ |
378 | fmt->fmt.pix.width = settings.img_width / settings.hor_dcm; |
379 | fmt->fmt.pix.height = settings.img_height * 2 / |
380 | (settings.tmp_dcm * settings.ver_dcm); |
381 | if (settings.tmp_dcm == 1) |
382 | fmt->fmt.pix.field = (zr->jpg_settings.odd_even ? |
383 | V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT); |
384 | else |
385 | fmt->fmt.pix.field = (zr->jpg_settings.odd_even ? |
386 | V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); |
387 | |
388 | fmt->fmt.pix.sizeimage = zoran_v4l2_calc_bufsize(settings: &settings); |
389 | fmt->fmt.pix.bytesperline = 0; |
390 | fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; |
391 | return res; |
392 | } |
393 | |
394 | static int zoran_try_fmt_vid_cap(struct file *file, void *__fh, |
395 | struct v4l2_format *fmt) |
396 | { |
397 | struct zoran *zr = video_drvdata(file); |
398 | int bpp; |
399 | int i; |
400 | |
401 | if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) |
402 | return zoran_try_fmt_vid_out(file, __fh, fmt); |
403 | |
404 | for (i = 0; i < NUM_FORMATS; i++) |
405 | if (zoran_formats[i].fourcc == fmt->fmt.pix.pixelformat) |
406 | break; |
407 | |
408 | if (i == NUM_FORMATS) { |
409 | /* TODO do not return here to fix the TRY_FMT cannot handle an invalid pixelformat*/ |
410 | return -EINVAL; |
411 | } |
412 | |
413 | fmt->fmt.pix.pixelformat = zoran_formats[i].fourcc; |
414 | fmt->fmt.pix.colorspace = zoran_formats[i].colorspace; |
415 | if (BUZ_MAX_HEIGHT < (fmt->fmt.pix.height * 2)) |
416 | fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; |
417 | else |
418 | fmt->fmt.pix.field = V4L2_FIELD_TOP; |
419 | |
420 | bpp = DIV_ROUND_UP(zoran_formats[i].depth, 8); |
421 | v4l_bound_align_image(width: &fmt->fmt.pix.width, BUZ_MIN_WIDTH, BUZ_MAX_WIDTH, |
422 | walign: bpp == 2 ? 1 : 2, |
423 | height: &fmt->fmt.pix.height, BUZ_MIN_HEIGHT, BUZ_MAX_HEIGHT, |
424 | halign: 0, salign: 0); |
425 | fmt->fmt.pix.bytesperline = fmt->fmt.pix.width * bpp; |
426 | fmt->fmt.pix.sizeimage = fmt->fmt.pix.bytesperline * fmt->fmt.pix.height; |
427 | return 0; |
428 | } |
429 | |
430 | static int zoran_s_fmt_vid_out(struct file *file, void *__fh, |
431 | struct v4l2_format *fmt) |
432 | { |
433 | struct zoran *zr = video_drvdata(file); |
434 | __le32 printformat = __cpu_to_le32(fmt->fmt.pix.pixelformat); |
435 | struct zoran_jpg_settings settings; |
436 | int res = 0; |
437 | |
438 | pci_dbg(zr->pci_dev, "size=%dx%d, fmt=0x%x (%4.4s)\n" , |
439 | fmt->fmt.pix.width, fmt->fmt.pix.height, |
440 | fmt->fmt.pix.pixelformat, |
441 | (char *)&printformat); |
442 | if (fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG) |
443 | return -EINVAL; |
444 | |
445 | if (!fmt->fmt.pix.height || !fmt->fmt.pix.width) |
446 | return -EINVAL; |
447 | |
448 | settings = zr->jpg_settings; |
449 | |
450 | /* we actually need to set 'real' parameters now */ |
451 | if (fmt->fmt.pix.height * 2 > BUZ_MAX_HEIGHT) |
452 | settings.tmp_dcm = 1; |
453 | else |
454 | settings.tmp_dcm = 2; |
455 | settings.decimation = 0; |
456 | if (fmt->fmt.pix.height <= zr->jpg_settings.img_height / 2) |
457 | settings.ver_dcm = 2; |
458 | else |
459 | settings.ver_dcm = 1; |
460 | if (fmt->fmt.pix.width <= zr->jpg_settings.img_width / 4) |
461 | settings.hor_dcm = 4; |
462 | else if (fmt->fmt.pix.width <= zr->jpg_settings.img_width / 2) |
463 | settings.hor_dcm = 2; |
464 | else |
465 | settings.hor_dcm = 1; |
466 | if (settings.tmp_dcm == 1) |
467 | settings.field_per_buff = 2; |
468 | else |
469 | settings.field_per_buff = 1; |
470 | |
471 | if (settings.hor_dcm > 1) { |
472 | settings.img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0; |
473 | settings.img_width = (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH; |
474 | } else { |
475 | settings.img_x = 0; |
476 | settings.img_width = BUZ_MAX_WIDTH; |
477 | } |
478 | |
479 | /* check */ |
480 | res = zoran_check_jpg_settings(zr, settings: &settings, try: 0); |
481 | if (res) |
482 | return res; |
483 | |
484 | /* it's ok, so set them */ |
485 | zr->jpg_settings = settings; |
486 | |
487 | if (fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) |
488 | zr->map_mode = ZORAN_MAP_MODE_JPG_REC; |
489 | else |
490 | zr->map_mode = ZORAN_MAP_MODE_JPG_PLAY; |
491 | |
492 | zr->buffer_size = zoran_v4l2_calc_bufsize(settings: &zr->jpg_settings); |
493 | |
494 | /* tell the user what we actually did */ |
495 | fmt->fmt.pix.width = settings.img_width / settings.hor_dcm; |
496 | fmt->fmt.pix.height = settings.img_height * 2 / |
497 | (settings.tmp_dcm * settings.ver_dcm); |
498 | if (settings.tmp_dcm == 1) |
499 | fmt->fmt.pix.field = (zr->jpg_settings.odd_even ? |
500 | V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT); |
501 | else |
502 | fmt->fmt.pix.field = (zr->jpg_settings.odd_even ? |
503 | V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); |
504 | fmt->fmt.pix.bytesperline = 0; |
505 | fmt->fmt.pix.sizeimage = zr->buffer_size; |
506 | fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; |
507 | return res; |
508 | } |
509 | |
510 | static int zoran_s_fmt_vid_cap(struct file *file, void *__fh, |
511 | struct v4l2_format *fmt) |
512 | { |
513 | struct zoran *zr = video_drvdata(file); |
514 | struct zoran_fh *fh = __fh; |
515 | int i; |
516 | int res = 0; |
517 | |
518 | if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) |
519 | return zoran_s_fmt_vid_out(file, fh: fh, fmt); |
520 | |
521 | for (i = 0; i < NUM_FORMATS; i++) |
522 | if (fmt->fmt.pix.pixelformat == zoran_formats[i].fourcc) |
523 | break; |
524 | if (i == NUM_FORMATS) { |
525 | pci_dbg(zr->pci_dev, "VIDIOC_S_FMT - unknown/unsupported format 0x%x\n" , |
526 | fmt->fmt.pix.pixelformat); |
527 | /* TODO do not return here to fix the TRY_FMT cannot handle an invalid pixelformat*/ |
528 | return -EINVAL; |
529 | } |
530 | |
531 | fmt->fmt.pix.pixelformat = zoran_formats[i].fourcc; |
532 | if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT) |
533 | fmt->fmt.pix.height = BUZ_MAX_HEIGHT; |
534 | if (fmt->fmt.pix.width > BUZ_MAX_WIDTH) |
535 | fmt->fmt.pix.width = BUZ_MAX_WIDTH; |
536 | if (fmt->fmt.pix.height < BUZ_MIN_HEIGHT) |
537 | fmt->fmt.pix.height = BUZ_MIN_HEIGHT; |
538 | if (fmt->fmt.pix.width < BUZ_MIN_WIDTH) |
539 | fmt->fmt.pix.width = BUZ_MIN_WIDTH; |
540 | |
541 | zr->map_mode = ZORAN_MAP_MODE_RAW; |
542 | |
543 | res = zoran_v4l_set_format(zr, width: fmt->fmt.pix.width, height: fmt->fmt.pix.height, |
544 | format: &zoran_formats[i]); |
545 | if (res) |
546 | return res; |
547 | |
548 | /* tell the user the results/missing stuff */ |
549 | fmt->fmt.pix.bytesperline = zr->v4l_settings.bytesperline; |
550 | fmt->fmt.pix.sizeimage = zr->buffer_size; |
551 | fmt->fmt.pix.colorspace = zr->v4l_settings.format->colorspace; |
552 | if (BUZ_MAX_HEIGHT < (zr->v4l_settings.height * 2)) |
553 | fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; |
554 | else |
555 | fmt->fmt.pix.field = V4L2_FIELD_TOP; |
556 | return res; |
557 | } |
558 | |
559 | static int zoran_g_std(struct file *file, void *__fh, v4l2_std_id *std) |
560 | { |
561 | struct zoran *zr = video_drvdata(file); |
562 | |
563 | *std = zr->norm; |
564 | return 0; |
565 | } |
566 | |
567 | static int zoran_s_std(struct file *file, void *__fh, v4l2_std_id std) |
568 | { |
569 | struct zoran *zr = video_drvdata(file); |
570 | int res = 0; |
571 | |
572 | if (zr->norm == std) |
573 | return 0; |
574 | |
575 | if (zr->running != ZORAN_MAP_MODE_NONE) |
576 | return -EBUSY; |
577 | |
578 | res = zoran_set_norm(zr, norm: std); |
579 | return res; |
580 | } |
581 | |
582 | static int zoran_enum_input(struct file *file, void *__fh, |
583 | struct v4l2_input *inp) |
584 | { |
585 | struct zoran *zr = video_drvdata(file); |
586 | |
587 | if (inp->index >= zr->card.inputs) |
588 | return -EINVAL; |
589 | |
590 | strscpy(inp->name, zr->card.input[inp->index].name, sizeof(inp->name)); |
591 | inp->type = V4L2_INPUT_TYPE_CAMERA; |
592 | inp->std = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM; |
593 | |
594 | /* Get status of video decoder */ |
595 | decoder_call(zr, video, g_input_status, &inp->status); |
596 | return 0; |
597 | } |
598 | |
599 | static int zoran_g_input(struct file *file, void *__fh, unsigned int *input) |
600 | { |
601 | struct zoran *zr = video_drvdata(file); |
602 | |
603 | *input = zr->input; |
604 | |
605 | return 0; |
606 | } |
607 | |
608 | static int zoran_s_input(struct file *file, void *__fh, unsigned int input) |
609 | { |
610 | struct zoran *zr = video_drvdata(file); |
611 | int res; |
612 | |
613 | if (zr->running != ZORAN_MAP_MODE_NONE) |
614 | return -EBUSY; |
615 | |
616 | res = zoran_set_input(zr, input); |
617 | return res; |
618 | } |
619 | |
620 | /* cropping (sub-frame capture) */ |
621 | static int zoran_g_selection(struct file *file, void *__fh, struct v4l2_selection *sel) |
622 | { |
623 | struct zoran *zr = video_drvdata(file); |
624 | |
625 | if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && |
626 | sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { |
627 | pci_dbg(zr->pci_dev, "%s invalid selection type combination\n" , __func__); |
628 | return -EINVAL; |
629 | } |
630 | |
631 | switch (sel->target) { |
632 | case V4L2_SEL_TGT_CROP: |
633 | sel->r.top = zr->jpg_settings.img_y; |
634 | sel->r.left = zr->jpg_settings.img_x; |
635 | sel->r.width = zr->jpg_settings.img_width; |
636 | sel->r.height = zr->jpg_settings.img_height; |
637 | break; |
638 | case V4L2_SEL_TGT_CROP_DEFAULT: |
639 | sel->r.top = 0; |
640 | sel->r.left = 0; |
641 | sel->r.width = BUZ_MIN_WIDTH; |
642 | sel->r.height = BUZ_MIN_HEIGHT; |
643 | break; |
644 | case V4L2_SEL_TGT_CROP_BOUNDS: |
645 | sel->r.top = 0; |
646 | sel->r.left = 0; |
647 | sel->r.width = BUZ_MAX_WIDTH; |
648 | sel->r.height = BUZ_MAX_HEIGHT; |
649 | break; |
650 | default: |
651 | return -EINVAL; |
652 | } |
653 | return 0; |
654 | } |
655 | |
656 | static int zoran_s_selection(struct file *file, void *__fh, struct v4l2_selection *sel) |
657 | { |
658 | struct zoran *zr = video_drvdata(file); |
659 | struct zoran_jpg_settings settings; |
660 | int res; |
661 | |
662 | if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && |
663 | sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
664 | return -EINVAL; |
665 | |
666 | if (!sel->r.width || !sel->r.height) |
667 | return -EINVAL; |
668 | |
669 | if (sel->target != V4L2_SEL_TGT_CROP) |
670 | return -EINVAL; |
671 | |
672 | if (zr->map_mode == ZORAN_MAP_MODE_RAW) { |
673 | pci_dbg(zr->pci_dev, "VIDIOC_S_SELECTION - subcapture only supported for compressed capture\n" ); |
674 | return -EINVAL; |
675 | } |
676 | |
677 | settings = zr->jpg_settings; |
678 | |
679 | /* move into a form that we understand */ |
680 | settings.img_x = sel->r.left; |
681 | settings.img_y = sel->r.top; |
682 | settings.img_width = sel->r.width; |
683 | settings.img_height = sel->r.height; |
684 | |
685 | /* check validity */ |
686 | res = zoran_check_jpg_settings(zr, settings: &settings, try: 0); |
687 | if (res) |
688 | return res; |
689 | |
690 | /* accept */ |
691 | zr->jpg_settings = settings; |
692 | return res; |
693 | } |
694 | |
695 | /* |
696 | * Output is disabled temporarily |
697 | * Zoran is picky about jpeg data it accepts. At least it seems to unsupport COM and APPn. |
698 | * So until a way to filter data will be done, disable output. |
699 | */ |
700 | static const struct v4l2_ioctl_ops zoran_ioctl_ops = { |
701 | .vidioc_querycap = zoran_querycap, |
702 | .vidioc_s_selection = zoran_s_selection, |
703 | .vidioc_g_selection = zoran_g_selection, |
704 | .vidioc_enum_input = zoran_enum_input, |
705 | .vidioc_g_input = zoran_g_input, |
706 | .vidioc_s_input = zoran_s_input, |
707 | .vidioc_g_std = zoran_g_std, |
708 | .vidioc_s_std = zoran_s_std, |
709 | .vidioc_create_bufs = vb2_ioctl_create_bufs, |
710 | .vidioc_reqbufs = vb2_ioctl_reqbufs, |
711 | .vidioc_querybuf = vb2_ioctl_querybuf, |
712 | .vidioc_qbuf = vb2_ioctl_qbuf, |
713 | .vidioc_dqbuf = vb2_ioctl_dqbuf, |
714 | .vidioc_expbuf = vb2_ioctl_expbuf, |
715 | .vidioc_streamon = vb2_ioctl_streamon, |
716 | .vidioc_streamoff = vb2_ioctl_streamoff, |
717 | .vidioc_enum_fmt_vid_cap = zoran_enum_fmt_vid_cap, |
718 | .vidioc_g_fmt_vid_cap = zoran_g_fmt_vid_cap, |
719 | .vidioc_s_fmt_vid_cap = zoran_s_fmt_vid_cap, |
720 | .vidioc_try_fmt_vid_cap = zoran_try_fmt_vid_cap, |
721 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, |
722 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, |
723 | }; |
724 | |
725 | static const struct v4l2_file_operations zoran_fops = { |
726 | .owner = THIS_MODULE, |
727 | .unlocked_ioctl = video_ioctl2, |
728 | .open = v4l2_fh_open, |
729 | .release = vb2_fop_release, |
730 | .mmap = vb2_fop_mmap, |
731 | .poll = vb2_fop_poll, |
732 | }; |
733 | |
734 | const struct video_device zoran_template = { |
735 | .name = ZORAN_NAME, |
736 | .fops = &zoran_fops, |
737 | .ioctl_ops = &zoran_ioctl_ops, |
738 | .release = &zoran_vdev_release, |
739 | .tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM, |
740 | }; |
741 | |
742 | static int zr_vb2_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, |
743 | unsigned int sizes[], struct device *alloc_devs[]) |
744 | { |
745 | struct zoran *zr = vb2_get_drv_priv(q: vq); |
746 | unsigned int size = zr->buffer_size; |
747 | |
748 | pci_dbg(zr->pci_dev, "%s nbuf=%u nplanes=%u" , __func__, *nbuffers, *nplanes); |
749 | |
750 | zr->buf_in_reserve = 0; |
751 | |
752 | if (*nbuffers < vq->min_queued_buffers) |
753 | *nbuffers = vq->min_queued_buffers; |
754 | |
755 | if (*nplanes) { |
756 | if (sizes[0] < size) |
757 | return -EINVAL; |
758 | else |
759 | return 0; |
760 | } |
761 | |
762 | *nplanes = 1; |
763 | sizes[0] = size; |
764 | |
765 | return 0; |
766 | } |
767 | |
768 | static void zr_vb2_queue(struct vb2_buffer *vb) |
769 | { |
770 | struct zoran *zr = vb2_get_drv_priv(q: vb->vb2_queue); |
771 | struct zr_buffer *buf = vb2_to_zr_buffer(vb); |
772 | unsigned long flags; |
773 | |
774 | spin_lock_irqsave(&zr->queued_bufs_lock, flags); |
775 | list_add_tail(new: &buf->queue, head: &zr->queued_bufs); |
776 | zr->buf_in_reserve++; |
777 | spin_unlock_irqrestore(lock: &zr->queued_bufs_lock, flags); |
778 | if (zr->running == ZORAN_MAP_MODE_JPG_REC) |
779 | zoran_feed_stat_com(zr); |
780 | zr->queued++; |
781 | } |
782 | |
783 | static int zr_vb2_prepare(struct vb2_buffer *vb) |
784 | { |
785 | struct zoran *zr = vb2_get_drv_priv(q: vb->vb2_queue); |
786 | |
787 | if (vb2_plane_size(vb, plane_no: 0) < zr->buffer_size) |
788 | return -EINVAL; |
789 | zr->prepared++; |
790 | |
791 | return 0; |
792 | } |
793 | |
794 | int zr_set_buf(struct zoran *zr) |
795 | { |
796 | struct zr_buffer *buf; |
797 | struct vb2_v4l2_buffer *vbuf; |
798 | dma_addr_t phys_addr; |
799 | unsigned long flags; |
800 | u32 reg; |
801 | |
802 | if (zr->running == ZORAN_MAP_MODE_NONE) |
803 | return 0; |
804 | |
805 | if (zr->inuse[0]) { |
806 | buf = zr->inuse[0]; |
807 | buf->vbuf.vb2_buf.timestamp = ktime_get_ns(); |
808 | buf->vbuf.sequence = zr->vbseq++; |
809 | vbuf = &buf->vbuf; |
810 | |
811 | buf->vbuf.field = V4L2_FIELD_INTERLACED; |
812 | if (BUZ_MAX_HEIGHT < (zr->v4l_settings.height * 2)) |
813 | buf->vbuf.field = V4L2_FIELD_INTERLACED; |
814 | else |
815 | buf->vbuf.field = V4L2_FIELD_TOP; |
816 | vb2_set_plane_payload(vb: &buf->vbuf.vb2_buf, plane_no: 0, size: zr->buffer_size); |
817 | vb2_buffer_done(vb: &buf->vbuf.vb2_buf, state: VB2_BUF_STATE_DONE); |
818 | zr->inuse[0] = NULL; |
819 | } |
820 | |
821 | spin_lock_irqsave(&zr->queued_bufs_lock, flags); |
822 | if (list_empty(head: &zr->queued_bufs)) { |
823 | btand(~ZR36057_ICR_INT_PIN_EN, ZR36057_ICR); |
824 | vb2_queue_error(q: zr->video_dev->queue); |
825 | spin_unlock_irqrestore(lock: &zr->queued_bufs_lock, flags); |
826 | return -EINVAL; |
827 | } |
828 | buf = list_first_entry_or_null(&zr->queued_bufs, struct zr_buffer, queue); |
829 | if (!buf) { |
830 | btand(~ZR36057_ICR_INT_PIN_EN, ZR36057_ICR); |
831 | vb2_queue_error(q: zr->video_dev->queue); |
832 | spin_unlock_irqrestore(lock: &zr->queued_bufs_lock, flags); |
833 | return -EINVAL; |
834 | } |
835 | list_del(entry: &buf->queue); |
836 | zr->buf_in_reserve--; |
837 | spin_unlock_irqrestore(lock: &zr->queued_bufs_lock, flags); |
838 | |
839 | vbuf = &buf->vbuf; |
840 | vbuf->vb2_buf.state = VB2_BUF_STATE_ACTIVE; |
841 | phys_addr = vb2_dma_contig_plane_dma_addr(vb: &vbuf->vb2_buf, plane_no: 0); |
842 | |
843 | if (!phys_addr) |
844 | return -EINVAL; |
845 | |
846 | zr->inuse[0] = buf; |
847 | |
848 | reg = phys_addr; |
849 | btwrite(reg, ZR36057_VDTR); |
850 | if (zr->v4l_settings.height > BUZ_MAX_HEIGHT / 2) |
851 | reg += zr->v4l_settings.bytesperline; |
852 | btwrite(reg, ZR36057_VDBR); |
853 | |
854 | reg = 0; |
855 | if (zr->v4l_settings.height > BUZ_MAX_HEIGHT / 2) |
856 | reg += zr->v4l_settings.bytesperline; |
857 | reg = (reg << ZR36057_VSSFGR_DISP_STRIDE); |
858 | reg |= ZR36057_VSSFGR_VID_OVF; |
859 | reg |= ZR36057_VSSFGR_SNAP_SHOT; |
860 | reg |= ZR36057_VSSFGR_FRAME_GRAB; |
861 | btwrite(reg, ZR36057_VSSFGR); |
862 | |
863 | btor(ZR36057_VDCR_VID_EN, ZR36057_VDCR); |
864 | return 0; |
865 | } |
866 | |
867 | static int zr_vb2_start_streaming(struct vb2_queue *vq, unsigned int count) |
868 | { |
869 | struct zoran *zr = vq->drv_priv; |
870 | int j; |
871 | |
872 | for (j = 0; j < BUZ_NUM_STAT_COM; j++) { |
873 | zr->stat_com[j] = cpu_to_le32(1); |
874 | zr->inuse[j] = NULL; |
875 | } |
876 | zr->vbseq = 0; |
877 | |
878 | if (zr->map_mode != ZORAN_MAP_MODE_RAW) { |
879 | pci_dbg(zr->pci_dev, "START JPG\n" ); |
880 | zr36057_restart(zr); |
881 | zoran_init_hardware(zr); |
882 | if (zr->map_mode == ZORAN_MAP_MODE_JPG_REC) |
883 | zr36057_enable_jpg(zr, mode: BUZ_MODE_MOTION_DECOMPRESS); |
884 | else |
885 | zr36057_enable_jpg(zr, mode: BUZ_MODE_MOTION_COMPRESS); |
886 | zoran_feed_stat_com(zr); |
887 | jpeg_start(zr); |
888 | zr->running = zr->map_mode; |
889 | btor(ZR36057_ICR_INT_PIN_EN, ZR36057_ICR); |
890 | return 0; |
891 | } |
892 | |
893 | pci_dbg(zr->pci_dev, "START RAW\n" ); |
894 | zr36057_restart(zr); |
895 | zoran_init_hardware(zr); |
896 | |
897 | zr36057_enable_jpg(zr, mode: BUZ_MODE_IDLE); |
898 | zr36057_set_memgrab(zr, mode: 1); |
899 | zr->running = zr->map_mode; |
900 | btor(ZR36057_ICR_INT_PIN_EN, ZR36057_ICR); |
901 | return 0; |
902 | } |
903 | |
904 | static void zr_vb2_stop_streaming(struct vb2_queue *vq) |
905 | { |
906 | struct zoran *zr = vq->drv_priv; |
907 | struct zr_buffer *buf; |
908 | unsigned long flags; |
909 | int j; |
910 | |
911 | btand(~ZR36057_ICR_INT_PIN_EN, ZR36057_ICR); |
912 | if (zr->map_mode != ZORAN_MAP_MODE_RAW) |
913 | zr36057_enable_jpg(zr, mode: BUZ_MODE_IDLE); |
914 | zr36057_set_memgrab(zr, mode: 0); |
915 | zr->running = ZORAN_MAP_MODE_NONE; |
916 | |
917 | zoran_set_pci_master(zr, set_master: 0); |
918 | |
919 | if (!pass_through) { /* Switch to color bar */ |
920 | decoder_call(zr, video, s_stream, 0); |
921 | encoder_call(zr, video, s_routing, 2, 0, 0); |
922 | } |
923 | |
924 | for (j = 0; j < BUZ_NUM_STAT_COM; j++) { |
925 | zr->stat_com[j] = cpu_to_le32(1); |
926 | if (!zr->inuse[j]) |
927 | continue; |
928 | buf = zr->inuse[j]; |
929 | pci_dbg(zr->pci_dev, "%s clean buf %d\n" , __func__, j); |
930 | vb2_buffer_done(vb: &buf->vbuf.vb2_buf, state: VB2_BUF_STATE_ERROR); |
931 | zr->inuse[j] = NULL; |
932 | } |
933 | |
934 | spin_lock_irqsave(&zr->queued_bufs_lock, flags); |
935 | while (!list_empty(head: &zr->queued_bufs)) { |
936 | buf = list_entry(zr->queued_bufs.next, struct zr_buffer, queue); |
937 | list_del(entry: &buf->queue); |
938 | vb2_buffer_done(vb: &buf->vbuf.vb2_buf, state: VB2_BUF_STATE_ERROR); |
939 | zr->buf_in_reserve--; |
940 | } |
941 | spin_unlock_irqrestore(lock: &zr->queued_bufs_lock, flags); |
942 | if (zr->buf_in_reserve) |
943 | pci_dbg(zr->pci_dev, "Buffer remaining %d\n" , zr->buf_in_reserve); |
944 | zr->map_mode = ZORAN_MAP_MODE_RAW; |
945 | } |
946 | |
947 | static const struct vb2_ops zr_video_qops = { |
948 | .queue_setup = zr_vb2_queue_setup, |
949 | .buf_queue = zr_vb2_queue, |
950 | .buf_prepare = zr_vb2_prepare, |
951 | .start_streaming = zr_vb2_start_streaming, |
952 | .stop_streaming = zr_vb2_stop_streaming, |
953 | .wait_prepare = vb2_ops_wait_prepare, |
954 | .wait_finish = vb2_ops_wait_finish, |
955 | }; |
956 | |
957 | int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq, int dir) |
958 | { |
959 | int err; |
960 | |
961 | spin_lock_init(&zr->queued_bufs_lock); |
962 | INIT_LIST_HEAD(list: &zr->queued_bufs); |
963 | |
964 | vq->dev = &zr->pci_dev->dev; |
965 | vq->type = dir; |
966 | |
967 | vq->io_modes = VB2_DMABUF | VB2_MMAP; |
968 | vq->drv_priv = zr; |
969 | vq->buf_struct_size = sizeof(struct zr_buffer); |
970 | vq->ops = &zr_video_qops; |
971 | vq->mem_ops = &vb2_dma_contig_memops; |
972 | vq->gfp_flags = GFP_DMA32; |
973 | vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
974 | vq->min_queued_buffers = 9; |
975 | vq->lock = &zr->lock; |
976 | err = vb2_queue_init(q: vq); |
977 | if (err) |
978 | return err; |
979 | zr->video_dev->queue = vq; |
980 | return 0; |
981 | } |
982 | |
983 | void zoran_queue_exit(struct zoran *zr) |
984 | { |
985 | vb2_queue_release(q: zr->video_dev->queue); |
986 | } |
987 | |