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