]>
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 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the BSD Licence, GNU General Public License | |
12 | * as published by the Free Software Foundation; either version 2 of the | |
13 | * License, or (at your option) any later version | |
14 | */ | |
15 | #include <linux/module.h> | |
1e6dd65e | 16 | #include <linux/errno.h> |
1e6dd65e | 17 | #include <linux/kernel.h> |
1e6dd65e MCC |
18 | #include <linux/init.h> |
19 | #include <linux/sched.h> | |
6b46c397 | 20 | #include <linux/slab.h> |
730947bc | 21 | #include <linux/font.h> |
1e6dd65e | 22 | #include <linux/version.h> |
51b54029 | 23 | #include <linux/mutex.h> |
1e6dd65e | 24 | #include <linux/videodev2.h> |
1e6dd65e | 25 | #include <linux/kthread.h> |
730947bc | 26 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) |
7dfb7103 | 27 | #include <linux/freezer.h> |
730947bc | 28 | #endif |
5ab6c9af HV |
29 | #include <media/videobuf-vmalloc.h> |
30 | #include <media/v4l2-device.h> | |
31 | #include <media/v4l2-ioctl.h> | |
730947bc | 32 | #include <media/v4l2-common.h> |
1e6dd65e | 33 | |
584ce48d | 34 | #define VIVI_MODULE_NAME "vivi" |
745271ae | 35 | |
1e6dd65e MCC |
36 | /* Wake up at about 30 fps */ |
37 | #define WAKE_NUMERATOR 30 | |
38 | #define WAKE_DENOMINATOR 1001 | |
39 | #define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ | |
40 | ||
730947bc HV |
41 | #define MAX_WIDTH 1920 |
42 | #define MAX_HEIGHT 1200 | |
43 | ||
1e6dd65e | 44 | #define VIVI_MAJOR_VERSION 0 |
730947bc | 45 | #define VIVI_MINOR_VERSION 7 |
1e6dd65e | 46 | #define VIVI_RELEASE 0 |
543323bc MCC |
47 | #define VIVI_VERSION \ |
48 | KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE) | |
1e6dd65e | 49 | |
5ab6c9af HV |
50 | MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board"); |
51 | MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol"); | |
52 | MODULE_LICENSE("Dual BSD/GPL"); | |
53 | ||
54 | static unsigned video_nr = -1; | |
55 | module_param(video_nr, uint, 0644); | |
56 | MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect"); | |
57 | ||
58 | static unsigned n_devs = 1; | |
59 | module_param(n_devs, uint, 0644); | |
60 | MODULE_PARM_DESC(n_devs, "number of video devices to create"); | |
61 | ||
62 | static unsigned debug; | |
63 | module_param(debug, uint, 0644); | |
64 | MODULE_PARM_DESC(debug, "activates debug info"); | |
65 | ||
66 | static unsigned int vid_limit = 16; | |
67 | module_param(vid_limit, uint, 0644); | |
68 | MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); | |
69 | ||
730947bc HV |
70 | /* Global font descriptor */ |
71 | static const u8 *font8x16; | |
1e6dd65e | 72 | |
5ab6c9af HV |
73 | #define dprintk(dev, level, fmt, arg...) \ |
74 | v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg) | |
1e6dd65e MCC |
75 | |
76 | /* ------------------------------------------------------------------ | |
77 | Basic structures | |
78 | ------------------------------------------------------------------*/ | |
79 | ||
80 | struct vivi_fmt { | |
81 | char *name; | |
82 | u32 fourcc; /* v4l2 format id */ | |
83 | int depth; | |
84 | }; | |
85 | ||
d891f475 MD |
86 | static struct vivi_fmt formats[] = { |
87 | { | |
88 | .name = "4:2:2, packed, YUYV", | |
89 | .fourcc = V4L2_PIX_FMT_YUYV, | |
90 | .depth = 16, | |
91 | }, | |
fca36bab MD |
92 | { |
93 | .name = "4:2:2, packed, UYVY", | |
94 | .fourcc = V4L2_PIX_FMT_UYVY, | |
95 | .depth = 16, | |
96 | }, | |
aeadb5d4 MD |
97 | { |
98 | .name = "RGB565 (LE)", | |
99 | .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ | |
100 | .depth = 16, | |
101 | }, | |
102 | { | |
103 | .name = "RGB565 (BE)", | |
104 | .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ | |
105 | .depth = 16, | |
106 | }, | |
def52393 MD |
107 | { |
108 | .name = "RGB555 (LE)", | |
109 | .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */ | |
110 | .depth = 16, | |
111 | }, | |
112 | { | |
113 | .name = "RGB555 (BE)", | |
114 | .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */ | |
115 | .depth = 16, | |
116 | }, | |
1e6dd65e MCC |
117 | }; |
118 | ||
d891f475 MD |
119 | static struct vivi_fmt *get_format(struct v4l2_format *f) |
120 | { | |
121 | struct vivi_fmt *fmt; | |
122 | unsigned int k; | |
123 | ||
124 | for (k = 0; k < ARRAY_SIZE(formats); k++) { | |
125 | fmt = &formats[k]; | |
126 | if (fmt->fourcc == f->fmt.pix.pixelformat) | |
127 | break; | |
128 | } | |
129 | ||
130 | if (k == ARRAY_SIZE(formats)) | |
131 | return NULL; | |
132 | ||
133 | return &formats[k]; | |
134 | } | |
135 | ||
1e6dd65e MCC |
136 | struct sg_to_addr { |
137 | int pos; | |
138 | struct scatterlist *sg; | |
139 | }; | |
140 | ||
141 | /* buffer for one video frame */ | |
142 | struct vivi_buffer { | |
143 | /* common v4l buffer stuff -- must be first */ | |
144 | struct videobuf_buffer vb; | |
145 | ||
146 | struct vivi_fmt *fmt; | |
1e6dd65e MCC |
147 | }; |
148 | ||
149 | struct vivi_dmaqueue { | |
150 | struct list_head active; | |
1e6dd65e MCC |
151 | |
152 | /* thread for generating video stream*/ | |
153 | struct task_struct *kthread; | |
154 | wait_queue_head_t wq; | |
155 | /* Counters to control fps rate */ | |
156 | int frame; | |
157 | int ini_jiffies; | |
158 | }; | |
159 | ||
160 | static LIST_HEAD(vivi_devlist); | |
161 | ||
162 | struct vivi_dev { | |
163 | struct list_head vivi_devlist; | |
5ab6c9af | 164 | struct v4l2_device v4l2_dev; |
1e6dd65e | 165 | |
730947bc HV |
166 | /* controls */ |
167 | int brightness; | |
168 | int contrast; | |
169 | int saturation; | |
170 | int hue; | |
171 | int volume; | |
172 | ||
55862ac9 | 173 | spinlock_t slock; |
aa9dbac4 | 174 | struct mutex mutex; |
1e6dd65e | 175 | |
1e6dd65e | 176 | /* various device info */ |
f905c442 | 177 | struct video_device *vfd; |
1e6dd65e MCC |
178 | |
179 | struct vivi_dmaqueue vidq; | |
180 | ||
181 | /* Several counters */ | |
730947bc | 182 | unsigned ms; |
dfd8c04e | 183 | unsigned long jiffies; |
025341d4 MCC |
184 | |
185 | int mv_count; /* Controls bars movement */ | |
e164b58a MCC |
186 | |
187 | /* Input Number */ | |
188 | int input; | |
c41ee24b | 189 | |
1e6dd65e MCC |
190 | /* video capture */ |
191 | struct vivi_fmt *fmt; | |
543323bc | 192 | unsigned int width, height; |
1e6dd65e MCC |
193 | struct videobuf_queue vb_vidq; |
194 | ||
730947bc HV |
195 | unsigned long generating; |
196 | u8 bars[9][3]; | |
197 | u8 line[MAX_WIDTH * 4]; | |
1e6dd65e MCC |
198 | }; |
199 | ||
200 | /* ------------------------------------------------------------------ | |
201 | DMA and thread functions | |
202 | ------------------------------------------------------------------*/ | |
203 | ||
204 | /* Bars and Colors should match positions */ | |
205 | ||
206 | enum colors { | |
207 | WHITE, | |
730947bc | 208 | AMBER, |
1e6dd65e MCC |
209 | CYAN, |
210 | GREEN, | |
211 | MAGENTA, | |
212 | RED, | |
543323bc MCC |
213 | BLUE, |
214 | BLACK, | |
730947bc | 215 | TEXT_BLACK, |
1e6dd65e MCC |
216 | }; |
217 | ||
730947bc | 218 | /* R G B */ |
e164b58a | 219 | #define COLOR_WHITE {204, 204, 204} |
730947bc HV |
220 | #define COLOR_AMBER {208, 208, 0} |
221 | #define COLOR_CYAN { 0, 206, 206} | |
e164b58a MCC |
222 | #define COLOR_GREEN { 0, 239, 0} |
223 | #define COLOR_MAGENTA {239, 0, 239} | |
224 | #define COLOR_RED {205, 0, 0} | |
225 | #define COLOR_BLUE { 0, 0, 255} | |
226 | #define COLOR_BLACK { 0, 0, 0} | |
227 | ||
228 | struct bar_std { | |
730947bc | 229 | u8 bar[9][3]; |
e164b58a MCC |
230 | }; |
231 | ||
232 | /* Maximum number of bars are 10 - otherwise, the input print code | |
233 | should be modified */ | |
234 | static struct bar_std bars[] = { | |
235 | { /* Standard ITU-R color bar sequence */ | |
730947bc HV |
236 | { COLOR_WHITE, COLOR_AMBER, COLOR_CYAN, COLOR_GREEN, |
237 | COLOR_MAGENTA, COLOR_RED, COLOR_BLUE, COLOR_BLACK, COLOR_BLACK } | |
e164b58a | 238 | }, { |
730947bc HV |
239 | { COLOR_WHITE, COLOR_AMBER, COLOR_BLACK, COLOR_WHITE, |
240 | COLOR_AMBER, COLOR_BLACK, COLOR_WHITE, COLOR_AMBER, COLOR_BLACK } | |
e164b58a | 241 | }, { |
730947bc HV |
242 | { COLOR_WHITE, COLOR_CYAN, COLOR_BLACK, COLOR_WHITE, |
243 | COLOR_CYAN, COLOR_BLACK, COLOR_WHITE, COLOR_CYAN, COLOR_BLACK } | |
e164b58a | 244 | }, { |
730947bc HV |
245 | { COLOR_WHITE, COLOR_GREEN, COLOR_BLACK, COLOR_WHITE, |
246 | COLOR_GREEN, COLOR_BLACK, COLOR_WHITE, COLOR_GREEN, COLOR_BLACK } | |
e164b58a | 247 | }, |
1e6dd65e MCC |
248 | }; |
249 | ||
e164b58a MCC |
250 | #define NUM_INPUTS ARRAY_SIZE(bars) |
251 | ||
543323bc MCC |
252 | #define TO_Y(r, g, b) \ |
253 | (((16829 * r + 33039 * g + 6416 * b + 32768) >> 16) + 16) | |
1e6dd65e | 254 | /* RGB to V(Cr) Color transform */ |
543323bc MCC |
255 | #define TO_V(r, g, b) \ |
256 | (((28784 * r - 24103 * g - 4681 * b + 32768) >> 16) + 128) | |
1e6dd65e | 257 | /* RGB to U(Cb) Color transform */ |
543323bc MCC |
258 | #define TO_U(r, g, b) \ |
259 | (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128) | |
1e6dd65e | 260 | |
c285addb | 261 | /* precalculate color bar values to speed up rendering */ |
730947bc | 262 | static void precalculate_bars(struct vivi_dev *dev) |
c285addb | 263 | { |
730947bc | 264 | u8 r, g, b; |
c285addb MCC |
265 | int k, is_yuv; |
266 | ||
730947bc HV |
267 | for (k = 0; k < 9; k++) { |
268 | r = bars[dev->input].bar[k][0]; | |
269 | g = bars[dev->input].bar[k][1]; | |
270 | b = bars[dev->input].bar[k][2]; | |
c285addb MCC |
271 | is_yuv = 0; |
272 | ||
730947bc | 273 | switch (dev->fmt->fourcc) { |
c285addb MCC |
274 | case V4L2_PIX_FMT_YUYV: |
275 | case V4L2_PIX_FMT_UYVY: | |
276 | is_yuv = 1; | |
277 | break; | |
278 | case V4L2_PIX_FMT_RGB565: | |
279 | case V4L2_PIX_FMT_RGB565X: | |
280 | r >>= 3; | |
281 | g >>= 2; | |
282 | b >>= 3; | |
283 | break; | |
284 | case V4L2_PIX_FMT_RGB555: | |
285 | case V4L2_PIX_FMT_RGB555X: | |
286 | r >>= 3; | |
287 | g >>= 3; | |
288 | b >>= 3; | |
289 | break; | |
290 | } | |
291 | ||
292 | if (is_yuv) { | |
730947bc HV |
293 | dev->bars[k][0] = TO_Y(r, g, b); /* Luma */ |
294 | dev->bars[k][1] = TO_U(r, g, b); /* Cb */ | |
295 | dev->bars[k][2] = TO_V(r, g, b); /* Cr */ | |
c285addb | 296 | } else { |
730947bc HV |
297 | dev->bars[k][0] = r; |
298 | dev->bars[k][1] = g; | |
299 | dev->bars[k][2] = b; | |
c285addb MCC |
300 | } |
301 | } | |
c285addb MCC |
302 | } |
303 | ||
e164b58a MCC |
304 | #define TSTAMP_MIN_Y 24 |
305 | #define TSTAMP_MAX_Y (TSTAMP_MIN_Y + 15) | |
306 | #define TSTAMP_INPUT_X 10 | |
307 | #define TSTAMP_MIN_X (54 + TSTAMP_INPUT_X) | |
1e6dd65e | 308 | |
730947bc | 309 | static void gen_twopix(struct vivi_dev *dev, u8 *buf, int colorpos) |
74d7c5af | 310 | { |
730947bc | 311 | u8 r_y, g_u, b_v; |
74d7c5af | 312 | int color; |
730947bc | 313 | u8 *p; |
74d7c5af | 314 | |
730947bc HV |
315 | r_y = dev->bars[colorpos][0]; /* R or precalculated Y */ |
316 | g_u = dev->bars[colorpos][1]; /* G or precalculated U */ | |
317 | b_v = dev->bars[colorpos][2]; /* B or precalculated V */ | |
74d7c5af MD |
318 | |
319 | for (color = 0; color < 4; color++) { | |
320 | p = buf + color; | |
321 | ||
730947bc | 322 | switch (dev->fmt->fourcc) { |
d891f475 MD |
323 | case V4L2_PIX_FMT_YUYV: |
324 | switch (color) { | |
325 | case 0: | |
326 | case 2: | |
327 | *p = r_y; | |
328 | break; | |
329 | case 1: | |
330 | *p = g_u; | |
331 | break; | |
332 | case 3: | |
333 | *p = b_v; | |
334 | break; | |
335 | } | |
74d7c5af | 336 | break; |
fca36bab MD |
337 | case V4L2_PIX_FMT_UYVY: |
338 | switch (color) { | |
339 | case 1: | |
340 | case 3: | |
341 | *p = r_y; | |
342 | break; | |
343 | case 0: | |
344 | *p = g_u; | |
345 | break; | |
346 | case 2: | |
347 | *p = b_v; | |
348 | break; | |
349 | } | |
350 | break; | |
aeadb5d4 MD |
351 | case V4L2_PIX_FMT_RGB565: |
352 | switch (color) { | |
353 | case 0: | |
354 | case 2: | |
355 | *p = (g_u << 5) | b_v; | |
356 | break; | |
357 | case 1: | |
358 | case 3: | |
359 | *p = (r_y << 3) | (g_u >> 3); | |
360 | break; | |
361 | } | |
362 | break; | |
363 | case V4L2_PIX_FMT_RGB565X: | |
364 | switch (color) { | |
365 | case 0: | |
366 | case 2: | |
367 | *p = (r_y << 3) | (g_u >> 3); | |
368 | break; | |
369 | case 1: | |
370 | case 3: | |
371 | *p = (g_u << 5) | b_v; | |
372 | break; | |
373 | } | |
374 | break; | |
def52393 MD |
375 | case V4L2_PIX_FMT_RGB555: |
376 | switch (color) { | |
377 | case 0: | |
378 | case 2: | |
379 | *p = (g_u << 5) | b_v; | |
380 | break; | |
381 | case 1: | |
382 | case 3: | |
383 | *p = (r_y << 2) | (g_u >> 3); | |
384 | break; | |
385 | } | |
386 | break; | |
387 | case V4L2_PIX_FMT_RGB555X: | |
388 | switch (color) { | |
389 | case 0: | |
390 | case 2: | |
391 | *p = (r_y << 2) | (g_u >> 3); | |
392 | break; | |
393 | case 1: | |
394 | case 3: | |
395 | *p = (g_u << 5) | b_v; | |
396 | break; | |
397 | } | |
398 | break; | |
74d7c5af MD |
399 | } |
400 | } | |
401 | } | |
402 | ||
730947bc | 403 | static void precalculate_line(struct vivi_dev *dev) |
1e6dd65e | 404 | { |
730947bc | 405 | int w; |
1e6dd65e | 406 | |
730947bc HV |
407 | for (w = 0; w < dev->width * 2; w += 2) { |
408 | int colorpos = (w / (dev->width / 8) % 8); | |
74d7c5af | 409 | |
730947bc | 410 | gen_twopix(dev, dev->line + w * 2, colorpos); |
1e6dd65e | 411 | } |
730947bc | 412 | } |
1e6dd65e | 413 | |
730947bc HV |
414 | static void gen_text(struct vivi_dev *dev, char *basep, |
415 | int y, int x, char *text) | |
416 | { | |
417 | int line; | |
e164b58a | 418 | |
730947bc HV |
419 | /* Checks if it is possible to show string */ |
420 | if (y + 16 >= dev->height || x + strlen(text) * 8 >= dev->width) | |
421 | return; | |
1e6dd65e MCC |
422 | |
423 | /* Print stream time */ | |
730947bc HV |
424 | for (line = y; line < y + 16; line++) { |
425 | int j = 0; | |
426 | char *pos = basep + line * dev->width * 2 + x * 2; | |
427 | char *s; | |
428 | ||
429 | for (s = text; *s; s++) { | |
430 | u8 chr = font8x16[*s * 16 + line - y]; | |
431 | int i; | |
432 | ||
433 | for (i = 0; i < 7; i++, j++) { | |
74d7c5af | 434 | /* Draw white font on black background */ |
730947bc HV |
435 | if (chr & (1 << (7 - i))) |
436 | gen_twopix(dev, pos + j * 2, WHITE); | |
74d7c5af | 437 | else |
730947bc | 438 | gen_twopix(dev, pos + j * 2, TEXT_BLACK); |
1e6dd65e MCC |
439 | } |
440 | } | |
441 | } | |
1e6dd65e | 442 | } |
78718e5d | 443 | |
730947bc | 444 | static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf) |
1e6dd65e | 445 | { |
730947bc HV |
446 | int hmax = buf->vb.height; |
447 | int wmax = buf->vb.width; | |
1e6dd65e | 448 | struct timeval ts; |
543323bc | 449 | void *vbuf = videobuf_to_vmalloc(&buf->vb); |
730947bc HV |
450 | unsigned ms; |
451 | char str[100]; | |
452 | int h, line = 1; | |
b50e7fe9 | 453 | |
5c554e6b | 454 | if (!vbuf) |
5a037706 | 455 | return; |
1e6dd65e | 456 | |
730947bc HV |
457 | for (h = 0; h < hmax; h++) |
458 | memcpy(vbuf + h * wmax * 2, dev->line + (dev->mv_count % wmax) * 2, wmax * 2); | |
5a037706 | 459 | |
1e6dd65e MCC |
460 | /* Updates stream time */ |
461 | ||
730947bc | 462 | dev->ms += jiffies_to_msecs(jiffies - dev->jiffies); |
543323bc | 463 | dev->jiffies = jiffies; |
730947bc HV |
464 | ms = dev->ms; |
465 | snprintf(str, sizeof(str), " %02d:%02d:%02d:%03d ", | |
466 | (ms / (60 * 60 * 1000)) % 24, | |
467 | (ms / (60 * 1000)) % 60, | |
468 | (ms / 1000) % 60, | |
469 | ms % 1000); | |
470 | gen_text(dev, vbuf, line++ * 16, 16, str); | |
471 | snprintf(str, sizeof(str), " %dx%d, input %d ", | |
472 | dev->width, dev->height, dev->input); | |
473 | gen_text(dev, vbuf, line++ * 16, 16, str); | |
474 | ||
475 | snprintf(str, sizeof(str), " brightness %3d, contrast %3d, saturation %3d, hue %d ", | |
476 | dev->brightness, | |
477 | dev->contrast, | |
478 | dev->saturation, | |
479 | dev->hue); | |
480 | gen_text(dev, vbuf, line++ * 16, 16, str); | |
481 | snprintf(str, sizeof(str), " volume %3d ", dev->volume); | |
482 | gen_text(dev, vbuf, line++ * 16, 16, str); | |
483 | ||
484 | dev->mv_count += 2; | |
1e6dd65e MCC |
485 | |
486 | /* Advice that buffer was filled */ | |
1e6dd65e MCC |
487 | buf->vb.field_count++; |
488 | do_gettimeofday(&ts); | |
489 | buf->vb.ts = ts; | |
78718e5d | 490 | buf->vb.state = VIDEOBUF_DONE; |
1e6dd65e MCC |
491 | } |
492 | ||
730947bc | 493 | static void vivi_thread_tick(struct vivi_dev *dev) |
1e6dd65e | 494 | { |
78718e5d | 495 | struct vivi_dmaqueue *dma_q = &dev->vidq; |
730947bc | 496 | struct vivi_buffer *buf; |
78718e5d | 497 | unsigned long flags = 0; |
1e6dd65e | 498 | |
78718e5d | 499 | dprintk(dev, 1, "Thread tick\n"); |
1e6dd65e | 500 | |
78718e5d BP |
501 | spin_lock_irqsave(&dev->slock, flags); |
502 | if (list_empty(&dma_q->active)) { | |
503 | dprintk(dev, 1, "No active queue to serve\n"); | |
504 | goto unlock; | |
505 | } | |
1e6dd65e | 506 | |
78718e5d BP |
507 | buf = list_entry(dma_q->active.next, |
508 | struct vivi_buffer, vb.queue); | |
1e6dd65e | 509 | |
78718e5d BP |
510 | /* Nobody is waiting on this buffer, return */ |
511 | if (!waitqueue_active(&buf->vb.done)) | |
512 | goto unlock; | |
1e6dd65e | 513 | |
78718e5d | 514 | list_del(&buf->vb.queue); |
0b600512 | 515 | |
78718e5d BP |
516 | do_gettimeofday(&buf->vb.ts); |
517 | ||
518 | /* Fill buffer */ | |
730947bc | 519 | vivi_fillbuff(dev, buf); |
78718e5d BP |
520 | dprintk(dev, 1, "filled buffer %p\n", buf); |
521 | ||
522 | wake_up(&buf->vb.done); | |
523 | dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i); | |
524 | unlock: | |
525 | spin_unlock_irqrestore(&dev->slock, flags); | |
1e6dd65e MCC |
526 | } |
527 | ||
6594ad82 MCC |
528 | #define frames_to_ms(frames) \ |
529 | ((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR) | |
530 | ||
730947bc | 531 | static void vivi_sleep(struct vivi_dev *dev) |
1e6dd65e | 532 | { |
78718e5d BP |
533 | struct vivi_dmaqueue *dma_q = &dev->vidq; |
534 | int timeout; | |
1e6dd65e MCC |
535 | DECLARE_WAITQUEUE(wait, current); |
536 | ||
7e28adb2 | 537 | dprintk(dev, 1, "%s dma_q=0x%08lx\n", __func__, |
6c2f9901 | 538 | (unsigned long)dma_q); |
1e6dd65e MCC |
539 | |
540 | add_wait_queue(&dma_q->wq, &wait); | |
6594ad82 MCC |
541 | if (kthread_should_stop()) |
542 | goto stop_task; | |
543 | ||
6594ad82 | 544 | /* Calculate time to wake up */ |
78718e5d | 545 | timeout = msecs_to_jiffies(frames_to_ms(1)); |
6594ad82 | 546 | |
730947bc | 547 | vivi_thread_tick(dev); |
6594ad82 MCC |
548 | |
549 | schedule_timeout_interruptible(timeout); | |
1e6dd65e | 550 | |
6594ad82 | 551 | stop_task: |
1e6dd65e MCC |
552 | remove_wait_queue(&dma_q->wq, &wait); |
553 | try_to_freeze(); | |
554 | } | |
555 | ||
972c3517 | 556 | static int vivi_thread(void *data) |
1e6dd65e | 557 | { |
730947bc | 558 | struct vivi_dev *dev = data; |
1e6dd65e | 559 | |
6c2f9901 | 560 | dprintk(dev, 1, "thread started\n"); |
1e6dd65e | 561 | |
83144186 | 562 | set_freezable(); |
0b600512 | 563 | |
1e6dd65e | 564 | for (;;) { |
730947bc | 565 | vivi_sleep(dev); |
1e6dd65e MCC |
566 | |
567 | if (kthread_should_stop()) | |
568 | break; | |
569 | } | |
6c2f9901 | 570 | dprintk(dev, 1, "thread: exit\n"); |
1e6dd65e MCC |
571 | return 0; |
572 | } | |
573 | ||
730947bc | 574 | static void vivi_start_generating(struct file *file) |
1e6dd65e | 575 | { |
730947bc | 576 | struct vivi_dev *dev = video_drvdata(file); |
78718e5d | 577 | struct vivi_dmaqueue *dma_q = &dev->vidq; |
6c2f9901 | 578 | |
7e28adb2 | 579 | dprintk(dev, 1, "%s\n", __func__); |
1e6dd65e | 580 | |
730947bc HV |
581 | if (test_and_set_bit(0, &dev->generating)) |
582 | return; | |
583 | file->private_data = dev; | |
584 | ||
585 | /* Resets frame counters */ | |
586 | dev->ms = 0; | |
587 | dev->mv_count = 0; | |
588 | dev->jiffies = jiffies; | |
589 | ||
590 | dma_q->frame = 0; | |
591 | dma_q->ini_jiffies = jiffies; | |
592 | dma_q->kthread = kthread_run(vivi_thread, dev, dev->v4l2_dev.name); | |
1e6dd65e | 593 | |
054afee4 | 594 | if (IS_ERR(dma_q->kthread)) { |
5ab6c9af | 595 | v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n"); |
730947bc HV |
596 | clear_bit(0, &dev->generating); |
597 | return; | |
1e6dd65e | 598 | } |
0b600512 MCC |
599 | /* Wakes thread */ |
600 | wake_up_interruptible(&dma_q->wq); | |
601 | ||
7e28adb2 | 602 | dprintk(dev, 1, "returning from %s\n", __func__); |
1e6dd65e MCC |
603 | } |
604 | ||
730947bc | 605 | static void vivi_stop_generating(struct file *file) |
1e6dd65e | 606 | { |
730947bc HV |
607 | struct vivi_dev *dev = video_drvdata(file); |
608 | struct vivi_dmaqueue *dma_q = &dev->vidq; | |
6c2f9901 | 609 | |
7e28adb2 | 610 | dprintk(dev, 1, "%s\n", __func__); |
730947bc HV |
611 | |
612 | if (!file->private_data) | |
613 | return; | |
614 | if (!test_and_clear_bit(0, &dev->generating)) | |
615 | return; | |
616 | ||
1e6dd65e MCC |
617 | /* shutdown control thread */ |
618 | if (dma_q->kthread) { | |
619 | kthread_stop(dma_q->kthread); | |
543323bc | 620 | dma_q->kthread = NULL; |
1e6dd65e | 621 | } |
730947bc HV |
622 | videobuf_stop(&dev->vb_vidq); |
623 | videobuf_mmap_free(&dev->vb_vidq); | |
624 | } | |
625 | ||
626 | static int vivi_is_generating(struct vivi_dev *dev) | |
627 | { | |
628 | return test_bit(0, &dev->generating); | |
1e6dd65e MCC |
629 | } |
630 | ||
1e6dd65e MCC |
631 | /* ------------------------------------------------------------------ |
632 | Videobuf operations | |
633 | ------------------------------------------------------------------*/ | |
634 | static int | |
635 | buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) | |
636 | { | |
730947bc | 637 | struct vivi_dev *dev = vq->priv_data; |
1e6dd65e | 638 | |
730947bc | 639 | *size = dev->width * dev->height * 2; |
1e6dd65e MCC |
640 | |
641 | if (0 == *count) | |
642 | *count = 32; | |
6bb2790f | 643 | |
730947bc HV |
644 | while (*size * *count > vid_limit * 1024 * 1024) |
645 | (*count)--; | |
6bb2790f | 646 | |
7e28adb2 | 647 | dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__, |
6c2f9901 | 648 | *count, *size); |
6bb2790f | 649 | |
1e6dd65e MCC |
650 | return 0; |
651 | } | |
652 | ||
972c3517 | 653 | static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf) |
1e6dd65e | 654 | { |
730947bc | 655 | struct vivi_dev *dev = vq->priv_data; |
6c2f9901 | 656 | |
7e28adb2 | 657 | dprintk(dev, 1, "%s, state: %i\n", __func__, buf->vb.state); |
1e6dd65e | 658 | |
5a037706 | 659 | videobuf_vmalloc_free(&buf->vb); |
fbde31d5 | 660 | dprintk(dev, 1, "free_buffer: freed\n"); |
0fc0686e | 661 | buf->vb.state = VIDEOBUF_NEEDS_INIT; |
1e6dd65e MCC |
662 | } |
663 | ||
1e6dd65e MCC |
664 | static int |
665 | buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, | |
666 | enum v4l2_field field) | |
667 | { | |
730947bc | 668 | struct vivi_dev *dev = vq->priv_data; |
543323bc | 669 | struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); |
78718e5d | 670 | int rc; |
1e6dd65e | 671 | |
7e28adb2 | 672 | dprintk(dev, 1, "%s, field=%d\n", __func__, field); |
1e6dd65e | 673 | |
730947bc | 674 | BUG_ON(NULL == dev->fmt); |
78718e5d | 675 | |
730947bc HV |
676 | if (dev->width < 48 || dev->width > MAX_WIDTH || |
677 | dev->height < 32 || dev->height > MAX_HEIGHT) | |
1e6dd65e | 678 | return -EINVAL; |
78718e5d | 679 | |
730947bc HV |
680 | buf->vb.size = dev->width * dev->height * 2; |
681 | if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) | |
1e6dd65e MCC |
682 | return -EINVAL; |
683 | ||
78718e5d | 684 | /* These properties only change when queue is idle, see s_fmt */ |
730947bc HV |
685 | buf->fmt = dev->fmt; |
686 | buf->vb.width = dev->width; | |
687 | buf->vb.height = dev->height; | |
78718e5d | 688 | buf->vb.field = field; |
1e6dd65e | 689 | |
730947bc HV |
690 | precalculate_bars(dev); |
691 | precalculate_line(dev); | |
c285addb | 692 | |
0fc0686e | 693 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { |
543323bc MCC |
694 | rc = videobuf_iolock(vq, &buf->vb, NULL); |
695 | if (rc < 0) | |
1e6dd65e MCC |
696 | goto fail; |
697 | } | |
698 | ||
0fc0686e | 699 | buf->vb.state = VIDEOBUF_PREPARED; |
1e6dd65e MCC |
700 | return 0; |
701 | ||
702 | fail: | |
543323bc | 703 | free_buffer(vq, buf); |
1e6dd65e MCC |
704 | return rc; |
705 | } | |
706 | ||
707 | static void | |
708 | buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) | |
709 | { | |
730947bc HV |
710 | struct vivi_dev *dev = vq->priv_data; |
711 | struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); | |
78718e5d BP |
712 | struct vivi_dmaqueue *vidq = &dev->vidq; |
713 | ||
7e28adb2 | 714 | dprintk(dev, 1, "%s\n", __func__); |
78718e5d BP |
715 | |
716 | buf->vb.state = VIDEOBUF_QUEUED; | |
717 | list_add_tail(&buf->vb.queue, &vidq->active); | |
1e6dd65e MCC |
718 | } |
719 | ||
543323bc MCC |
720 | static void buffer_release(struct videobuf_queue *vq, |
721 | struct videobuf_buffer *vb) | |
1e6dd65e | 722 | { |
730947bc HV |
723 | struct vivi_dev *dev = vq->priv_data; |
724 | struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); | |
1e6dd65e | 725 | |
7e28adb2 | 726 | dprintk(dev, 1, "%s\n", __func__); |
1e6dd65e | 727 | |
543323bc | 728 | free_buffer(vq, buf); |
1e6dd65e MCC |
729 | } |
730 | ||
1e6dd65e MCC |
731 | static struct videobuf_queue_ops vivi_video_qops = { |
732 | .buf_setup = buffer_setup, | |
733 | .buf_prepare = buffer_prepare, | |
734 | .buf_queue = buffer_queue, | |
735 | .buf_release = buffer_release, | |
1e6dd65e MCC |
736 | }; |
737 | ||
c820cc45 MCC |
738 | /* ------------------------------------------------------------------ |
739 | IOCTL vidioc handling | |
740 | ------------------------------------------------------------------*/ | |
543323bc | 741 | static int vidioc_querycap(struct file *file, void *priv, |
c820cc45 MCC |
742 | struct v4l2_capability *cap) |
743 | { | |
730947bc | 744 | struct vivi_dev *dev = video_drvdata(file); |
5ab6c9af | 745 | |
c820cc45 MCC |
746 | strcpy(cap->driver, "vivi"); |
747 | strcpy(cap->card, "vivi"); | |
5ab6c9af | 748 | strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info)); |
c820cc45 | 749 | cap->version = VIVI_VERSION; |
730947bc HV |
750 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | \ |
751 | V4L2_CAP_READWRITE; | |
c820cc45 MCC |
752 | return 0; |
753 | } | |
754 | ||
78b526a4 | 755 | static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, |
c820cc45 MCC |
756 | struct v4l2_fmtdesc *f) |
757 | { | |
d891f475 MD |
758 | struct vivi_fmt *fmt; |
759 | ||
760 | if (f->index >= ARRAY_SIZE(formats)) | |
c820cc45 MCC |
761 | return -EINVAL; |
762 | ||
d891f475 MD |
763 | fmt = &formats[f->index]; |
764 | ||
765 | strlcpy(f->description, fmt->name, sizeof(f->description)); | |
766 | f->pixelformat = fmt->fourcc; | |
c820cc45 MCC |
767 | return 0; |
768 | } | |
769 | ||
78b526a4 | 770 | static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, |
c820cc45 MCC |
771 | struct v4l2_format *f) |
772 | { | |
730947bc | 773 | struct vivi_dev *dev = video_drvdata(file); |
c820cc45 | 774 | |
730947bc HV |
775 | f->fmt.pix.width = dev->width; |
776 | f->fmt.pix.height = dev->height; | |
777 | f->fmt.pix.field = dev->vb_vidq.field; | |
778 | f->fmt.pix.pixelformat = dev->fmt->fourcc; | |
c820cc45 | 779 | f->fmt.pix.bytesperline = |
730947bc | 780 | (f->fmt.pix.width * dev->fmt->depth) >> 3; |
c820cc45 MCC |
781 | f->fmt.pix.sizeimage = |
782 | f->fmt.pix.height * f->fmt.pix.bytesperline; | |
730947bc | 783 | return 0; |
c820cc45 MCC |
784 | } |
785 | ||
78b526a4 | 786 | static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, |
1e6dd65e MCC |
787 | struct v4l2_format *f) |
788 | { | |
730947bc | 789 | struct vivi_dev *dev = video_drvdata(file); |
1e6dd65e MCC |
790 | struct vivi_fmt *fmt; |
791 | enum v4l2_field field; | |
1e6dd65e | 792 | |
d891f475 MD |
793 | fmt = get_format(f); |
794 | if (!fmt) { | |
795 | dprintk(dev, 1, "Fourcc format (0x%08x) invalid.\n", | |
796 | f->fmt.pix.pixelformat); | |
1e6dd65e MCC |
797 | return -EINVAL; |
798 | } | |
1e6dd65e MCC |
799 | |
800 | field = f->fmt.pix.field; | |
801 | ||
802 | if (field == V4L2_FIELD_ANY) { | |
543323bc | 803 | field = V4L2_FIELD_INTERLACED; |
1e6dd65e | 804 | } else if (V4L2_FIELD_INTERLACED != field) { |
6c2f9901 | 805 | dprintk(dev, 1, "Field type invalid.\n"); |
1e6dd65e MCC |
806 | return -EINVAL; |
807 | } | |
808 | ||
1e6dd65e | 809 | f->fmt.pix.field = field; |
730947bc HV |
810 | v4l_bound_align_image(&f->fmt.pix.width, 48, MAX_WIDTH, 2, |
811 | &f->fmt.pix.height, 32, MAX_HEIGHT, 0, 0); | |
1e6dd65e MCC |
812 | f->fmt.pix.bytesperline = |
813 | (f->fmt.pix.width * fmt->depth) >> 3; | |
814 | f->fmt.pix.sizeimage = | |
815 | f->fmt.pix.height * f->fmt.pix.bytesperline; | |
1e6dd65e MCC |
816 | return 0; |
817 | } | |
818 | ||
e164b58a MCC |
819 | static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, |
820 | struct v4l2_format *f) | |
821 | { | |
730947bc | 822 | struct vivi_dev *dev = video_drvdata(file); |
e164b58a | 823 | |
730947bc | 824 | int ret = vidioc_try_fmt_vid_cap(file, priv, f); |
e164b58a MCC |
825 | if (ret < 0) |
826 | return ret; | |
827 | ||
730947bc HV |
828 | if (vivi_is_generating(dev)) { |
829 | dprintk(dev, 1, "%s device busy\n", __func__); | |
e164b58a MCC |
830 | ret = -EBUSY; |
831 | goto out; | |
832 | } | |
833 | ||
730947bc HV |
834 | dev->fmt = get_format(f); |
835 | dev->width = f->fmt.pix.width; | |
836 | dev->height = f->fmt.pix.height; | |
837 | dev->vb_vidq.field = f->fmt.pix.field; | |
78718e5d BP |
838 | ret = 0; |
839 | out: | |
e164b58a | 840 | return ret; |
1e6dd65e MCC |
841 | } |
842 | ||
543323bc MCC |
843 | static int vidioc_reqbufs(struct file *file, void *priv, |
844 | struct v4l2_requestbuffers *p) | |
1e6dd65e | 845 | { |
730947bc | 846 | struct vivi_dev *dev = video_drvdata(file); |
1e6dd65e | 847 | |
730947bc | 848 | return videobuf_reqbufs(&dev->vb_vidq, p); |
1e6dd65e MCC |
849 | } |
850 | ||
543323bc | 851 | static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) |
1e6dd65e | 852 | { |
730947bc | 853 | struct vivi_dev *dev = video_drvdata(file); |
1e6dd65e | 854 | |
730947bc | 855 | return videobuf_querybuf(&dev->vb_vidq, p); |
c820cc45 | 856 | } |
1e6dd65e | 857 | |
543323bc | 858 | static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) |
c820cc45 | 859 | { |
730947bc | 860 | struct vivi_dev *dev = video_drvdata(file); |
1e6dd65e | 861 | |
730947bc | 862 | return videobuf_qbuf(&dev->vb_vidq, p); |
c820cc45 | 863 | } |
1e6dd65e | 864 | |
543323bc | 865 | static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) |
c820cc45 | 866 | { |
730947bc | 867 | struct vivi_dev *dev = video_drvdata(file); |
1e6dd65e | 868 | |
730947bc HV |
869 | return videobuf_dqbuf(&dev->vb_vidq, p, |
870 | file->f_flags & O_NONBLOCK); | |
c820cc45 | 871 | } |
1e6dd65e | 872 | |
0dfa9abd | 873 | #ifdef CONFIG_VIDEO_V4L1_COMPAT |
543323bc | 874 | static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) |
c820cc45 | 875 | { |
730947bc | 876 | struct vivi_dev *dev = video_drvdata(file); |
4ceb04e1 | 877 | |
730947bc | 878 | return videobuf_cgmbuf(&dev->vb_vidq, mbuf, 8); |
c820cc45 MCC |
879 | } |
880 | #endif | |
1e6dd65e | 881 | |
dc46ace1 | 882 | static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) |
c820cc45 | 883 | { |
730947bc HV |
884 | struct vivi_dev *dev = video_drvdata(file); |
885 | int ret; | |
1e6dd65e | 886 | |
730947bc | 887 | if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
c820cc45 | 888 | return -EINVAL; |
730947bc HV |
889 | ret = videobuf_streamon(&dev->vb_vidq); |
890 | if (ret) | |
891 | return ret; | |
1e6dd65e | 892 | |
730947bc HV |
893 | vivi_start_generating(file); |
894 | return 0; | |
c820cc45 | 895 | } |
1e6dd65e | 896 | |
dc46ace1 | 897 | static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) |
c820cc45 | 898 | { |
730947bc HV |
899 | struct vivi_dev *dev = video_drvdata(file); |
900 | int ret; | |
1e6dd65e | 901 | |
730947bc | 902 | if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
c820cc45 | 903 | return -EINVAL; |
730947bc HV |
904 | ret = videobuf_streamoff(&dev->vb_vidq); |
905 | if (!ret) | |
906 | vivi_stop_generating(file); | |
907 | return ret; | |
c820cc45 MCC |
908 | } |
909 | ||
543323bc | 910 | static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) |
c820cc45 | 911 | { |
c820cc45 MCC |
912 | return 0; |
913 | } | |
1e6dd65e | 914 | |
c820cc45 | 915 | /* only one input in this sample driver */ |
543323bc | 916 | static int vidioc_enum_input(struct file *file, void *priv, |
c820cc45 MCC |
917 | struct v4l2_input *inp) |
918 | { | |
e164b58a | 919 | if (inp->index >= NUM_INPUTS) |
c820cc45 | 920 | return -EINVAL; |
1e6dd65e | 921 | |
c820cc45 | 922 | inp->type = V4L2_INPUT_TYPE_CAMERA; |
784c668b | 923 | inp->std = V4L2_STD_525_60; |
e164b58a | 924 | sprintf(inp->name, "Camera %u", inp->index); |
730947bc | 925 | return 0; |
c820cc45 | 926 | } |
1e6dd65e | 927 | |
543323bc | 928 | static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) |
c820cc45 | 929 | { |
730947bc | 930 | struct vivi_dev *dev = video_drvdata(file); |
e164b58a MCC |
931 | |
932 | *i = dev->input; | |
730947bc | 933 | return 0; |
c820cc45 | 934 | } |
730947bc | 935 | |
543323bc | 936 | static int vidioc_s_input(struct file *file, void *priv, unsigned int i) |
c820cc45 | 937 | { |
730947bc | 938 | struct vivi_dev *dev = video_drvdata(file); |
e164b58a MCC |
939 | |
940 | if (i >= NUM_INPUTS) | |
c820cc45 | 941 | return -EINVAL; |
1e6dd65e | 942 | |
e164b58a | 943 | dev->input = i; |
730947bc HV |
944 | precalculate_bars(dev); |
945 | precalculate_line(dev); | |
946 | return 0; | |
c820cc45 | 947 | } |
1e6dd65e | 948 | |
730947bc | 949 | /* --- controls ---------------------------------------------- */ |
543323bc MCC |
950 | static int vidioc_queryctrl(struct file *file, void *priv, |
951 | struct v4l2_queryctrl *qc) | |
c820cc45 | 952 | { |
730947bc HV |
953 | switch (qc->id) { |
954 | case V4L2_CID_AUDIO_VOLUME: | |
955 | return v4l2_ctrl_query_fill(qc, 0, 255, 1, 200); | |
956 | case V4L2_CID_BRIGHTNESS: | |
957 | return v4l2_ctrl_query_fill(qc, 0, 255, 1, 127); | |
958 | case V4L2_CID_CONTRAST: | |
959 | return v4l2_ctrl_query_fill(qc, 0, 255, 1, 16); | |
960 | case V4L2_CID_SATURATION: | |
961 | return v4l2_ctrl_query_fill(qc, 0, 255, 1, 127); | |
962 | case V4L2_CID_HUE: | |
963 | return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0); | |
964 | } | |
c820cc45 MCC |
965 | return -EINVAL; |
966 | } | |
1e6dd65e | 967 | |
543323bc MCC |
968 | static int vidioc_g_ctrl(struct file *file, void *priv, |
969 | struct v4l2_control *ctrl) | |
c820cc45 | 970 | { |
730947bc | 971 | struct vivi_dev *dev = video_drvdata(file); |
1e6dd65e | 972 | |
730947bc HV |
973 | switch (ctrl->id) { |
974 | case V4L2_CID_AUDIO_VOLUME: | |
975 | ctrl->value = dev->volume; | |
976 | return 0; | |
977 | case V4L2_CID_BRIGHTNESS: | |
978 | ctrl->value = dev->brightness; | |
979 | return 0; | |
980 | case V4L2_CID_CONTRAST: | |
981 | ctrl->value = dev->contrast; | |
982 | return 0; | |
983 | case V4L2_CID_SATURATION: | |
984 | ctrl->value = dev->saturation; | |
985 | return 0; | |
986 | case V4L2_CID_HUE: | |
987 | ctrl->value = dev->hue; | |
988 | return 0; | |
989 | } | |
c820cc45 | 990 | return -EINVAL; |
1e6dd65e | 991 | } |
730947bc | 992 | |
543323bc | 993 | static int vidioc_s_ctrl(struct file *file, void *priv, |
c820cc45 | 994 | struct v4l2_control *ctrl) |
1e6dd65e | 995 | { |
730947bc HV |
996 | struct vivi_dev *dev = video_drvdata(file); |
997 | struct v4l2_queryctrl qc; | |
998 | int err; | |
999 | ||
1000 | qc.id = ctrl->id; | |
1001 | err = vidioc_queryctrl(file, priv, &qc); | |
1002 | if (err < 0) | |
1003 | return err; | |
1004 | if (ctrl->value < qc.minimum || ctrl->value > qc.maximum) | |
1005 | return -ERANGE; | |
1006 | switch (ctrl->id) { | |
1007 | case V4L2_CID_AUDIO_VOLUME: | |
1008 | dev->volume = ctrl->value; | |
1009 | return 0; | |
1010 | case V4L2_CID_BRIGHTNESS: | |
1011 | dev->brightness = ctrl->value; | |
1012 | return 0; | |
1013 | case V4L2_CID_CONTRAST: | |
1014 | dev->contrast = ctrl->value; | |
1015 | return 0; | |
1016 | case V4L2_CID_SATURATION: | |
1017 | dev->saturation = ctrl->value; | |
1018 | return 0; | |
1019 | case V4L2_CID_HUE: | |
1020 | dev->hue = ctrl->value; | |
1021 | return 0; | |
1022 | } | |
c820cc45 | 1023 | return -EINVAL; |
1e6dd65e MCC |
1024 | } |
1025 | ||
1026 | /* ------------------------------------------------------------------ | |
1027 | File operations for the device | |
1028 | ------------------------------------------------------------------*/ | |
1029 | ||
1e6dd65e MCC |
1030 | static ssize_t |
1031 | vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) | |
1032 | { | |
730947bc | 1033 | struct vivi_dev *dev = video_drvdata(file); |
1e6dd65e | 1034 | |
730947bc HV |
1035 | vivi_start_generating(file); |
1036 | return videobuf_read_stream(&dev->vb_vidq, data, count, ppos, 0, | |
1e6dd65e | 1037 | file->f_flags & O_NONBLOCK); |
1e6dd65e MCC |
1038 | } |
1039 | ||
1040 | static unsigned int | |
1041 | vivi_poll(struct file *file, struct poll_table_struct *wait) | |
1042 | { | |
730947bc HV |
1043 | struct vivi_dev *dev = video_drvdata(file); |
1044 | struct videobuf_queue *q = &dev->vb_vidq; | |
1e6dd65e | 1045 | |
7e28adb2 | 1046 | dprintk(dev, 1, "%s\n", __func__); |
1e6dd65e | 1047 | |
730947bc | 1048 | vivi_start_generating(file); |
85c7c70b | 1049 | return videobuf_poll_stream(file, q, wait); |
1e6dd65e MCC |
1050 | } |
1051 | ||
bec43661 | 1052 | static int vivi_close(struct file *file) |
1e6dd65e | 1053 | { |
50462eb0 | 1054 | struct video_device *vdev = video_devdata(file); |
730947bc | 1055 | struct vivi_dev *dev = video_drvdata(file); |
1e6dd65e | 1056 | |
730947bc | 1057 | vivi_stop_generating(file); |
1e6dd65e | 1058 | |
730947bc HV |
1059 | dprintk(dev, 1, "close called (dev=%s)\n", |
1060 | video_device_node_name(vdev)); | |
1e6dd65e MCC |
1061 | return 0; |
1062 | } | |
1063 | ||
543323bc | 1064 | static int vivi_mmap(struct file *file, struct vm_area_struct *vma) |
1e6dd65e | 1065 | { |
730947bc | 1066 | struct vivi_dev *dev = video_drvdata(file); |
1e6dd65e MCC |
1067 | int ret; |
1068 | ||
6c2f9901 | 1069 | dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma); |
1e6dd65e | 1070 | |
730947bc | 1071 | ret = videobuf_mmap_mapper(&dev->vb_vidq, vma); |
1e6dd65e | 1072 | |
6c2f9901 | 1073 | dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n", |
1e6dd65e | 1074 | (unsigned long)vma->vm_start, |
730947bc | 1075 | (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, |
1e6dd65e | 1076 | ret); |
1e6dd65e MCC |
1077 | return ret; |
1078 | } | |
1079 | ||
bec43661 | 1080 | static const struct v4l2_file_operations vivi_fops = { |
1e6dd65e | 1081 | .owner = THIS_MODULE, |
f905c442 | 1082 | .release = vivi_close, |
1e6dd65e MCC |
1083 | .read = vivi_read, |
1084 | .poll = vivi_poll, | |
fedc6c81 | 1085 | .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ |
5a037706 | 1086 | .mmap = vivi_mmap, |
1e6dd65e MCC |
1087 | }; |
1088 | ||
a399810c | 1089 | static const struct v4l2_ioctl_ops vivi_ioctl_ops = { |
c820cc45 | 1090 | .vidioc_querycap = vidioc_querycap, |
78b526a4 HV |
1091 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, |
1092 | .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, | |
1093 | .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, | |
1094 | .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, | |
c820cc45 MCC |
1095 | .vidioc_reqbufs = vidioc_reqbufs, |
1096 | .vidioc_querybuf = vidioc_querybuf, | |
1097 | .vidioc_qbuf = vidioc_qbuf, | |
1098 | .vidioc_dqbuf = vidioc_dqbuf, | |
1099 | .vidioc_s_std = vidioc_s_std, | |
1100 | .vidioc_enum_input = vidioc_enum_input, | |
1101 | .vidioc_g_input = vidioc_g_input, | |
1102 | .vidioc_s_input = vidioc_s_input, | |
730947bc HV |
1103 | .vidioc_streamon = vidioc_streamon, |
1104 | .vidioc_streamoff = vidioc_streamoff, | |
c820cc45 MCC |
1105 | .vidioc_queryctrl = vidioc_queryctrl, |
1106 | .vidioc_g_ctrl = vidioc_g_ctrl, | |
1107 | .vidioc_s_ctrl = vidioc_s_ctrl, | |
0dfa9abd | 1108 | #ifdef CONFIG_VIDEO_V4L1_COMPAT |
c820cc45 MCC |
1109 | .vidiocgmbuf = vidiocgmbuf, |
1110 | #endif | |
a399810c HV |
1111 | }; |
1112 | ||
1113 | static struct video_device vivi_template = { | |
1114 | .name = "vivi", | |
a399810c HV |
1115 | .fops = &vivi_fops, |
1116 | .ioctl_ops = &vivi_ioctl_ops, | |
a399810c HV |
1117 | .release = video_device_release, |
1118 | ||
784c668b | 1119 | .tvnorms = V4L2_STD_525_60, |
e75f9cee | 1120 | .current_norm = V4L2_STD_NTSC_M, |
1e6dd65e | 1121 | }; |
5ab6c9af | 1122 | |
c820cc45 | 1123 | /* ----------------------------------------------------------------- |
1e6dd65e MCC |
1124 | Initialization and module stuff |
1125 | ------------------------------------------------------------------*/ | |
1126 | ||
5ab6c9af HV |
1127 | static int vivi_release(void) |
1128 | { | |
1129 | struct vivi_dev *dev; | |
1130 | struct list_head *list; | |
980d4f17 | 1131 | |
5ab6c9af HV |
1132 | while (!list_empty(&vivi_devlist)) { |
1133 | list = vivi_devlist.next; | |
1134 | list_del(list); | |
1135 | dev = list_entry(list, struct vivi_dev, vivi_devlist); | |
1136 | ||
38c7c036 LP |
1137 | v4l2_info(&dev->v4l2_dev, "unregistering %s\n", |
1138 | video_device_node_name(dev->vfd)); | |
5ab6c9af HV |
1139 | video_unregister_device(dev->vfd); |
1140 | v4l2_device_unregister(&dev->v4l2_dev); | |
1141 | kfree(dev); | |
1142 | } | |
1143 | ||
1144 | return 0; | |
1145 | } | |
1146 | ||
c41ee24b | 1147 | static int __init vivi_create_instance(int inst) |
1e6dd65e | 1148 | { |
1e6dd65e | 1149 | struct vivi_dev *dev; |
f905c442 | 1150 | struct video_device *vfd; |
730947bc | 1151 | int ret; |
1e6dd65e | 1152 | |
5ab6c9af HV |
1153 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
1154 | if (!dev) | |
1155 | return -ENOMEM; | |
980d4f17 | 1156 | |
5ab6c9af | 1157 | snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), |
c41ee24b | 1158 | "%s-%03d", VIVI_MODULE_NAME, inst); |
5ab6c9af HV |
1159 | ret = v4l2_device_register(NULL, &dev->v4l2_dev); |
1160 | if (ret) | |
1161 | goto free_dev; | |
1e6dd65e | 1162 | |
730947bc HV |
1163 | dev->fmt = &formats[0]; |
1164 | dev->width = 640; | |
1165 | dev->height = 480; | |
1166 | dev->volume = 200; | |
1167 | dev->brightness = 127; | |
1168 | dev->contrast = 16; | |
1169 | dev->saturation = 127; | |
1170 | dev->hue = 0; | |
1171 | ||
fedc6c81 HV |
1172 | /* initialize locks */ |
1173 | spin_lock_init(&dev->slock); | |
1174 | mutex_init(&dev->mutex); | |
1175 | ||
730947bc HV |
1176 | videobuf_queue_vmalloc_init(&dev->vb_vidq, &vivi_video_qops, |
1177 | NULL, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, | |
1178 | V4L2_FIELD_INTERLACED, | |
fedc6c81 | 1179 | sizeof(struct vivi_buffer), dev, &dev->mutex); |
730947bc | 1180 | |
5ab6c9af HV |
1181 | /* init video dma queues */ |
1182 | INIT_LIST_HEAD(&dev->vidq.active); | |
1183 | init_waitqueue_head(&dev->vidq.wq); | |
1e6dd65e | 1184 | |
5ab6c9af HV |
1185 | ret = -ENOMEM; |
1186 | vfd = video_device_alloc(); | |
1187 | if (!vfd) | |
1188 | goto unreg_dev; | |
55712ff7 | 1189 | |
5ab6c9af | 1190 | *vfd = vivi_template; |
c285addb | 1191 | vfd->debug = debug; |
730947bc | 1192 | vfd->v4l2_dev = &dev->v4l2_dev; |
fedc6c81 | 1193 | vfd->lock = &dev->mutex; |
55712ff7 | 1194 | |
5ab6c9af HV |
1195 | ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); |
1196 | if (ret < 0) | |
1197 | goto rel_vdev; | |
980d4f17 | 1198 | |
5ab6c9af | 1199 | video_set_drvdata(vfd, dev); |
980d4f17 | 1200 | |
5ab6c9af HV |
1201 | /* Now that everything is fine, let's add it to device list */ |
1202 | list_add_tail(&dev->vivi_devlist, &vivi_devlist); | |
980d4f17 | 1203 | |
7de0b873 | 1204 | if (video_nr != -1) |
5ab6c9af | 1205 | video_nr++; |
f905c442 | 1206 | |
5ab6c9af | 1207 | dev->vfd = vfd; |
38c7c036 LP |
1208 | v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n", |
1209 | video_device_node_name(vfd)); | |
5ab6c9af HV |
1210 | return 0; |
1211 | ||
1212 | rel_vdev: | |
1213 | video_device_release(vfd); | |
1214 | unreg_dev: | |
1215 | v4l2_device_unregister(&dev->v4l2_dev); | |
1216 | free_dev: | |
1217 | kfree(dev); | |
1218 | return ret; | |
1219 | } | |
f905c442 | 1220 | |
5ab6c9af HV |
1221 | /* This routine allocates from 1 to n_devs virtual drivers. |
1222 | ||
1223 | The real maximum number of virtual drivers will depend on how many drivers | |
1224 | will succeed. This is limited to the maximum number of devices that | |
1225 | videodev supports, which is equal to VIDEO_NUM_DEVICES. | |
1226 | */ | |
1227 | static int __init vivi_init(void) | |
1228 | { | |
730947bc | 1229 | const struct font_desc *font = find_font("VGA8x16"); |
9185cbfc | 1230 | int ret = 0, i; |
5ab6c9af | 1231 | |
730947bc HV |
1232 | if (font == NULL) { |
1233 | printk(KERN_ERR "vivi: could not find font\n"); | |
1234 | return -ENODEV; | |
1235 | } | |
1236 | font8x16 = font->data; | |
1237 | ||
5ab6c9af HV |
1238 | if (n_devs <= 0) |
1239 | n_devs = 1; | |
1240 | ||
1241 | for (i = 0; i < n_devs; i++) { | |
1242 | ret = vivi_create_instance(i); | |
1243 | if (ret) { | |
1244 | /* If some instantiations succeeded, keep driver */ | |
1245 | if (i) | |
1246 | ret = 0; | |
1247 | break; | |
1248 | } | |
55712ff7 | 1249 | } |
f905c442 | 1250 | |
55712ff7 | 1251 | if (ret < 0) { |
730947bc | 1252 | printk(KERN_ERR "vivi: error %d while loading driver\n", ret); |
5ab6c9af HV |
1253 | return ret; |
1254 | } | |
1255 | ||
1256 | printk(KERN_INFO "Video Technology Magazine Virtual Video " | |
745271ae CK |
1257 | "Capture Board ver %u.%u.%u successfully loaded.\n", |
1258 | (VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF, | |
1259 | VIVI_VERSION & 0xFF); | |
980d4f17 | 1260 | |
5ab6c9af HV |
1261 | /* n_devs will reflect the actual number of allocated devices */ |
1262 | n_devs = i; | |
980d4f17 | 1263 | |
1e6dd65e MCC |
1264 | return ret; |
1265 | } | |
1266 | ||
1267 | static void __exit vivi_exit(void) | |
1268 | { | |
55712ff7 | 1269 | vivi_release(); |
1e6dd65e MCC |
1270 | } |
1271 | ||
1272 | module_init(vivi_init); | |
1273 | module_exit(vivi_exit); |