Commit | Line | Data |
---|---|---|
1e6dd65e MCC |
1 | /* |
2 | * Virtual Video driver - This code emulates a real video device with v4l2 api | |
3 | * | |
4 | * Copyright (c) 2006 by: | |
5 | * Mauro Carvalho Chehab <mchehab--a.t--infradead.org> | |
6 | * Ted Walther <ted--a.t--enumera.com> | |
7 | * John Sokol <sokol--a.t--videotechnology.com> | |
8 | * http://v4l.videotechnology.com/ | |
9 | * | |
e007a325 PO |
10 | * Conversion to videobuf2 by Pawel Osciak & Marek Szyprowski |
11 | * Copyright (c) 2010 Samsung Electronics | |
12 | * | |
1e6dd65e MCC |
13 | * This program is free software; you can redistribute it and/or modify |
14 | * it under the terms of the BSD Licence, GNU General Public License | |
15 | * as published by the Free Software Foundation; either version 2 of the | |
16 | * License, or (at your option) any later version | |
17 | */ | |
18 | #include <linux/module.h> | |
1e6dd65e | 19 | #include <linux/errno.h> |
1e6dd65e | 20 | #include <linux/kernel.h> |
1e6dd65e MCC |
21 | #include <linux/init.h> |
22 | #include <linux/sched.h> | |
6b46c397 | 23 | #include <linux/slab.h> |
730947bc | 24 | #include <linux/font.h> |
51b54029 | 25 | #include <linux/mutex.h> |
1e6dd65e | 26 | #include <linux/videodev2.h> |
1e6dd65e | 27 | #include <linux/kthread.h> |
7dfb7103 | 28 | #include <linux/freezer.h> |
e007a325 | 29 | #include <media/videobuf2-vmalloc.h> |
5ab6c9af HV |
30 | #include <media/v4l2-device.h> |
31 | #include <media/v4l2-ioctl.h> | |
7e996afa | 32 | #include <media/v4l2-ctrls.h> |
2e4784d0 | 33 | #include <media/v4l2-fh.h> |
c7a52f8d | 34 | #include <media/v4l2-event.h> |
730947bc | 35 | #include <media/v4l2-common.h> |
1e6dd65e | 36 | |
584ce48d | 37 | #define VIVI_MODULE_NAME "vivi" |
745271ae | 38 | |
fe0e990b KS |
39 | /* Maximum allowed frame rate |
40 | * | |
41 | * Vivi will allow setting timeperframe in [1/FPS_MAX - FPS_MAX/1] range. | |
42 | * | |
43 | * Ideally FPS_MAX should be infinity, i.e. practically UINT_MAX, but that | |
44 | * might hit application errors when they manipulate these values. | |
45 | * | |
46 | * Besides, for tpf < 1ms image-generation logic should be changed, to avoid | |
47 | * producing frames with equal content. | |
48 | */ | |
49 | #define FPS_MAX 1000 | |
1e6dd65e | 50 | |
730947bc HV |
51 | #define MAX_WIDTH 1920 |
52 | #define MAX_HEIGHT 1200 | |
53 | ||
1990d50b | 54 | #define VIVI_VERSION "0.8.1" |
1e6dd65e | 55 | |
5ab6c9af HV |
56 | MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board"); |
57 | MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol"); | |
58 | MODULE_LICENSE("Dual BSD/GPL"); | |
1990d50b | 59 | MODULE_VERSION(VIVI_VERSION); |
5ab6c9af HV |
60 | |
61 | static unsigned video_nr = -1; | |
62 | module_param(video_nr, uint, 0644); | |
63 | MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect"); | |
64 | ||
65 | static unsigned n_devs = 1; | |
66 | module_param(n_devs, uint, 0644); | |
67 | MODULE_PARM_DESC(n_devs, "number of video devices to create"); | |
68 | ||
69 | static unsigned debug; | |
70 | module_param(debug, uint, 0644); | |
71 | MODULE_PARM_DESC(debug, "activates debug info"); | |
72 | ||
730947bc HV |
73 | /* Global font descriptor */ |
74 | static const u8 *font8x16; | |
1e6dd65e | 75 | |
fe0e990b KS |
76 | /* timeperframe: min/max and default */ |
77 | static const struct v4l2_fract | |
78 | tpf_min = {.numerator = 1, .denominator = FPS_MAX}, | |
79 | tpf_max = {.numerator = FPS_MAX, .denominator = 1}, | |
80 | tpf_default = {.numerator = 1001, .denominator = 30000}; /* NTSC */ | |
81 | ||
5ab6c9af HV |
82 | #define dprintk(dev, level, fmt, arg...) \ |
83 | v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg) | |
1e6dd65e MCC |
84 | |
85 | /* ------------------------------------------------------------------ | |
86 | Basic structures | |
87 | ------------------------------------------------------------------*/ | |
88 | ||
89 | struct vivi_fmt { | |
c19bec50 | 90 | const char *name; |
1e6dd65e | 91 | u32 fourcc; /* v4l2 format id */ |
0a3a8a36 HV |
92 | u8 depth; |
93 | bool is_yuv; | |
1e6dd65e MCC |
94 | }; |
95 | ||
c19bec50 | 96 | static const struct vivi_fmt formats[] = { |
d891f475 MD |
97 | { |
98 | .name = "4:2:2, packed, YUYV", | |
99 | .fourcc = V4L2_PIX_FMT_YUYV, | |
100 | .depth = 16, | |
0a3a8a36 | 101 | .is_yuv = true, |
d891f475 | 102 | }, |
fca36bab MD |
103 | { |
104 | .name = "4:2:2, packed, UYVY", | |
105 | .fourcc = V4L2_PIX_FMT_UYVY, | |
106 | .depth = 16, | |
0a3a8a36 | 107 | .is_yuv = true, |
fca36bab | 108 | }, |
3d51dca2 HV |
109 | { |
110 | .name = "4:2:2, packed, YVYU", | |
111 | .fourcc = V4L2_PIX_FMT_YVYU, | |
112 | .depth = 16, | |
0a3a8a36 | 113 | .is_yuv = true, |
3d51dca2 HV |
114 | }, |
115 | { | |
116 | .name = "4:2:2, packed, VYUY", | |
117 | .fourcc = V4L2_PIX_FMT_VYUY, | |
118 | .depth = 16, | |
0a3a8a36 | 119 | .is_yuv = true, |
3d51dca2 | 120 | }, |
aeadb5d4 MD |
121 | { |
122 | .name = "RGB565 (LE)", | |
123 | .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ | |
124 | .depth = 16, | |
125 | }, | |
126 | { | |
127 | .name = "RGB565 (BE)", | |
128 | .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ | |
129 | .depth = 16, | |
130 | }, | |
def52393 MD |
131 | { |
132 | .name = "RGB555 (LE)", | |
133 | .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */ | |
134 | .depth = 16, | |
135 | }, | |
136 | { | |
137 | .name = "RGB555 (BE)", | |
138 | .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */ | |
139 | .depth = 16, | |
140 | }, | |
3d51dca2 HV |
141 | { |
142 | .name = "RGB24 (LE)", | |
143 | .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */ | |
144 | .depth = 24, | |
145 | }, | |
146 | { | |
147 | .name = "RGB24 (BE)", | |
148 | .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */ | |
149 | .depth = 24, | |
150 | }, | |
151 | { | |
152 | .name = "RGB32 (LE)", | |
153 | .fourcc = V4L2_PIX_FMT_RGB32, /* argb */ | |
154 | .depth = 32, | |
155 | }, | |
156 | { | |
157 | .name = "RGB32 (BE)", | |
158 | .fourcc = V4L2_PIX_FMT_BGR32, /* bgra */ | |
159 | .depth = 32, | |
160 | }, | |
1e6dd65e MCC |
161 | }; |
162 | ||
c19bec50 | 163 | static const struct vivi_fmt *__get_format(u32 pixelformat) |
d891f475 | 164 | { |
c19bec50 | 165 | const struct vivi_fmt *fmt; |
d891f475 MD |
166 | unsigned int k; |
167 | ||
168 | for (k = 0; k < ARRAY_SIZE(formats); k++) { | |
169 | fmt = &formats[k]; | |
fe0e990b | 170 | if (fmt->fourcc == pixelformat) |
d891f475 MD |
171 | break; |
172 | } | |
173 | ||
174 | if (k == ARRAY_SIZE(formats)) | |
175 | return NULL; | |
176 | ||
177 | return &formats[k]; | |
178 | } | |
179 | ||
c19bec50 | 180 | static const struct vivi_fmt *get_format(struct v4l2_format *f) |
fe0e990b KS |
181 | { |
182 | return __get_format(f->fmt.pix.pixelformat); | |
183 | } | |
184 | ||
1e6dd65e MCC |
185 | /* buffer for one video frame */ |
186 | struct vivi_buffer { | |
187 | /* common v4l buffer stuff -- must be first */ | |
e007a325 PO |
188 | struct vb2_buffer vb; |
189 | struct list_head list; | |
1e6dd65e MCC |
190 | }; |
191 | ||
192 | struct vivi_dmaqueue { | |
193 | struct list_head active; | |
1e6dd65e MCC |
194 | |
195 | /* thread for generating video stream*/ | |
196 | struct task_struct *kthread; | |
197 | wait_queue_head_t wq; | |
198 | /* Counters to control fps rate */ | |
199 | int frame; | |
200 | int ini_jiffies; | |
201 | }; | |
202 | ||
203 | static LIST_HEAD(vivi_devlist); | |
204 | ||
205 | struct vivi_dev { | |
206 | struct list_head vivi_devlist; | |
5ab6c9af | 207 | struct v4l2_device v4l2_dev; |
7e996afa | 208 | struct v4l2_ctrl_handler ctrl_handler; |
70bd97ae | 209 | struct video_device vdev; |
1e6dd65e | 210 | |
730947bc | 211 | /* controls */ |
7e996afa HV |
212 | struct v4l2_ctrl *brightness; |
213 | struct v4l2_ctrl *contrast; | |
214 | struct v4l2_ctrl *saturation; | |
215 | struct v4l2_ctrl *hue; | |
a1c894fb HV |
216 | struct { |
217 | /* autogain/gain cluster */ | |
218 | struct v4l2_ctrl *autogain; | |
219 | struct v4l2_ctrl *gain; | |
220 | }; | |
7e996afa | 221 | struct v4l2_ctrl *volume; |
7088f4df | 222 | struct v4l2_ctrl *alpha; |
7e996afa HV |
223 | struct v4l2_ctrl *button; |
224 | struct v4l2_ctrl *boolean; | |
225 | struct v4l2_ctrl *int32; | |
226 | struct v4l2_ctrl *int64; | |
227 | struct v4l2_ctrl *menu; | |
228 | struct v4l2_ctrl *string; | |
b6d17a56 | 229 | struct v4l2_ctrl *bitmask; |
c520331a | 230 | struct v4l2_ctrl *int_menu; |
730947bc | 231 | |
55862ac9 | 232 | spinlock_t slock; |
aa9dbac4 | 233 | struct mutex mutex; |
1e6dd65e | 234 | |
1e6dd65e MCC |
235 | struct vivi_dmaqueue vidq; |
236 | ||
237 | /* Several counters */ | |
730947bc | 238 | unsigned ms; |
dfd8c04e | 239 | unsigned long jiffies; |
7e996afa | 240 | unsigned button_pressed; |
025341d4 MCC |
241 | |
242 | int mv_count; /* Controls bars movement */ | |
e164b58a MCC |
243 | |
244 | /* Input Number */ | |
245 | int input; | |
c41ee24b | 246 | |
1e6dd65e | 247 | /* video capture */ |
c19bec50 | 248 | const struct vivi_fmt *fmt; |
fe0e990b | 249 | struct v4l2_fract timeperframe; |
543323bc | 250 | unsigned int width, height; |
e007a325 | 251 | struct vb2_queue vb_vidq; |
f0af5e8f | 252 | unsigned int seq_count; |
1e6dd65e | 253 | |
3d51dca2 | 254 | u8 bars[9][3]; |
10ce8441 | 255 | u8 line[MAX_WIDTH * 8] __attribute__((__aligned__(4))); |
3d51dca2 | 256 | unsigned int pixelsize; |
7088f4df | 257 | u8 alpha_component; |
e3a8b4d2 | 258 | u32 textfg, textbg; |
1e6dd65e MCC |
259 | }; |
260 | ||
261 | /* ------------------------------------------------------------------ | |
262 | DMA and thread functions | |
263 | ------------------------------------------------------------------*/ | |
264 | ||
265 | /* Bars and Colors should match positions */ | |
266 | ||
267 | enum colors { | |
268 | WHITE, | |
730947bc | 269 | AMBER, |
1e6dd65e MCC |
270 | CYAN, |
271 | GREEN, | |
272 | MAGENTA, | |
273 | RED, | |
543323bc MCC |
274 | BLUE, |
275 | BLACK, | |
730947bc | 276 | TEXT_BLACK, |
1e6dd65e MCC |
277 | }; |
278 | ||
730947bc | 279 | /* R G B */ |
e164b58a | 280 | #define COLOR_WHITE {204, 204, 204} |
730947bc HV |
281 | #define COLOR_AMBER {208, 208, 0} |
282 | #define COLOR_CYAN { 0, 206, 206} | |
e164b58a MCC |
283 | #define COLOR_GREEN { 0, 239, 0} |
284 | #define COLOR_MAGENTA {239, 0, 239} | |
285 | #define COLOR_RED {205, 0, 0} | |
286 | #define COLOR_BLUE { 0, 0, 255} | |
287 | #define COLOR_BLACK { 0, 0, 0} | |
288 | ||
289 | struct bar_std { | |
730947bc | 290 | u8 bar[9][3]; |
e164b58a MCC |
291 | }; |
292 | ||
293 | /* Maximum number of bars are 10 - otherwise, the input print code | |
294 | should be modified */ | |
c19bec50 | 295 | static const struct bar_std bars[] = { |
e164b58a | 296 | { /* Standard ITU-R color bar sequence */ |
730947bc HV |
297 | { COLOR_WHITE, COLOR_AMBER, COLOR_CYAN, COLOR_GREEN, |
298 | COLOR_MAGENTA, COLOR_RED, COLOR_BLUE, COLOR_BLACK, COLOR_BLACK } | |
e164b58a | 299 | }, { |
730947bc HV |
300 | { COLOR_WHITE, COLOR_AMBER, COLOR_BLACK, COLOR_WHITE, |
301 | COLOR_AMBER, COLOR_BLACK, COLOR_WHITE, COLOR_AMBER, COLOR_BLACK } | |
e164b58a | 302 | }, { |
730947bc HV |
303 | { COLOR_WHITE, COLOR_CYAN, COLOR_BLACK, COLOR_WHITE, |
304 | COLOR_CYAN, COLOR_BLACK, COLOR_WHITE, COLOR_CYAN, COLOR_BLACK } | |
e164b58a | 305 | }, { |
730947bc HV |
306 | { COLOR_WHITE, COLOR_GREEN, COLOR_BLACK, COLOR_WHITE, |
307 | COLOR_GREEN, COLOR_BLACK, COLOR_WHITE, COLOR_GREEN, COLOR_BLACK } | |
e164b58a | 308 | }, |
1e6dd65e MCC |
309 | }; |
310 | ||
e164b58a MCC |
311 | #define NUM_INPUTS ARRAY_SIZE(bars) |
312 | ||
543323bc MCC |
313 | #define TO_Y(r, g, b) \ |
314 | (((16829 * r + 33039 * g + 6416 * b + 32768) >> 16) + 16) | |
1e6dd65e | 315 | /* RGB to V(Cr) Color transform */ |
543323bc MCC |
316 | #define TO_V(r, g, b) \ |
317 | (((28784 * r - 24103 * g - 4681 * b + 32768) >> 16) + 128) | |
1e6dd65e | 318 | /* RGB to U(Cb) Color transform */ |
543323bc MCC |
319 | #define TO_U(r, g, b) \ |
320 | (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128) | |
1e6dd65e | 321 | |
c285addb | 322 | /* precalculate color bar values to speed up rendering */ |
730947bc | 323 | static void precalculate_bars(struct vivi_dev *dev) |
c285addb | 324 | { |
730947bc | 325 | u8 r, g, b; |
c285addb MCC |
326 | int k, is_yuv; |
327 | ||
730947bc HV |
328 | for (k = 0; k < 9; k++) { |
329 | r = bars[dev->input].bar[k][0]; | |
330 | g = bars[dev->input].bar[k][1]; | |
331 | b = bars[dev->input].bar[k][2]; | |
0a3a8a36 | 332 | is_yuv = dev->fmt->is_yuv; |
c285addb | 333 | |
730947bc | 334 | switch (dev->fmt->fourcc) { |
c285addb MCC |
335 | case V4L2_PIX_FMT_RGB565: |
336 | case V4L2_PIX_FMT_RGB565X: | |
337 | r >>= 3; | |
338 | g >>= 2; | |
339 | b >>= 3; | |
340 | break; | |
341 | case V4L2_PIX_FMT_RGB555: | |
342 | case V4L2_PIX_FMT_RGB555X: | |
343 | r >>= 3; | |
344 | g >>= 3; | |
345 | b >>= 3; | |
346 | break; | |
0a3a8a36 HV |
347 | case V4L2_PIX_FMT_YUYV: |
348 | case V4L2_PIX_FMT_UYVY: | |
349 | case V4L2_PIX_FMT_YVYU: | |
350 | case V4L2_PIX_FMT_VYUY: | |
3d51dca2 HV |
351 | case V4L2_PIX_FMT_RGB24: |
352 | case V4L2_PIX_FMT_BGR24: | |
353 | case V4L2_PIX_FMT_RGB32: | |
354 | case V4L2_PIX_FMT_BGR32: | |
355 | break; | |
c285addb MCC |
356 | } |
357 | ||
358 | if (is_yuv) { | |
730947bc HV |
359 | dev->bars[k][0] = TO_Y(r, g, b); /* Luma */ |
360 | dev->bars[k][1] = TO_U(r, g, b); /* Cb */ | |
361 | dev->bars[k][2] = TO_V(r, g, b); /* Cr */ | |
c285addb | 362 | } else { |
730947bc HV |
363 | dev->bars[k][0] = r; |
364 | dev->bars[k][1] = g; | |
365 | dev->bars[k][2] = b; | |
c285addb MCC |
366 | } |
367 | } | |
c285addb MCC |
368 | } |
369 | ||
3d51dca2 HV |
370 | /* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */ |
371 | static void gen_twopix(struct vivi_dev *dev, u8 *buf, int colorpos, bool odd) | |
74d7c5af | 372 | { |
730947bc | 373 | u8 r_y, g_u, b_v; |
7088f4df | 374 | u8 alpha = dev->alpha_component; |
74d7c5af | 375 | int color; |
730947bc | 376 | u8 *p; |
74d7c5af | 377 | |
730947bc HV |
378 | r_y = dev->bars[colorpos][0]; /* R or precalculated Y */ |
379 | g_u = dev->bars[colorpos][1]; /* G or precalculated U */ | |
380 | b_v = dev->bars[colorpos][2]; /* B or precalculated V */ | |
74d7c5af | 381 | |
3d51dca2 | 382 | for (color = 0; color < dev->pixelsize; color++) { |
74d7c5af MD |
383 | p = buf + color; |
384 | ||
730947bc | 385 | switch (dev->fmt->fourcc) { |
d891f475 MD |
386 | case V4L2_PIX_FMT_YUYV: |
387 | switch (color) { | |
388 | case 0: | |
d891f475 MD |
389 | *p = r_y; |
390 | break; | |
391 | case 1: | |
3d51dca2 | 392 | *p = odd ? b_v : g_u; |
d891f475 MD |
393 | break; |
394 | } | |
74d7c5af | 395 | break; |
fca36bab MD |
396 | case V4L2_PIX_FMT_UYVY: |
397 | switch (color) { | |
3d51dca2 HV |
398 | case 0: |
399 | *p = odd ? b_v : g_u; | |
400 | break; | |
fca36bab | 401 | case 1: |
fca36bab MD |
402 | *p = r_y; |
403 | break; | |
3d51dca2 HV |
404 | } |
405 | break; | |
406 | case V4L2_PIX_FMT_YVYU: | |
407 | switch (color) { | |
408 | case 0: | |
409 | *p = r_y; | |
410 | break; | |
411 | case 1: | |
412 | *p = odd ? g_u : b_v; | |
413 | break; | |
414 | } | |
415 | break; | |
416 | case V4L2_PIX_FMT_VYUY: | |
417 | switch (color) { | |
fca36bab | 418 | case 0: |
3d51dca2 | 419 | *p = odd ? g_u : b_v; |
fca36bab | 420 | break; |
3d51dca2 HV |
421 | case 1: |
422 | *p = r_y; | |
fca36bab MD |
423 | break; |
424 | } | |
425 | break; | |
aeadb5d4 MD |
426 | case V4L2_PIX_FMT_RGB565: |
427 | switch (color) { | |
428 | case 0: | |
aeadb5d4 MD |
429 | *p = (g_u << 5) | b_v; |
430 | break; | |
431 | case 1: | |
aeadb5d4 MD |
432 | *p = (r_y << 3) | (g_u >> 3); |
433 | break; | |
434 | } | |
435 | break; | |
436 | case V4L2_PIX_FMT_RGB565X: | |
437 | switch (color) { | |
438 | case 0: | |
aeadb5d4 MD |
439 | *p = (r_y << 3) | (g_u >> 3); |
440 | break; | |
441 | case 1: | |
aeadb5d4 MD |
442 | *p = (g_u << 5) | b_v; |
443 | break; | |
444 | } | |
445 | break; | |
def52393 MD |
446 | case V4L2_PIX_FMT_RGB555: |
447 | switch (color) { | |
448 | case 0: | |
def52393 MD |
449 | *p = (g_u << 5) | b_v; |
450 | break; | |
451 | case 1: | |
7088f4df | 452 | *p = (alpha & 0x80) | (r_y << 2) | (g_u >> 3); |
def52393 MD |
453 | break; |
454 | } | |
455 | break; | |
456 | case V4L2_PIX_FMT_RGB555X: | |
457 | switch (color) { | |
458 | case 0: | |
7088f4df | 459 | *p = (alpha & 0x80) | (r_y << 2) | (g_u >> 3); |
def52393 MD |
460 | break; |
461 | case 1: | |
def52393 MD |
462 | *p = (g_u << 5) | b_v; |
463 | break; | |
464 | } | |
465 | break; | |
3d51dca2 HV |
466 | case V4L2_PIX_FMT_RGB24: |
467 | switch (color) { | |
468 | case 0: | |
469 | *p = r_y; | |
470 | break; | |
471 | case 1: | |
472 | *p = g_u; | |
473 | break; | |
474 | case 2: | |
475 | *p = b_v; | |
476 | break; | |
477 | } | |
478 | break; | |
479 | case V4L2_PIX_FMT_BGR24: | |
480 | switch (color) { | |
481 | case 0: | |
482 | *p = b_v; | |
483 | break; | |
484 | case 1: | |
485 | *p = g_u; | |
486 | break; | |
487 | case 2: | |
488 | *p = r_y; | |
489 | break; | |
490 | } | |
491 | break; | |
492 | case V4L2_PIX_FMT_RGB32: | |
493 | switch (color) { | |
494 | case 0: | |
7088f4df | 495 | *p = alpha; |
3d51dca2 HV |
496 | break; |
497 | case 1: | |
498 | *p = r_y; | |
499 | break; | |
500 | case 2: | |
501 | *p = g_u; | |
502 | break; | |
503 | case 3: | |
504 | *p = b_v; | |
505 | break; | |
506 | } | |
507 | break; | |
508 | case V4L2_PIX_FMT_BGR32: | |
509 | switch (color) { | |
510 | case 0: | |
511 | *p = b_v; | |
512 | break; | |
513 | case 1: | |
514 | *p = g_u; | |
515 | break; | |
516 | case 2: | |
517 | *p = r_y; | |
518 | break; | |
519 | case 3: | |
7088f4df | 520 | *p = alpha; |
3d51dca2 HV |
521 | break; |
522 | } | |
523 | break; | |
74d7c5af MD |
524 | } |
525 | } | |
526 | } | |
527 | ||
730947bc | 528 | static void precalculate_line(struct vivi_dev *dev) |
1e6dd65e | 529 | { |
d40fbf8d KS |
530 | unsigned pixsize = dev->pixelsize; |
531 | unsigned pixsize2 = 2*pixsize; | |
532 | int colorpos; | |
533 | u8 *pos; | |
534 | ||
535 | for (colorpos = 0; colorpos < 16; ++colorpos) { | |
536 | u8 pix[8]; | |
537 | int wstart = colorpos * dev->width / 8; | |
538 | int wend = (colorpos+1) * dev->width / 8; | |
539 | int w; | |
540 | ||
541 | gen_twopix(dev, &pix[0], colorpos % 8, 0); | |
542 | gen_twopix(dev, &pix[pixsize], colorpos % 8, 1); | |
543 | ||
544 | for (w = wstart/2*2, pos = dev->line + w*pixsize; w < wend; w += 2, pos += pixsize2) | |
545 | memcpy(pos, pix, pixsize2); | |
1e6dd65e | 546 | } |
730947bc | 547 | } |
1e6dd65e | 548 | |
e3a8b4d2 KS |
549 | /* need this to do rgb24 rendering */ |
550 | typedef struct { u16 __; u8 _; } __attribute__((packed)) x24; | |
551 | ||
730947bc HV |
552 | static void gen_text(struct vivi_dev *dev, char *basep, |
553 | int y, int x, char *text) | |
554 | { | |
555 | int line; | |
e3a8b4d2 | 556 | unsigned int width = dev->width; |
e164b58a | 557 | |
730947bc | 558 | /* Checks if it is possible to show string */ |
e3a8b4d2 | 559 | if (y + 16 >= dev->height || x + strlen(text) * 8 >= width) |
730947bc | 560 | return; |
1e6dd65e MCC |
561 | |
562 | /* Print stream time */ | |
e3a8b4d2 KS |
563 | #define PRINTSTR(PIXTYPE) do { \ |
564 | PIXTYPE fg; \ | |
565 | PIXTYPE bg; \ | |
566 | memcpy(&fg, &dev->textfg, sizeof(PIXTYPE)); \ | |
567 | memcpy(&bg, &dev->textbg, sizeof(PIXTYPE)); \ | |
568 | \ | |
569 | for (line = 0; line < 16; line++) { \ | |
570 | PIXTYPE *pos = (PIXTYPE *)( basep + ((y + line) * width + x) * sizeof(PIXTYPE) ); \ | |
571 | u8 *s; \ | |
572 | \ | |
573 | for (s = text; *s; s++) { \ | |
574 | u8 chr = font8x16[*s * 16 + line]; \ | |
575 | \ | |
576 | pos[0] = (chr & (0x01 << 7) ? fg : bg); \ | |
577 | pos[1] = (chr & (0x01 << 6) ? fg : bg); \ | |
578 | pos[2] = (chr & (0x01 << 5) ? fg : bg); \ | |
579 | pos[3] = (chr & (0x01 << 4) ? fg : bg); \ | |
580 | pos[4] = (chr & (0x01 << 3) ? fg : bg); \ | |
581 | pos[5] = (chr & (0x01 << 2) ? fg : bg); \ | |
582 | pos[6] = (chr & (0x01 << 1) ? fg : bg); \ | |
583 | pos[7] = (chr & (0x01 << 0) ? fg : bg); \ | |
584 | \ | |
585 | pos += 8; \ | |
586 | } \ | |
587 | } \ | |
588 | } while (0) | |
589 | ||
590 | switch (dev->pixelsize) { | |
591 | case 2: | |
592 | PRINTSTR(u16); break; | |
593 | case 4: | |
594 | PRINTSTR(u32); break; | |
595 | case 3: | |
596 | PRINTSTR(x24); break; | |
1e6dd65e | 597 | } |
1e6dd65e | 598 | } |
78718e5d | 599 | |
730947bc | 600 | static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf) |
1e6dd65e | 601 | { |
13908f33 | 602 | int stride = dev->width * dev->pixelsize; |
e007a325 | 603 | int hmax = dev->height; |
e007a325 | 604 | void *vbuf = vb2_plane_vaddr(&buf->vb, 0); |
730947bc HV |
605 | unsigned ms; |
606 | char str[100]; | |
607 | int h, line = 1; | |
13908f33 | 608 | u8 *linestart; |
a1c894fb | 609 | s32 gain; |
b50e7fe9 | 610 | |
5c554e6b | 611 | if (!vbuf) |
5a037706 | 612 | return; |
1e6dd65e | 613 | |
13908f33 KS |
614 | linestart = dev->line + (dev->mv_count % dev->width) * dev->pixelsize; |
615 | ||
730947bc | 616 | for (h = 0; h < hmax; h++) |
13908f33 | 617 | memcpy(vbuf + h * stride, linestart, stride); |
5a037706 | 618 | |
1e6dd65e MCC |
619 | /* Updates stream time */ |
620 | ||
e3a8b4d2 KS |
621 | gen_twopix(dev, (u8 *)&dev->textbg, TEXT_BLACK, /*odd=*/ 0); |
622 | gen_twopix(dev, (u8 *)&dev->textfg, WHITE, /*odd=*/ 0); | |
623 | ||
730947bc | 624 | dev->ms += jiffies_to_msecs(jiffies - dev->jiffies); |
543323bc | 625 | dev->jiffies = jiffies; |
730947bc HV |
626 | ms = dev->ms; |
627 | snprintf(str, sizeof(str), " %02d:%02d:%02d:%03d ", | |
628 | (ms / (60 * 60 * 1000)) % 24, | |
629 | (ms / (60 * 1000)) % 60, | |
630 | (ms / 1000) % 60, | |
631 | ms % 1000); | |
632 | gen_text(dev, vbuf, line++ * 16, 16, str); | |
633 | snprintf(str, sizeof(str), " %dx%d, input %d ", | |
634 | dev->width, dev->height, dev->input); | |
635 | gen_text(dev, vbuf, line++ * 16, 16, str); | |
636 | ||
a1c894fb | 637 | gain = v4l2_ctrl_g_ctrl(dev->gain); |
77e7c4e6 | 638 | mutex_lock(dev->ctrl_handler.lock); |
730947bc | 639 | snprintf(str, sizeof(str), " brightness %3d, contrast %3d, saturation %3d, hue %d ", |
7e996afa HV |
640 | dev->brightness->cur.val, |
641 | dev->contrast->cur.val, | |
642 | dev->saturation->cur.val, | |
643 | dev->hue->cur.val); | |
730947bc | 644 | gen_text(dev, vbuf, line++ * 16, 16, str); |
7088f4df HV |
645 | snprintf(str, sizeof(str), " autogain %d, gain %3d, volume %3d, alpha 0x%02x ", |
646 | dev->autogain->cur.val, gain, dev->volume->cur.val, | |
647 | dev->alpha->cur.val); | |
730947bc | 648 | gen_text(dev, vbuf, line++ * 16, 16, str); |
b6d17a56 | 649 | snprintf(str, sizeof(str), " int32 %d, int64 %lld, bitmask %08x ", |
7e996afa | 650 | dev->int32->cur.val, |
b6d17a56 HV |
651 | dev->int64->cur.val64, |
652 | dev->bitmask->cur.val); | |
7e996afa HV |
653 | gen_text(dev, vbuf, line++ * 16, 16, str); |
654 | snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ", | |
655 | dev->boolean->cur.val, | |
656 | dev->menu->qmenu[dev->menu->cur.val], | |
657 | dev->string->cur.string); | |
f70cfc7f | 658 | gen_text(dev, vbuf, line++ * 16, 16, str); |
c520331a SA |
659 | snprintf(str, sizeof(str), " integer_menu %lld, value %d ", |
660 | dev->int_menu->qmenu_int[dev->int_menu->cur.val], | |
661 | dev->int_menu->cur.val); | |
662 | gen_text(dev, vbuf, line++ * 16, 16, str); | |
77e7c4e6 | 663 | mutex_unlock(dev->ctrl_handler.lock); |
7e996afa HV |
664 | if (dev->button_pressed) { |
665 | dev->button_pressed--; | |
666 | snprintf(str, sizeof(str), " button pressed!"); | |
667 | gen_text(dev, vbuf, line++ * 16, 16, str); | |
668 | } | |
730947bc HV |
669 | |
670 | dev->mv_count += 2; | |
1e6dd65e | 671 | |
cd779254 | 672 | buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; |
f0af5e8f | 673 | buf->vb.v4l2_buf.sequence = dev->seq_count++; |
8e6057b5 | 674 | v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); |
1e6dd65e MCC |
675 | } |
676 | ||
730947bc | 677 | static void vivi_thread_tick(struct vivi_dev *dev) |
1e6dd65e | 678 | { |
78718e5d | 679 | struct vivi_dmaqueue *dma_q = &dev->vidq; |
730947bc | 680 | struct vivi_buffer *buf; |
78718e5d | 681 | unsigned long flags = 0; |
1e6dd65e | 682 | |
78718e5d | 683 | dprintk(dev, 1, "Thread tick\n"); |
1e6dd65e | 684 | |
78718e5d BP |
685 | spin_lock_irqsave(&dev->slock, flags); |
686 | if (list_empty(&dma_q->active)) { | |
687 | dprintk(dev, 1, "No active queue to serve\n"); | |
1de5be5e HV |
688 | spin_unlock_irqrestore(&dev->slock, flags); |
689 | return; | |
78718e5d | 690 | } |
1e6dd65e | 691 | |
e007a325 PO |
692 | buf = list_entry(dma_q->active.next, struct vivi_buffer, list); |
693 | list_del(&buf->list); | |
1de5be5e | 694 | spin_unlock_irqrestore(&dev->slock, flags); |
1e6dd65e | 695 | |
8e6057b5 | 696 | v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); |
78718e5d BP |
697 | |
698 | /* Fill buffer */ | |
730947bc | 699 | vivi_fillbuff(dev, buf); |
78718e5d BP |
700 | dprintk(dev, 1, "filled buffer %p\n", buf); |
701 | ||
e007a325 PO |
702 | vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); |
703 | dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index); | |
1e6dd65e MCC |
704 | } |
705 | ||
fe0e990b KS |
706 | #define frames_to_ms(dev, frames) \ |
707 | ((frames * dev->timeperframe.numerator * 1000) / dev->timeperframe.denominator) | |
6594ad82 | 708 | |
730947bc | 709 | static void vivi_sleep(struct vivi_dev *dev) |
1e6dd65e | 710 | { |
78718e5d BP |
711 | struct vivi_dmaqueue *dma_q = &dev->vidq; |
712 | int timeout; | |
1e6dd65e MCC |
713 | DECLARE_WAITQUEUE(wait, current); |
714 | ||
7e28adb2 | 715 | dprintk(dev, 1, "%s dma_q=0x%08lx\n", __func__, |
6c2f9901 | 716 | (unsigned long)dma_q); |
1e6dd65e MCC |
717 | |
718 | add_wait_queue(&dma_q->wq, &wait); | |
6594ad82 MCC |
719 | if (kthread_should_stop()) |
720 | goto stop_task; | |
721 | ||
6594ad82 | 722 | /* Calculate time to wake up */ |
fe0e990b | 723 | timeout = msecs_to_jiffies(frames_to_ms(dev, 1)); |
6594ad82 | 724 | |
730947bc | 725 | vivi_thread_tick(dev); |
6594ad82 MCC |
726 | |
727 | schedule_timeout_interruptible(timeout); | |
1e6dd65e | 728 | |
6594ad82 | 729 | stop_task: |
1e6dd65e MCC |
730 | remove_wait_queue(&dma_q->wq, &wait); |
731 | try_to_freeze(); | |
732 | } | |
733 | ||
972c3517 | 734 | static int vivi_thread(void *data) |
1e6dd65e | 735 | { |
730947bc | 736 | struct vivi_dev *dev = data; |
1e6dd65e | 737 | |
6c2f9901 | 738 | dprintk(dev, 1, "thread started\n"); |
1e6dd65e | 739 | |
83144186 | 740 | set_freezable(); |
0b600512 | 741 | |
1e6dd65e | 742 | for (;;) { |
730947bc | 743 | vivi_sleep(dev); |
1e6dd65e MCC |
744 | |
745 | if (kthread_should_stop()) | |
746 | break; | |
747 | } | |
6c2f9901 | 748 | dprintk(dev, 1, "thread: exit\n"); |
1e6dd65e MCC |
749 | return 0; |
750 | } | |
751 | ||
e007a325 | 752 | static int vivi_start_generating(struct vivi_dev *dev) |
1e6dd65e | 753 | { |
78718e5d | 754 | struct vivi_dmaqueue *dma_q = &dev->vidq; |
6c2f9901 | 755 | |
7e28adb2 | 756 | dprintk(dev, 1, "%s\n", __func__); |
1e6dd65e | 757 | |
730947bc HV |
758 | /* Resets frame counters */ |
759 | dev->ms = 0; | |
760 | dev->mv_count = 0; | |
761 | dev->jiffies = jiffies; | |
762 | ||
763 | dma_q->frame = 0; | |
764 | dma_q->ini_jiffies = jiffies; | |
f170168b KC |
765 | dma_q->kthread = kthread_run(vivi_thread, dev, "%s", |
766 | dev->v4l2_dev.name); | |
1e6dd65e | 767 | |
054afee4 | 768 | if (IS_ERR(dma_q->kthread)) { |
5ab6c9af | 769 | v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n"); |
e007a325 | 770 | return PTR_ERR(dma_q->kthread); |
1e6dd65e | 771 | } |
0b600512 MCC |
772 | /* Wakes thread */ |
773 | wake_up_interruptible(&dma_q->wq); | |
774 | ||
7e28adb2 | 775 | dprintk(dev, 1, "returning from %s\n", __func__); |
e007a325 | 776 | return 0; |
1e6dd65e MCC |
777 | } |
778 | ||
e007a325 | 779 | static void vivi_stop_generating(struct vivi_dev *dev) |
1e6dd65e | 780 | { |
730947bc | 781 | struct vivi_dmaqueue *dma_q = &dev->vidq; |
6c2f9901 | 782 | |
7e28adb2 | 783 | dprintk(dev, 1, "%s\n", __func__); |
730947bc | 784 | |
1e6dd65e MCC |
785 | /* shutdown control thread */ |
786 | if (dma_q->kthread) { | |
787 | kthread_stop(dma_q->kthread); | |
543323bc | 788 | dma_q->kthread = NULL; |
1e6dd65e | 789 | } |
730947bc | 790 | |
e007a325 PO |
791 | /* |
792 | * Typical driver might need to wait here until dma engine stops. | |
793 | * In this case we can abort imiedetly, so it's just a noop. | |
794 | */ | |
795 | ||
796 | /* Release all active buffers */ | |
797 | while (!list_empty(&dma_q->active)) { | |
798 | struct vivi_buffer *buf; | |
799 | buf = list_entry(dma_q->active.next, struct vivi_buffer, list); | |
800 | list_del(&buf->list); | |
801 | vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); | |
802 | dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index); | |
803 | } | |
1e6dd65e | 804 | } |
1e6dd65e MCC |
805 | /* ------------------------------------------------------------------ |
806 | Videobuf operations | |
807 | ------------------------------------------------------------------*/ | |
fc714e70 GL |
808 | static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, |
809 | unsigned int *nbuffers, unsigned int *nplanes, | |
810 | unsigned int sizes[], void *alloc_ctxs[]) | |
1e6dd65e | 811 | { |
e007a325 PO |
812 | struct vivi_dev *dev = vb2_get_drv_priv(vq); |
813 | unsigned long size; | |
814 | ||
efab6b6a HV |
815 | size = dev->width * dev->height * dev->pixelsize; |
816 | if (fmt) { | |
817 | if (fmt->fmt.pix.sizeimage < size) | |
818 | return -EINVAL; | |
2e90c6c3 | 819 | size = fmt->fmt.pix.sizeimage; |
efab6b6a HV |
820 | /* check against insane over 8K resolution buffers */ |
821 | if (size > 7680 * 4320 * dev->pixelsize) | |
822 | return -EINVAL; | |
823 | } | |
6bb2790f | 824 | |
e007a325 | 825 | *nplanes = 1; |
6bb2790f | 826 | |
e007a325 PO |
827 | sizes[0] = size; |
828 | ||
829 | /* | |
830 | * videobuf2-vmalloc allocator is context-less so no need to set | |
831 | * alloc_ctxs array. | |
832 | */ | |
833 | ||
834 | dprintk(dev, 1, "%s, count=%d, size=%ld\n", __func__, | |
835 | *nbuffers, size); | |
6bb2790f | 836 | |
1e6dd65e MCC |
837 | return 0; |
838 | } | |
839 | ||
e007a325 | 840 | static int buffer_prepare(struct vb2_buffer *vb) |
1e6dd65e | 841 | { |
e007a325 | 842 | struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue); |
543323bc | 843 | struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); |
e007a325 | 844 | unsigned long size; |
1e6dd65e | 845 | |
e007a325 | 846 | dprintk(dev, 1, "%s, field=%d\n", __func__, vb->v4l2_buf.field); |
1e6dd65e | 847 | |
730947bc | 848 | BUG_ON(NULL == dev->fmt); |
78718e5d | 849 | |
e007a325 PO |
850 | /* |
851 | * Theses properties only change when queue is idle, see s_fmt. | |
852 | * The below checks should not be performed here, on each | |
853 | * buffer_prepare (i.e. on each qbuf). Most of the code in this function | |
854 | * should thus be moved to buffer_init and s_fmt. | |
855 | */ | |
730947bc HV |
856 | if (dev->width < 48 || dev->width > MAX_WIDTH || |
857 | dev->height < 32 || dev->height > MAX_HEIGHT) | |
1e6dd65e | 858 | return -EINVAL; |
78718e5d | 859 | |
3d51dca2 | 860 | size = dev->width * dev->height * dev->pixelsize; |
e007a325 PO |
861 | if (vb2_plane_size(vb, 0) < size) { |
862 | dprintk(dev, 1, "%s data will not fit into plane (%lu < %lu)\n", | |
863 | __func__, vb2_plane_size(vb, 0), size); | |
1e6dd65e | 864 | return -EINVAL; |
e007a325 PO |
865 | } |
866 | ||
867 | vb2_set_plane_payload(&buf->vb, 0, size); | |
1e6dd65e | 868 | |
730947bc HV |
869 | precalculate_bars(dev); |
870 | precalculate_line(dev); | |
c285addb | 871 | |
e007a325 PO |
872 | return 0; |
873 | } | |
1e6dd65e | 874 | |
e007a325 | 875 | static void buffer_queue(struct vb2_buffer *vb) |
1e6dd65e | 876 | { |
e007a325 | 877 | struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue); |
730947bc | 878 | struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); |
78718e5d | 879 | struct vivi_dmaqueue *vidq = &dev->vidq; |
e007a325 | 880 | unsigned long flags = 0; |
78718e5d | 881 | |
7e28adb2 | 882 | dprintk(dev, 1, "%s\n", __func__); |
78718e5d | 883 | |
e007a325 PO |
884 | spin_lock_irqsave(&dev->slock, flags); |
885 | list_add_tail(&buf->list, &vidq->active); | |
886 | spin_unlock_irqrestore(&dev->slock, flags); | |
1e6dd65e MCC |
887 | } |
888 | ||
bd323e28 | 889 | static int start_streaming(struct vb2_queue *vq, unsigned int count) |
1e6dd65e | 890 | { |
e007a325 | 891 | struct vivi_dev *dev = vb2_get_drv_priv(vq); |
48d829da | 892 | int err; |
f0af5e8f | 893 | |
e007a325 | 894 | dprintk(dev, 1, "%s\n", __func__); |
f0af5e8f | 895 | dev->seq_count = 0; |
48d829da HV |
896 | err = vivi_start_generating(dev); |
897 | if (err) { | |
898 | struct vivi_buffer *buf, *tmp; | |
899 | ||
900 | list_for_each_entry_safe(buf, tmp, &dev->vidq.active, list) { | |
901 | list_del(&buf->list); | |
902 | vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED); | |
903 | } | |
904 | } | |
905 | return err; | |
e007a325 | 906 | } |
1e6dd65e | 907 | |
e007a325 | 908 | /* abort streaming and wait for last buffer */ |
e37559b2 | 909 | static void stop_streaming(struct vb2_queue *vq) |
e007a325 PO |
910 | { |
911 | struct vivi_dev *dev = vb2_get_drv_priv(vq); | |
7e28adb2 | 912 | dprintk(dev, 1, "%s\n", __func__); |
e007a325 | 913 | vivi_stop_generating(dev); |
e007a325 PO |
914 | } |
915 | ||
916 | static void vivi_lock(struct vb2_queue *vq) | |
917 | { | |
918 | struct vivi_dev *dev = vb2_get_drv_priv(vq); | |
919 | mutex_lock(&dev->mutex); | |
920 | } | |
1e6dd65e | 921 | |
e007a325 PO |
922 | static void vivi_unlock(struct vb2_queue *vq) |
923 | { | |
924 | struct vivi_dev *dev = vb2_get_drv_priv(vq); | |
925 | mutex_unlock(&dev->mutex); | |
1e6dd65e MCC |
926 | } |
927 | ||
e007a325 | 928 | |
c19bec50 | 929 | static const struct vb2_ops vivi_video_qops = { |
e007a325 | 930 | .queue_setup = queue_setup, |
e007a325 | 931 | .buf_prepare = buffer_prepare, |
e007a325 PO |
932 | .buf_queue = buffer_queue, |
933 | .start_streaming = start_streaming, | |
934 | .stop_streaming = stop_streaming, | |
935 | .wait_prepare = vivi_unlock, | |
936 | .wait_finish = vivi_lock, | |
1e6dd65e MCC |
937 | }; |
938 | ||
c820cc45 MCC |
939 | /* ------------------------------------------------------------------ |
940 | IOCTL vidioc handling | |
941 | ------------------------------------------------------------------*/ | |
543323bc | 942 | static int vidioc_querycap(struct file *file, void *priv, |
c820cc45 MCC |
943 | struct v4l2_capability *cap) |
944 | { | |
730947bc | 945 | struct vivi_dev *dev = video_drvdata(file); |
5ab6c9af | 946 | |
c820cc45 MCC |
947 | strcpy(cap->driver, "vivi"); |
948 | strcpy(cap->card, "vivi"); | |
72c2af6e HV |
949 | snprintf(cap->bus_info, sizeof(cap->bus_info), |
950 | "platform:%s", dev->v4l2_dev.name); | |
23268ae5 HV |
951 | cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | |
952 | V4L2_CAP_READWRITE; | |
953 | cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; | |
c820cc45 MCC |
954 | return 0; |
955 | } | |
956 | ||
78b526a4 | 957 | static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, |
c820cc45 MCC |
958 | struct v4l2_fmtdesc *f) |
959 | { | |
c19bec50 | 960 | const struct vivi_fmt *fmt; |
d891f475 MD |
961 | |
962 | if (f->index >= ARRAY_SIZE(formats)) | |
c820cc45 MCC |
963 | return -EINVAL; |
964 | ||
d891f475 MD |
965 | fmt = &formats[f->index]; |
966 | ||
967 | strlcpy(f->description, fmt->name, sizeof(f->description)); | |
968 | f->pixelformat = fmt->fourcc; | |
c820cc45 MCC |
969 | return 0; |
970 | } | |
971 | ||
78b526a4 | 972 | static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, |
c820cc45 MCC |
973 | struct v4l2_format *f) |
974 | { | |
730947bc | 975 | struct vivi_dev *dev = video_drvdata(file); |
c820cc45 | 976 | |
730947bc HV |
977 | f->fmt.pix.width = dev->width; |
978 | f->fmt.pix.height = dev->height; | |
cd779254 | 979 | f->fmt.pix.field = V4L2_FIELD_INTERLACED; |
730947bc | 980 | f->fmt.pix.pixelformat = dev->fmt->fourcc; |
c820cc45 | 981 | f->fmt.pix.bytesperline = |
730947bc | 982 | (f->fmt.pix.width * dev->fmt->depth) >> 3; |
c820cc45 MCC |
983 | f->fmt.pix.sizeimage = |
984 | f->fmt.pix.height * f->fmt.pix.bytesperline; | |
0a3a8a36 | 985 | if (dev->fmt->is_yuv) |
8c79eece HV |
986 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; |
987 | else | |
988 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; | |
730947bc | 989 | return 0; |
c820cc45 MCC |
990 | } |
991 | ||
78b526a4 | 992 | static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, |
1e6dd65e MCC |
993 | struct v4l2_format *f) |
994 | { | |
730947bc | 995 | struct vivi_dev *dev = video_drvdata(file); |
c19bec50 | 996 | const struct vivi_fmt *fmt; |
1e6dd65e | 997 | |
d891f475 MD |
998 | fmt = get_format(f); |
999 | if (!fmt) { | |
cd779254 | 1000 | dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n", |
d891f475 | 1001 | f->fmt.pix.pixelformat); |
cd779254 HV |
1002 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; |
1003 | fmt = get_format(f); | |
1e6dd65e MCC |
1004 | } |
1005 | ||
cd779254 | 1006 | f->fmt.pix.field = V4L2_FIELD_INTERLACED; |
730947bc HV |
1007 | v4l_bound_align_image(&f->fmt.pix.width, 48, MAX_WIDTH, 2, |
1008 | &f->fmt.pix.height, 32, MAX_HEIGHT, 0, 0); | |
1e6dd65e MCC |
1009 | f->fmt.pix.bytesperline = |
1010 | (f->fmt.pix.width * fmt->depth) >> 3; | |
1011 | f->fmt.pix.sizeimage = | |
1012 | f->fmt.pix.height * f->fmt.pix.bytesperline; | |
0a3a8a36 | 1013 | if (fmt->is_yuv) |
8c79eece HV |
1014 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; |
1015 | else | |
1016 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; | |
2f65f467 | 1017 | f->fmt.pix.priv = 0; |
1e6dd65e MCC |
1018 | return 0; |
1019 | } | |
1020 | ||
e164b58a MCC |
1021 | static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, |
1022 | struct v4l2_format *f) | |
1023 | { | |
730947bc | 1024 | struct vivi_dev *dev = video_drvdata(file); |
e007a325 | 1025 | struct vb2_queue *q = &dev->vb_vidq; |
e164b58a | 1026 | |
730947bc | 1027 | int ret = vidioc_try_fmt_vid_cap(file, priv, f); |
e164b58a MCC |
1028 | if (ret < 0) |
1029 | return ret; | |
1030 | ||
f2ba5a0b | 1031 | if (vb2_is_busy(q)) { |
730947bc | 1032 | dprintk(dev, 1, "%s device busy\n", __func__); |
e007a325 | 1033 | return -EBUSY; |
e164b58a MCC |
1034 | } |
1035 | ||
730947bc | 1036 | dev->fmt = get_format(f); |
3d51dca2 | 1037 | dev->pixelsize = dev->fmt->depth / 8; |
730947bc HV |
1038 | dev->width = f->fmt.pix.width; |
1039 | dev->height = f->fmt.pix.height; | |
e007a325 PO |
1040 | |
1041 | return 0; | |
1e6dd65e MCC |
1042 | } |
1043 | ||
77747f79 HV |
1044 | static int vidioc_enum_framesizes(struct file *file, void *fh, |
1045 | struct v4l2_frmsizeenum *fsize) | |
1046 | { | |
1047 | static const struct v4l2_frmsize_stepwise sizes = { | |
1048 | 48, MAX_WIDTH, 4, | |
1049 | 32, MAX_HEIGHT, 1 | |
1050 | }; | |
1051 | int i; | |
1052 | ||
1053 | if (fsize->index) | |
1054 | return -EINVAL; | |
1055 | for (i = 0; i < ARRAY_SIZE(formats); i++) | |
1056 | if (formats[i].fourcc == fsize->pixel_format) | |
1057 | break; | |
1058 | if (i == ARRAY_SIZE(formats)) | |
1059 | return -EINVAL; | |
1060 | fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; | |
1061 | fsize->stepwise = sizes; | |
1062 | return 0; | |
1063 | } | |
1064 | ||
c820cc45 | 1065 | /* only one input in this sample driver */ |
543323bc | 1066 | static int vidioc_enum_input(struct file *file, void *priv, |
c820cc45 MCC |
1067 | struct v4l2_input *inp) |
1068 | { | |
e164b58a | 1069 | if (inp->index >= NUM_INPUTS) |
c820cc45 | 1070 | return -EINVAL; |
1e6dd65e | 1071 | |
c820cc45 | 1072 | inp->type = V4L2_INPUT_TYPE_CAMERA; |
e164b58a | 1073 | sprintf(inp->name, "Camera %u", inp->index); |
730947bc | 1074 | return 0; |
c820cc45 | 1075 | } |
1e6dd65e | 1076 | |
543323bc | 1077 | static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) |
c820cc45 | 1078 | { |
730947bc | 1079 | struct vivi_dev *dev = video_drvdata(file); |
e164b58a MCC |
1080 | |
1081 | *i = dev->input; | |
730947bc | 1082 | return 0; |
c820cc45 | 1083 | } |
730947bc | 1084 | |
543323bc | 1085 | static int vidioc_s_input(struct file *file, void *priv, unsigned int i) |
c820cc45 | 1086 | { |
730947bc | 1087 | struct vivi_dev *dev = video_drvdata(file); |
e164b58a MCC |
1088 | |
1089 | if (i >= NUM_INPUTS) | |
c820cc45 | 1090 | return -EINVAL; |
1e6dd65e | 1091 | |
c7a52f8d HV |
1092 | if (i == dev->input) |
1093 | return 0; | |
1094 | ||
e164b58a | 1095 | dev->input = i; |
af2d68d1 HV |
1096 | /* |
1097 | * Modify the brightness range depending on the input. | |
1098 | * This makes it easy to use vivi to test if applications can | |
1099 | * handle control range modifications and is also how this is | |
1100 | * typically used in practice as different inputs may be hooked | |
1101 | * up to different receivers with different control ranges. | |
1102 | */ | |
1103 | v4l2_ctrl_modify_range(dev->brightness, | |
1104 | 128 * i, 255 + 128 * i, 1, 127 + 128 * i); | |
730947bc HV |
1105 | precalculate_bars(dev); |
1106 | precalculate_line(dev); | |
1107 | return 0; | |
c820cc45 | 1108 | } |
1e6dd65e | 1109 | |
39c1cb2b | 1110 | /* timeperframe is arbitrary and continuous */ |
fe0e990b KS |
1111 | static int vidioc_enum_frameintervals(struct file *file, void *priv, |
1112 | struct v4l2_frmivalenum *fival) | |
1113 | { | |
c19bec50 | 1114 | const struct vivi_fmt *fmt; |
fe0e990b KS |
1115 | |
1116 | if (fival->index) | |
1117 | return -EINVAL; | |
1118 | ||
1119 | fmt = __get_format(fival->pixel_format); | |
1120 | if (!fmt) | |
1121 | return -EINVAL; | |
1122 | ||
ba38acb1 HV |
1123 | /* check for valid width/height */ |
1124 | if (fival->width < 48 || fival->width > MAX_WIDTH || (fival->width & 3)) | |
1125 | return -EINVAL; | |
1126 | if (fival->height < 32 || fival->height > MAX_HEIGHT) | |
1127 | return -EINVAL; | |
fe0e990b KS |
1128 | |
1129 | fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS; | |
1130 | ||
39c1cb2b | 1131 | /* fill in stepwise (step=1.0 is required by V4L2 spec) */ |
fe0e990b KS |
1132 | fival->stepwise.min = tpf_min; |
1133 | fival->stepwise.max = tpf_max; | |
1134 | fival->stepwise.step = (struct v4l2_fract) {1, 1}; | |
1135 | ||
1136 | return 0; | |
1137 | } | |
1138 | ||
1139 | static int vidioc_g_parm(struct file *file, void *priv, | |
1140 | struct v4l2_streamparm *parm) | |
1141 | { | |
1142 | struct vivi_dev *dev = video_drvdata(file); | |
1143 | ||
1144 | if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
1145 | return -EINVAL; | |
1146 | ||
1147 | parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; | |
1148 | parm->parm.capture.timeperframe = dev->timeperframe; | |
1149 | parm->parm.capture.readbuffers = 1; | |
1150 | return 0; | |
1151 | } | |
1152 | ||
1153 | #define FRACT_CMP(a, OP, b) \ | |
1154 | ((u64)(a).numerator * (b).denominator OP (u64)(b).numerator * (a).denominator) | |
1155 | ||
1156 | static int vidioc_s_parm(struct file *file, void *priv, | |
1157 | struct v4l2_streamparm *parm) | |
1158 | { | |
1159 | struct vivi_dev *dev = video_drvdata(file); | |
1160 | struct v4l2_fract tpf; | |
1161 | ||
1162 | if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
1163 | return -EINVAL; | |
1164 | ||
1165 | tpf = parm->parm.capture.timeperframe; | |
1166 | ||
1167 | /* tpf: {*, 0} resets timing; clip to [min, max]*/ | |
1168 | tpf = tpf.denominator ? tpf : tpf_default; | |
1169 | tpf = FRACT_CMP(tpf, <, tpf_min) ? tpf_min : tpf; | |
1170 | tpf = FRACT_CMP(tpf, >, tpf_max) ? tpf_max : tpf; | |
1171 | ||
1172 | dev->timeperframe = tpf; | |
1173 | parm->parm.capture.timeperframe = tpf; | |
1174 | parm->parm.capture.readbuffers = 1; | |
1175 | return 0; | |
1176 | } | |
1177 | ||
730947bc | 1178 | /* --- controls ---------------------------------------------- */ |
1e6dd65e | 1179 | |
a1c894fb HV |
1180 | static int vivi_g_volatile_ctrl(struct v4l2_ctrl *ctrl) |
1181 | { | |
1182 | struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler); | |
1183 | ||
1184 | if (ctrl == dev->autogain) | |
1185 | dev->gain->val = jiffies & 0xff; | |
1186 | return 0; | |
1187 | } | |
1188 | ||
7e996afa | 1189 | static int vivi_s_ctrl(struct v4l2_ctrl *ctrl) |
c820cc45 | 1190 | { |
7e996afa | 1191 | struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler); |
1e6dd65e | 1192 | |
7088f4df HV |
1193 | switch (ctrl->id) { |
1194 | case V4L2_CID_ALPHA_COMPONENT: | |
1195 | dev->alpha_component = ctrl->val; | |
1196 | break; | |
1197 | default: | |
1198 | if (ctrl == dev->button) | |
1199 | dev->button_pressed = 30; | |
1200 | break; | |
1201 | } | |
7e996afa | 1202 | return 0; |
1e6dd65e MCC |
1203 | } |
1204 | ||
1205 | /* ------------------------------------------------------------------ | |
1206 | File operations for the device | |
1207 | ------------------------------------------------------------------*/ | |
1208 | ||
7e996afa | 1209 | static const struct v4l2_ctrl_ops vivi_ctrl_ops = { |
a1c894fb | 1210 | .g_volatile_ctrl = vivi_g_volatile_ctrl, |
7e996afa HV |
1211 | .s_ctrl = vivi_s_ctrl, |
1212 | }; | |
1213 | ||
1214 | #define VIVI_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000) | |
1215 | ||
1216 | static const struct v4l2_ctrl_config vivi_ctrl_button = { | |
1217 | .ops = &vivi_ctrl_ops, | |
1218 | .id = VIVI_CID_CUSTOM_BASE + 0, | |
1219 | .name = "Button", | |
1220 | .type = V4L2_CTRL_TYPE_BUTTON, | |
1221 | }; | |
1222 | ||
1223 | static const struct v4l2_ctrl_config vivi_ctrl_boolean = { | |
1224 | .ops = &vivi_ctrl_ops, | |
1225 | .id = VIVI_CID_CUSTOM_BASE + 1, | |
1226 | .name = "Boolean", | |
1227 | .type = V4L2_CTRL_TYPE_BOOLEAN, | |
1228 | .min = 0, | |
1229 | .max = 1, | |
1230 | .step = 1, | |
1231 | .def = 1, | |
1232 | }; | |
1233 | ||
1234 | static const struct v4l2_ctrl_config vivi_ctrl_int32 = { | |
1235 | .ops = &vivi_ctrl_ops, | |
1236 | .id = VIVI_CID_CUSTOM_BASE + 2, | |
1237 | .name = "Integer 32 Bits", | |
1238 | .type = V4L2_CTRL_TYPE_INTEGER, | |
5b283029 HV |
1239 | .min = 0x80000000, |
1240 | .max = 0x7fffffff, | |
7e996afa HV |
1241 | .step = 1, |
1242 | }; | |
1243 | ||
1244 | static const struct v4l2_ctrl_config vivi_ctrl_int64 = { | |
1245 | .ops = &vivi_ctrl_ops, | |
1246 | .id = VIVI_CID_CUSTOM_BASE + 3, | |
1247 | .name = "Integer 64 Bits", | |
1248 | .type = V4L2_CTRL_TYPE_INTEGER64, | |
1249 | }; | |
1250 | ||
1251 | static const char * const vivi_ctrl_menu_strings[] = { | |
1252 | "Menu Item 0 (Skipped)", | |
1253 | "Menu Item 1", | |
1254 | "Menu Item 2 (Skipped)", | |
1255 | "Menu Item 3", | |
1256 | "Menu Item 4", | |
1257 | "Menu Item 5 (Skipped)", | |
1258 | NULL, | |
1259 | }; | |
1260 | ||
1261 | static const struct v4l2_ctrl_config vivi_ctrl_menu = { | |
1262 | .ops = &vivi_ctrl_ops, | |
1263 | .id = VIVI_CID_CUSTOM_BASE + 4, | |
1264 | .name = "Menu", | |
1265 | .type = V4L2_CTRL_TYPE_MENU, | |
1266 | .min = 1, | |
1267 | .max = 4, | |
1268 | .def = 3, | |
1269 | .menu_skip_mask = 0x04, | |
1270 | .qmenu = vivi_ctrl_menu_strings, | |
1271 | }; | |
1272 | ||
1273 | static const struct v4l2_ctrl_config vivi_ctrl_string = { | |
1274 | .ops = &vivi_ctrl_ops, | |
1275 | .id = VIVI_CID_CUSTOM_BASE + 5, | |
1276 | .name = "String", | |
1277 | .type = V4L2_CTRL_TYPE_STRING, | |
1278 | .min = 2, | |
1279 | .max = 4, | |
1280 | .step = 1, | |
1281 | }; | |
1282 | ||
b6d17a56 HV |
1283 | static const struct v4l2_ctrl_config vivi_ctrl_bitmask = { |
1284 | .ops = &vivi_ctrl_ops, | |
1285 | .id = VIVI_CID_CUSTOM_BASE + 6, | |
1286 | .name = "Bitmask", | |
1287 | .type = V4L2_CTRL_TYPE_BITMASK, | |
1288 | .def = 0x80002000, | |
1289 | .min = 0, | |
1290 | .max = 0x80402010, | |
1291 | .step = 0, | |
1292 | }; | |
1293 | ||
c520331a SA |
1294 | static const s64 vivi_ctrl_int_menu_values[] = { |
1295 | 1, 1, 2, 3, 5, 8, 13, 21, 42, | |
1296 | }; | |
1297 | ||
1298 | static const struct v4l2_ctrl_config vivi_ctrl_int_menu = { | |
1299 | .ops = &vivi_ctrl_ops, | |
1300 | .id = VIVI_CID_CUSTOM_BASE + 7, | |
1301 | .name = "Integer menu", | |
1302 | .type = V4L2_CTRL_TYPE_INTEGER_MENU, | |
1303 | .min = 1, | |
1304 | .max = 8, | |
1305 | .def = 4, | |
1306 | .menu_skip_mask = 0x02, | |
1307 | .qmenu_int = vivi_ctrl_int_menu_values, | |
1308 | }; | |
1309 | ||
bec43661 | 1310 | static const struct v4l2_file_operations vivi_fops = { |
1e6dd65e | 1311 | .owner = THIS_MODULE, |
c7a52f8d | 1312 | .open = v4l2_fh_open, |
f2ba5a0b HV |
1313 | .release = vb2_fop_release, |
1314 | .read = vb2_fop_read, | |
1315 | .poll = vb2_fop_poll, | |
fedc6c81 | 1316 | .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ |
f2ba5a0b | 1317 | .mmap = vb2_fop_mmap, |
1e6dd65e MCC |
1318 | }; |
1319 | ||
a399810c | 1320 | static const struct v4l2_ioctl_ops vivi_ioctl_ops = { |
c820cc45 | 1321 | .vidioc_querycap = vidioc_querycap, |
78b526a4 HV |
1322 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, |
1323 | .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, | |
1324 | .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, | |
1325 | .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, | |
77747f79 | 1326 | .vidioc_enum_framesizes = vidioc_enum_framesizes, |
f2ba5a0b | 1327 | .vidioc_reqbufs = vb2_ioctl_reqbufs, |
2e90c6c3 HV |
1328 | .vidioc_create_bufs = vb2_ioctl_create_bufs, |
1329 | .vidioc_prepare_buf = vb2_ioctl_prepare_buf, | |
f2ba5a0b HV |
1330 | .vidioc_querybuf = vb2_ioctl_querybuf, |
1331 | .vidioc_qbuf = vb2_ioctl_qbuf, | |
1332 | .vidioc_dqbuf = vb2_ioctl_dqbuf, | |
c820cc45 MCC |
1333 | .vidioc_enum_input = vidioc_enum_input, |
1334 | .vidioc_g_input = vidioc_g_input, | |
1335 | .vidioc_s_input = vidioc_s_input, | |
fe0e990b KS |
1336 | .vidioc_enum_frameintervals = vidioc_enum_frameintervals, |
1337 | .vidioc_g_parm = vidioc_g_parm, | |
1338 | .vidioc_s_parm = vidioc_s_parm, | |
f2ba5a0b HV |
1339 | .vidioc_streamon = vb2_ioctl_streamon, |
1340 | .vidioc_streamoff = vb2_ioctl_streamoff, | |
e2ecb257 | 1341 | .vidioc_log_status = v4l2_ctrl_log_status, |
6d6604fa | 1342 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, |
c7a52f8d | 1343 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, |
a399810c HV |
1344 | }; |
1345 | ||
c19bec50 | 1346 | static const struct video_device vivi_template = { |
a399810c | 1347 | .name = "vivi", |
a399810c HV |
1348 | .fops = &vivi_fops, |
1349 | .ioctl_ops = &vivi_ioctl_ops, | |
70bd97ae | 1350 | .release = video_device_release_empty, |
1e6dd65e | 1351 | }; |
5ab6c9af | 1352 | |
c820cc45 | 1353 | /* ----------------------------------------------------------------- |
1e6dd65e MCC |
1354 | Initialization and module stuff |
1355 | ------------------------------------------------------------------*/ | |
1356 | ||
5ab6c9af HV |
1357 | static int vivi_release(void) |
1358 | { | |
1359 | struct vivi_dev *dev; | |
1360 | struct list_head *list; | |
980d4f17 | 1361 | |
5ab6c9af HV |
1362 | while (!list_empty(&vivi_devlist)) { |
1363 | list = vivi_devlist.next; | |
1364 | list_del(list); | |
1365 | dev = list_entry(list, struct vivi_dev, vivi_devlist); | |
1366 | ||
38c7c036 | 1367 | v4l2_info(&dev->v4l2_dev, "unregistering %s\n", |
70bd97ae HV |
1368 | video_device_node_name(&dev->vdev)); |
1369 | video_unregister_device(&dev->vdev); | |
5ab6c9af | 1370 | v4l2_device_unregister(&dev->v4l2_dev); |
7e996afa | 1371 | v4l2_ctrl_handler_free(&dev->ctrl_handler); |
5ab6c9af HV |
1372 | kfree(dev); |
1373 | } | |
1374 | ||
1375 | return 0; | |
1376 | } | |
1377 | ||
c41ee24b | 1378 | static int __init vivi_create_instance(int inst) |
1e6dd65e | 1379 | { |
1e6dd65e | 1380 | struct vivi_dev *dev; |
f905c442 | 1381 | struct video_device *vfd; |
7e996afa | 1382 | struct v4l2_ctrl_handler *hdl; |
e007a325 | 1383 | struct vb2_queue *q; |
730947bc | 1384 | int ret; |
1e6dd65e | 1385 | |
5ab6c9af HV |
1386 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
1387 | if (!dev) | |
1388 | return -ENOMEM; | |
980d4f17 | 1389 | |
5ab6c9af | 1390 | snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), |
c41ee24b | 1391 | "%s-%03d", VIVI_MODULE_NAME, inst); |
5ab6c9af HV |
1392 | ret = v4l2_device_register(NULL, &dev->v4l2_dev); |
1393 | if (ret) | |
1394 | goto free_dev; | |
1e6dd65e | 1395 | |
730947bc | 1396 | dev->fmt = &formats[0]; |
fe0e990b | 1397 | dev->timeperframe = tpf_default; |
730947bc HV |
1398 | dev->width = 640; |
1399 | dev->height = 480; | |
3d51dca2 | 1400 | dev->pixelsize = dev->fmt->depth / 8; |
7e996afa HV |
1401 | hdl = &dev->ctrl_handler; |
1402 | v4l2_ctrl_handler_init(hdl, 11); | |
1403 | dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, | |
1404 | V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200); | |
1405 | dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, | |
1406 | V4L2_CID_BRIGHTNESS, 0, 255, 1, 127); | |
1407 | dev->contrast = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, | |
1408 | V4L2_CID_CONTRAST, 0, 255, 1, 16); | |
1409 | dev->saturation = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, | |
1410 | V4L2_CID_SATURATION, 0, 255, 1, 127); | |
1411 | dev->hue = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, | |
1412 | V4L2_CID_HUE, -128, 127, 1, 0); | |
a1c894fb HV |
1413 | dev->autogain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, |
1414 | V4L2_CID_AUTOGAIN, 0, 1, 1, 1); | |
1415 | dev->gain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, | |
1416 | V4L2_CID_GAIN, 0, 255, 1, 100); | |
7088f4df HV |
1417 | dev->alpha = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, |
1418 | V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 0); | |
7e996afa HV |
1419 | dev->button = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_button, NULL); |
1420 | dev->int32 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int32, NULL); | |
1421 | dev->int64 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int64, NULL); | |
1422 | dev->boolean = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_boolean, NULL); | |
1423 | dev->menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_menu, NULL); | |
1424 | dev->string = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_string, NULL); | |
b6d17a56 | 1425 | dev->bitmask = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_bitmask, NULL); |
c520331a | 1426 | dev->int_menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int_menu, NULL); |
7e996afa HV |
1427 | if (hdl->error) { |
1428 | ret = hdl->error; | |
1429 | goto unreg_dev; | |
1430 | } | |
a1c894fb | 1431 | v4l2_ctrl_auto_cluster(2, &dev->autogain, 0, true); |
7e996afa | 1432 | dev->v4l2_dev.ctrl_handler = hdl; |
730947bc | 1433 | |
fedc6c81 HV |
1434 | /* initialize locks */ |
1435 | spin_lock_init(&dev->slock); | |
fedc6c81 | 1436 | |
e007a325 PO |
1437 | /* initialize queue */ |
1438 | q = &dev->vb_vidq; | |
e007a325 | 1439 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
a626f0ac | 1440 | q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; |
e007a325 PO |
1441 | q->drv_priv = dev; |
1442 | q->buf_struct_size = sizeof(struct vivi_buffer); | |
1443 | q->ops = &vivi_video_qops; | |
1444 | q->mem_ops = &vb2_vmalloc_memops; | |
ade48681 | 1445 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
e007a325 | 1446 | |
4195ec7a EG |
1447 | ret = vb2_queue_init(q); |
1448 | if (ret) | |
1449 | goto unreg_dev; | |
e007a325 PO |
1450 | |
1451 | mutex_init(&dev->mutex); | |
730947bc | 1452 | |
5ab6c9af HV |
1453 | /* init video dma queues */ |
1454 | INIT_LIST_HEAD(&dev->vidq.active); | |
1455 | init_waitqueue_head(&dev->vidq.wq); | |
1e6dd65e | 1456 | |
70bd97ae | 1457 | vfd = &dev->vdev; |
5ab6c9af | 1458 | *vfd = vivi_template; |
c285addb | 1459 | vfd->debug = debug; |
730947bc | 1460 | vfd->v4l2_dev = &dev->v4l2_dev; |
f2ba5a0b | 1461 | vfd->queue = q; |
b1a873a3 | 1462 | set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); |
e007a325 PO |
1463 | |
1464 | /* | |
1465 | * Provide a mutex to v4l2 core. It will be used to protect | |
1466 | * all fops and v4l2 ioctls. | |
1467 | */ | |
fedc6c81 | 1468 | vfd->lock = &dev->mutex; |
70bd97ae | 1469 | video_set_drvdata(vfd, dev); |
55712ff7 | 1470 | |
5ab6c9af HV |
1471 | ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); |
1472 | if (ret < 0) | |
70bd97ae | 1473 | goto unreg_dev; |
980d4f17 | 1474 | |
5ab6c9af HV |
1475 | /* Now that everything is fine, let's add it to device list */ |
1476 | list_add_tail(&dev->vivi_devlist, &vivi_devlist); | |
980d4f17 | 1477 | |
38c7c036 LP |
1478 | v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n", |
1479 | video_device_node_name(vfd)); | |
5ab6c9af HV |
1480 | return 0; |
1481 | ||
5ab6c9af | 1482 | unreg_dev: |
7e996afa | 1483 | v4l2_ctrl_handler_free(hdl); |
5ab6c9af HV |
1484 | v4l2_device_unregister(&dev->v4l2_dev); |
1485 | free_dev: | |
1486 | kfree(dev); | |
1487 | return ret; | |
1488 | } | |
f905c442 | 1489 | |
5ab6c9af HV |
1490 | /* This routine allocates from 1 to n_devs virtual drivers. |
1491 | ||
1492 | The real maximum number of virtual drivers will depend on how many drivers | |
1493 | will succeed. This is limited to the maximum number of devices that | |
1494 | videodev supports, which is equal to VIDEO_NUM_DEVICES. | |
1495 | */ | |
1496 | static int __init vivi_init(void) | |
1497 | { | |
730947bc | 1498 | const struct font_desc *font = find_font("VGA8x16"); |
9185cbfc | 1499 | int ret = 0, i; |
5ab6c9af | 1500 | |
730947bc HV |
1501 | if (font == NULL) { |
1502 | printk(KERN_ERR "vivi: could not find font\n"); | |
1503 | return -ENODEV; | |
1504 | } | |
1505 | font8x16 = font->data; | |
1506 | ||
5ab6c9af HV |
1507 | if (n_devs <= 0) |
1508 | n_devs = 1; | |
1509 | ||
1510 | for (i = 0; i < n_devs; i++) { | |
1511 | ret = vivi_create_instance(i); | |
1512 | if (ret) { | |
1513 | /* If some instantiations succeeded, keep driver */ | |
1514 | if (i) | |
1515 | ret = 0; | |
1516 | break; | |
1517 | } | |
55712ff7 | 1518 | } |
f905c442 | 1519 | |
55712ff7 | 1520 | if (ret < 0) { |
730947bc | 1521 | printk(KERN_ERR "vivi: error %d while loading driver\n", ret); |
5ab6c9af HV |
1522 | return ret; |
1523 | } | |
1524 | ||
1525 | printk(KERN_INFO "Video Technology Magazine Virtual Video " | |
1990d50b MCC |
1526 | "Capture Board ver %s successfully loaded.\n", |
1527 | VIVI_VERSION); | |
980d4f17 | 1528 | |
5ab6c9af HV |
1529 | /* n_devs will reflect the actual number of allocated devices */ |
1530 | n_devs = i; | |
980d4f17 | 1531 | |
1e6dd65e MCC |
1532 | return ret; |
1533 | } | |
1534 | ||
1535 | static void __exit vivi_exit(void) | |
1536 | { | |
55712ff7 | 1537 | vivi_release(); |
1e6dd65e MCC |
1538 | } |
1539 | ||
1540 | module_init(vivi_init); | |
1541 | module_exit(vivi_exit); |