blob: 2fddba6d5b39fbc2a90b3bc70e8b6fac8787f1ef [file] [log] [blame]
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001/*
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>
16#include <linux/delay.h>
17#include <linux/errno.h>
18#include <linux/fs.h>
19#include <linux/kernel.h>
20#include <linux/slab.h>
21#include <linux/mm.h>
22#include <linux/ioport.h>
23#include <linux/init.h>
24#include <linux/sched.h>
25#include <linux/pci.h>
26#include <linux/random.h>
27#include <linux/version.h>
Matthias Kaehlcke51b54022007-07-02 10:19:38 -030028#include <linux/mutex.h>
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -030029#include <linux/videodev2.h>
Andrew Morton10951362006-04-27 10:10:58 -030030#include <linux/dma-mapping.h>
Mauro Carvalho Chehabcd41e282006-04-09 15:43:41 -030031#ifdef CONFIG_VIDEO_V4L1_COMPAT
32/* Include V4L1 specific functions. Should be removed soon */
33#include <linux/videodev.h>
34#endif
Michael Krufkyf13df912006-03-23 22:01:44 -030035#include <linux/interrupt.h>
Mauro Carvalho Chehab5a037702007-08-02 23:31:54 -030036#include <media/videobuf-vmalloc.h>
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -030037#include <media/v4l2-common.h>
Hans Verkuil35ea11f2008-07-20 08:12:02 -030038#include <media/v4l2-ioctl.h>
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -030039#include <linux/kthread.h>
40#include <linux/highmem.h>
Nigel Cunningham7dfb7102006-12-06 20:34:23 -080041#include <linux/freezer.h>
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -030042
Mauro Carvalho Chehab584ce482008-06-10 15:21:49 -030043#define VIVI_MODULE_NAME "vivi"
Carl Karsten745271a2008-06-10 00:02:32 -030044
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -030045/* Wake up at about 30 fps */
46#define WAKE_NUMERATOR 30
47#define WAKE_DENOMINATOR 1001
48#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */
49
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -030050#include "font.h"
51
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -030052#define VIVI_MAJOR_VERSION 0
Carl Karsten745271a2008-06-10 00:02:32 -030053#define VIVI_MINOR_VERSION 5
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -030054#define VIVI_RELEASE 0
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -030055#define VIVI_VERSION \
56 KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -030057
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -030058/* Declare static vars that will be used as parameters */
59static unsigned int vid_limit = 16; /* Video memory limit, in Mb */
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -030060static int video_nr = -1; /* /dev/videoN, -1 for autodetect */
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -030061static int n_devs = 1; /* Number of virtual devices */
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -030062
63/* supported controls */
64static struct v4l2_queryctrl vivi_qctrl[] = {
65 {
66 .id = V4L2_CID_AUDIO_VOLUME,
67 .name = "Volume",
68 .minimum = 0,
69 .maximum = 65535,
70 .step = 65535/100,
71 .default_value = 65535,
72 .flags = 0,
73 .type = V4L2_CTRL_TYPE_INTEGER,
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -030074 }, {
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -030075 .id = V4L2_CID_BRIGHTNESS,
76 .type = V4L2_CTRL_TYPE_INTEGER,
77 .name = "Brightness",
78 .minimum = 0,
79 .maximum = 255,
80 .step = 1,
81 .default_value = 127,
82 .flags = 0,
83 }, {
84 .id = V4L2_CID_CONTRAST,
85 .type = V4L2_CTRL_TYPE_INTEGER,
86 .name = "Contrast",
87 .minimum = 0,
88 .maximum = 255,
89 .step = 0x1,
90 .default_value = 0x10,
91 .flags = 0,
92 }, {
93 .id = V4L2_CID_SATURATION,
94 .type = V4L2_CTRL_TYPE_INTEGER,
95 .name = "Saturation",
96 .minimum = 0,
97 .maximum = 255,
98 .step = 0x1,
99 .default_value = 127,
100 .flags = 0,
101 }, {
102 .id = V4L2_CID_HUE,
103 .type = V4L2_CTRL_TYPE_INTEGER,
104 .name = "Hue",
105 .minimum = -128,
106 .maximum = 127,
107 .step = 0x1,
108 .default_value = 0,
109 .flags = 0,
110 }
111};
112
113static int qctl_regs[ARRAY_SIZE(vivi_qctrl)];
114
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300115#define dprintk(dev, level, fmt, arg...) \
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300116 do { \
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300117 if (dev->vfd->debug >= (level)) \
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300118 printk(KERN_DEBUG "vivi: " fmt , ## arg); \
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300119 } while (0)
120
121/* ------------------------------------------------------------------
122 Basic structures
123 ------------------------------------------------------------------*/
124
125struct vivi_fmt {
126 char *name;
127 u32 fourcc; /* v4l2 format id */
128 int depth;
129};
130
Magnus Dammd891f472008-10-14 12:47:09 -0300131static struct vivi_fmt formats[] = {
132 {
133 .name = "4:2:2, packed, YUYV",
134 .fourcc = V4L2_PIX_FMT_YUYV,
135 .depth = 16,
136 },
Magnus Dammfca36ba2008-10-14 12:47:25 -0300137 {
138 .name = "4:2:2, packed, UYVY",
139 .fourcc = V4L2_PIX_FMT_UYVY,
140 .depth = 16,
141 },
Magnus Dammaeadb5d2008-10-14 12:47:35 -0300142 {
143 .name = "RGB565 (LE)",
144 .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
145 .depth = 16,
146 },
147 {
148 .name = "RGB565 (BE)",
149 .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
150 .depth = 16,
151 },
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300152};
153
Magnus Dammd891f472008-10-14 12:47:09 -0300154static struct vivi_fmt *get_format(struct v4l2_format *f)
155{
156 struct vivi_fmt *fmt;
157 unsigned int k;
158
159 for (k = 0; k < ARRAY_SIZE(formats); k++) {
160 fmt = &formats[k];
161 if (fmt->fourcc == f->fmt.pix.pixelformat)
162 break;
163 }
164
165 if (k == ARRAY_SIZE(formats))
166 return NULL;
167
168 return &formats[k];
169}
170
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300171struct sg_to_addr {
172 int pos;
173 struct scatterlist *sg;
174};
175
176/* buffer for one video frame */
177struct vivi_buffer {
178 /* common v4l buffer stuff -- must be first */
179 struct videobuf_buffer vb;
180
181 struct vivi_fmt *fmt;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300182};
183
184struct vivi_dmaqueue {
185 struct list_head active;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300186
187 /* thread for generating video stream*/
188 struct task_struct *kthread;
189 wait_queue_head_t wq;
190 /* Counters to control fps rate */
191 int frame;
192 int ini_jiffies;
193};
194
195static LIST_HEAD(vivi_devlist);
196
197struct vivi_dev {
198 struct list_head vivi_devlist;
199
Mauro Carvalho Chehab55862ac2007-12-13 16:13:37 -0300200 spinlock_t slock;
Brandon Philipsaa9dbac2008-04-02 18:10:59 -0300201 struct mutex mutex;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300202
203 int users;
204
205 /* various device info */
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -0300206 struct video_device *vfd;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300207
208 struct vivi_dmaqueue vidq;
209
210 /* Several counters */
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -0300211 int h, m, s, ms;
212 unsigned long jiffies;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300213 char timestr[13];
Mauro Carvalho Chehab025341d2007-12-10 04:43:38 -0300214
215 int mv_count; /* Controls bars movement */
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300216};
217
218struct vivi_fh {
219 struct vivi_dev *dev;
220
221 /* video capture */
222 struct vivi_fmt *fmt;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300223 unsigned int width, height;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300224 struct videobuf_queue vb_vidq;
225
226 enum v4l2_buf_type type;
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300227 unsigned char bars[8][3];
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300228};
229
230/* ------------------------------------------------------------------
231 DMA and thread functions
232 ------------------------------------------------------------------*/
233
234/* Bars and Colors should match positions */
235
236enum colors {
237 WHITE,
238 AMBAR,
239 CYAN,
240 GREEN,
241 MAGENTA,
242 RED,
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300243 BLUE,
244 BLACK,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300245};
246
247static u8 bars[8][3] = {
248 /* R G B */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300249 {204, 204, 204}, /* white */
250 {208, 208, 0}, /* ambar */
251 { 0, 206, 206}, /* cyan */
252 { 0, 239, 0}, /* green */
253 {239, 0, 239}, /* magenta */
254 {205, 0, 0}, /* red */
255 { 0, 0, 255}, /* blue */
256 { 0, 0, 0}, /* black */
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300257};
258
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300259#define TO_Y(r, g, b) \
260 (((16829 * r + 33039 * g + 6416 * b + 32768) >> 16) + 16)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300261/* RGB to V(Cr) Color transform */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300262#define TO_V(r, g, b) \
263 (((28784 * r - 24103 * g - 4681 * b + 32768) >> 16) + 128)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300264/* RGB to U(Cb) Color transform */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300265#define TO_U(r, g, b) \
266 (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300267
268#define TSTAMP_MIN_Y 24
269#define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
270#define TSTAMP_MIN_X 64
271
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300272static void gen_twopix(struct vivi_fh *fh, unsigned char *buf, int colorpos)
273{
274 unsigned char r_y, g_u, b_v;
275 unsigned char *p;
276 int color;
277
278 r_y = fh->bars[colorpos][0]; /* R or precalculated Y */
279 g_u = fh->bars[colorpos][1]; /* G or precalculated U */
280 b_v = fh->bars[colorpos][2]; /* B or precalculated V */
281
282 for (color = 0; color < 4; color++) {
283 p = buf + color;
284
Magnus Dammd891f472008-10-14 12:47:09 -0300285 switch (fh->fmt->fourcc) {
286 case V4L2_PIX_FMT_YUYV:
287 switch (color) {
288 case 0:
289 case 2:
290 *p = r_y;
291 break;
292 case 1:
293 *p = g_u;
294 break;
295 case 3:
296 *p = b_v;
297 break;
298 }
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300299 break;
Magnus Dammfca36ba2008-10-14 12:47:25 -0300300 case V4L2_PIX_FMT_UYVY:
301 switch (color) {
302 case 1:
303 case 3:
304 *p = r_y;
305 break;
306 case 0:
307 *p = g_u;
308 break;
309 case 2:
310 *p = b_v;
311 break;
312 }
313 break;
Magnus Dammaeadb5d2008-10-14 12:47:35 -0300314 case V4L2_PIX_FMT_RGB565:
315 switch (color) {
316 case 0:
317 case 2:
318 *p = (g_u << 5) | b_v;
319 break;
320 case 1:
321 case 3:
322 *p = (r_y << 3) | (g_u >> 3);
323 break;
324 }
325 break;
326 case V4L2_PIX_FMT_RGB565X:
327 switch (color) {
328 case 0:
329 case 2:
330 *p = (r_y << 3) | (g_u >> 3);
331 break;
332 case 1:
333 case 3:
334 *p = (g_u << 5) | b_v;
335 break;
336 }
337 break;
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300338 }
339 }
340}
341
342static void gen_line(struct vivi_fh *fh, char *basep, int inipos, int wmax,
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300343 int hmax, int line, int count, char *timestr)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300344{
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300345 int w, i, j;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300346 int pos = inipos;
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300347 char *s;
348 u8 chr;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300349
350 /* We will just duplicate the second pixel at the packet */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300351 wmax /= 2;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300352
353 /* Generate a standard color bar pattern */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300354 for (w = 0; w < wmax; w++) {
355 int colorpos = ((w + count) * 8/(wmax + 1)) % 8;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300356
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300357 gen_twopix(fh, basep + pos, colorpos);
358 pos += 4; /* only 16 bpp supported for now */
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300359 }
360
361 /* Checks if it is possible to show timestamp */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300362 if (TSTAMP_MAX_Y >= hmax)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300363 goto end;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300364 if (TSTAMP_MIN_X + strlen(timestr) >= wmax)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300365 goto end;
366
367 /* Print stream time */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300368 if (line >= TSTAMP_MIN_Y && line <= TSTAMP_MAX_Y) {
369 j = TSTAMP_MIN_X;
370 for (s = timestr; *s; s++) {
371 chr = rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y];
372 for (i = 0; i < 7; i++) {
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300373 pos = inipos + j * 2;
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300374 /* Draw white font on black background */
375 if (chr & 1 << (7 - i))
376 gen_twopix(fh, basep + pos, WHITE);
377 else
378 gen_twopix(fh, basep + pos, BLACK);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300379 j++;
380 }
381 }
382 }
383
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300384end:
Mauro Carvalho Chehabb50e7fe2007-01-25 05:00:01 -0300385 return;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300386}
Brandon Philips78718e52008-04-02 18:10:59 -0300387
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300388static void vivi_fillbuff(struct vivi_fh *fh, struct vivi_buffer *buf)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300389{
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300390 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300391 int h , pos = 0;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300392 int hmax = buf->vb.height;
393 int wmax = buf->vb.width;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300394 struct timeval ts;
Marcin Slusarz5c554e62008-06-22 09:11:40 -0300395 char *tmpbuf;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300396 void *vbuf = videobuf_to_vmalloc(&buf->vb);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300397
Marcin Slusarz5c554e62008-06-22 09:11:40 -0300398 if (!vbuf)
Mauro Carvalho Chehab5a037702007-08-02 23:31:54 -0300399 return;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300400
Marcin Slusarz5c554e62008-06-22 09:11:40 -0300401 tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC);
402 if (!tmpbuf)
Brandon Philips78718e52008-04-02 18:10:59 -0300403 return;
404
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300405 for (h = 0; h < hmax; h++) {
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300406 gen_line(fh, tmpbuf, 0, wmax, hmax, h, dev->mv_count,
Mauro Carvalho Chehab3bef5e42007-09-22 02:01:33 -0300407 dev->timestr);
Brandon Philips78718e52008-04-02 18:10:59 -0300408 memcpy(vbuf + pos, tmpbuf, wmax * 2);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300409 pos += wmax*2;
410 }
411
Mauro Carvalho Chehab025341d2007-12-10 04:43:38 -0300412 dev->mv_count++;
Mauro Carvalho Chehab3bef5e42007-09-22 02:01:33 -0300413
Mauro Carvalho Chehab5a037702007-08-02 23:31:54 -0300414 kfree(tmpbuf);
415
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300416 /* Updates stream time */
417
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -0300418 dev->ms += jiffies_to_msecs(jiffies-dev->jiffies);
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300419 dev->jiffies = jiffies;
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -0300420 if (dev->ms >= 1000) {
421 dev->ms -= 1000;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300422 dev->s++;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300423 if (dev->s >= 60) {
424 dev->s -= 60;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300425 dev->m++;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300426 if (dev->m > 60) {
427 dev->m -= 60;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300428 dev->h++;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300429 if (dev->h > 24)
430 dev->h -= 24;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300431 }
432 }
433 }
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300434 sprintf(dev->timestr, "%02d:%02d:%02d:%03d",
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -0300435 dev->h, dev->m, dev->s, dev->ms);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300436
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300437 dprintk(dev, 2, "vivifill at %s: Buffer 0x%08lx size= %d\n",
438 dev->timestr, (unsigned long)tmpbuf, pos);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300439
440 /* Advice that buffer was filled */
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300441 buf->vb.field_count++;
442 do_gettimeofday(&ts);
443 buf->vb.ts = ts;
Brandon Philips78718e52008-04-02 18:10:59 -0300444 buf->vb.state = VIDEOBUF_DONE;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300445}
446
Brandon Philips78718e52008-04-02 18:10:59 -0300447static void vivi_thread_tick(struct vivi_fh *fh)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300448{
Brandon Philips78718e52008-04-02 18:10:59 -0300449 struct vivi_buffer *buf;
450 struct vivi_dev *dev = fh->dev;
451 struct vivi_dmaqueue *dma_q = &dev->vidq;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300452
Brandon Philips78718e52008-04-02 18:10:59 -0300453 unsigned long flags = 0;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300454
Brandon Philips78718e52008-04-02 18:10:59 -0300455 dprintk(dev, 1, "Thread tick\n");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300456
Brandon Philips78718e52008-04-02 18:10:59 -0300457 spin_lock_irqsave(&dev->slock, flags);
458 if (list_empty(&dma_q->active)) {
459 dprintk(dev, 1, "No active queue to serve\n");
460 goto unlock;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300461 }
Brandon Philips78718e52008-04-02 18:10:59 -0300462
463 buf = list_entry(dma_q->active.next,
464 struct vivi_buffer, vb.queue);
465
466 /* Nobody is waiting on this buffer, return */
467 if (!waitqueue_active(&buf->vb.done))
468 goto unlock;
469
470 list_del(&buf->vb.queue);
471
472 do_gettimeofday(&buf->vb.ts);
473
474 /* Fill buffer */
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300475 vivi_fillbuff(fh, buf);
Brandon Philips78718e52008-04-02 18:10:59 -0300476 dprintk(dev, 1, "filled buffer %p\n", buf);
477
478 wake_up(&buf->vb.done);
479 dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i);
480unlock:
481 spin_unlock_irqrestore(&dev->slock, flags);
482 return;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300483}
484
Mauro Carvalho Chehab6594ad82007-12-13 16:15:41 -0300485#define frames_to_ms(frames) \
486 ((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR)
487
Brandon Philips78718e52008-04-02 18:10:59 -0300488static void vivi_sleep(struct vivi_fh *fh)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300489{
Brandon Philips78718e52008-04-02 18:10:59 -0300490 struct vivi_dev *dev = fh->dev;
491 struct vivi_dmaqueue *dma_q = &dev->vidq;
492 int timeout;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300493 DECLARE_WAITQUEUE(wait, current);
494
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300495 dprintk(dev, 1, "%s dma_q=0x%08lx\n", __func__,
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300496 (unsigned long)dma_q);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300497
498 add_wait_queue(&dma_q->wq, &wait);
Mauro Carvalho Chehab6594ad82007-12-13 16:15:41 -0300499 if (kthread_should_stop())
500 goto stop_task;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300501
Mauro Carvalho Chehab6594ad82007-12-13 16:15:41 -0300502 /* Calculate time to wake up */
Brandon Philips78718e52008-04-02 18:10:59 -0300503 timeout = msecs_to_jiffies(frames_to_ms(1));
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300504
Brandon Philips78718e52008-04-02 18:10:59 -0300505 vivi_thread_tick(fh);
Mauro Carvalho Chehab6594ad82007-12-13 16:15:41 -0300506
507 schedule_timeout_interruptible(timeout);
508
509stop_task:
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300510 remove_wait_queue(&dma_q->wq, &wait);
511 try_to_freeze();
512}
513
Adrian Bunk972c3512006-04-27 21:06:50 -0300514static int vivi_thread(void *data)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300515{
Brandon Philips78718e52008-04-02 18:10:59 -0300516 struct vivi_fh *fh = data;
517 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300518
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300519 dprintk(dev, 1, "thread started\n");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300520
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700521 set_freezable();
Mauro Carvalho Chehab0b600512007-01-14 08:33:24 -0300522
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300523 for (;;) {
Brandon Philips78718e52008-04-02 18:10:59 -0300524 vivi_sleep(fh);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300525
526 if (kthread_should_stop())
527 break;
528 }
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300529 dprintk(dev, 1, "thread: exit\n");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300530 return 0;
531}
532
Brandon Philips78718e52008-04-02 18:10:59 -0300533static int vivi_start_thread(struct vivi_fh *fh)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300534{
Brandon Philips78718e52008-04-02 18:10:59 -0300535 struct vivi_dev *dev = fh->dev;
536 struct vivi_dmaqueue *dma_q = &dev->vidq;
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300537
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300538 dma_q->frame = 0;
539 dma_q->ini_jiffies = jiffies;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300540
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300541 dprintk(dev, 1, "%s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300542
Brandon Philips78718e52008-04-02 18:10:59 -0300543 dma_q->kthread = kthread_run(vivi_thread, fh, "vivi");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300544
Akinobu Mita054afee2006-12-20 10:04:00 -0300545 if (IS_ERR(dma_q->kthread)) {
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300546 printk(KERN_ERR "vivi: kernel_thread() failed\n");
Akinobu Mita054afee2006-12-20 10:04:00 -0300547 return PTR_ERR(dma_q->kthread);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300548 }
Mauro Carvalho Chehab0b600512007-01-14 08:33:24 -0300549 /* Wakes thread */
550 wake_up_interruptible(&dma_q->wq);
551
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300552 dprintk(dev, 1, "returning from %s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300553 return 0;
554}
555
Adrian Bunk972c3512006-04-27 21:06:50 -0300556static void vivi_stop_thread(struct vivi_dmaqueue *dma_q)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300557{
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300558 struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
559
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300560 dprintk(dev, 1, "%s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300561 /* shutdown control thread */
562 if (dma_q->kthread) {
563 kthread_stop(dma_q->kthread);
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300564 dma_q->kthread = NULL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300565 }
566}
567
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300568/* ------------------------------------------------------------------
569 Videobuf operations
570 ------------------------------------------------------------------*/
571static int
572buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
573{
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300574 struct vivi_fh *fh = vq->priv_data;
575 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300576
577 *size = fh->width*fh->height*2;
578
579 if (0 == *count)
580 *count = 32;
Mauro Carvalho Chehab6bb27902007-08-23 16:41:14 -0300581
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300582 while (*size * *count > vid_limit * 1024 * 1024)
583 (*count)--;
Mauro Carvalho Chehab6bb27902007-08-23 16:41:14 -0300584
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300585 dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__,
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300586 *count, *size);
Mauro Carvalho Chehab6bb27902007-08-23 16:41:14 -0300587
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300588 return 0;
589}
590
Adrian Bunk972c3512006-04-27 21:06:50 -0300591static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300592{
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300593 struct vivi_fh *fh = vq->priv_data;
594 struct vivi_dev *dev = fh->dev;
595
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300596 dprintk(dev, 1, "%s, state: %i\n", __func__, buf->vb.state);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300597
598 if (in_interrupt())
599 BUG();
600
Mauro Carvalho Chehab5a037702007-08-02 23:31:54 -0300601 videobuf_vmalloc_free(&buf->vb);
Mauro Carvalho Chehabfbde31d2008-04-13 14:57:44 -0300602 dprintk(dev, 1, "free_buffer: freed\n");
Brandon Philips0fc06862007-11-06 20:02:36 -0300603 buf->vb.state = VIDEOBUF_NEEDS_INIT;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300604}
605
606#define norm_maxw() 1024
607#define norm_maxh() 768
608static int
609buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
610 enum v4l2_field field)
611{
612 struct vivi_fh *fh = vq->priv_data;
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300613 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300614 struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
Brandon Philips78718e52008-04-02 18:10:59 -0300615 int rc;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300616
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300617 dprintk(dev, 1, "%s, field=%d\n", __func__, field);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300618
619 BUG_ON(NULL == fh->fmt);
Brandon Philips78718e52008-04-02 18:10:59 -0300620
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300621 if (fh->width < 48 || fh->width > norm_maxw() ||
622 fh->height < 32 || fh->height > norm_maxh())
623 return -EINVAL;
Brandon Philips78718e52008-04-02 18:10:59 -0300624
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300625 buf->vb.size = fh->width*fh->height*2;
626 if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
627 return -EINVAL;
628
Brandon Philips78718e52008-04-02 18:10:59 -0300629 /* These properties only change when queue is idle, see s_fmt */
630 buf->fmt = fh->fmt;
631 buf->vb.width = fh->width;
632 buf->vb.height = fh->height;
633 buf->vb.field = field;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300634
Brandon Philips0fc06862007-11-06 20:02:36 -0300635 if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300636 rc = videobuf_iolock(vq, &buf->vb, NULL);
637 if (rc < 0)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300638 goto fail;
639 }
640
Brandon Philips0fc06862007-11-06 20:02:36 -0300641 buf->vb.state = VIDEOBUF_PREPARED;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300642
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300643 return 0;
644
645fail:
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300646 free_buffer(vq, buf);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300647 return rc;
648}
649
650static void
651buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
652{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300653 struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
654 struct vivi_fh *fh = vq->priv_data;
655 struct vivi_dev *dev = fh->dev;
Brandon Philips78718e52008-04-02 18:10:59 -0300656 struct vivi_dmaqueue *vidq = &dev->vidq;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300657
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300658 dprintk(dev, 1, "%s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300659
Brandon Philips78718e52008-04-02 18:10:59 -0300660 buf->vb.state = VIDEOBUF_QUEUED;
661 list_add_tail(&buf->vb.queue, &vidq->active);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300662}
663
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300664static void buffer_release(struct videobuf_queue *vq,
665 struct videobuf_buffer *vb)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300666{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300667 struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300668 struct vivi_fh *fh = vq->priv_data;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300669 struct vivi_dev *dev = (struct vivi_dev *)fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300670
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300671 dprintk(dev, 1, "%s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300672
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300673 free_buffer(vq, buf);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300674}
675
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300676static struct videobuf_queue_ops vivi_video_qops = {
677 .buf_setup = buffer_setup,
678 .buf_prepare = buffer_prepare,
679 .buf_queue = buffer_queue,
680 .buf_release = buffer_release,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300681};
682
683/* ------------------------------------------------------------------
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300684 IOCTL vidioc handling
685 ------------------------------------------------------------------*/
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300686static int vidioc_querycap(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300687 struct v4l2_capability *cap)
688{
689 strcpy(cap->driver, "vivi");
690 strcpy(cap->card, "vivi");
691 cap->version = VIVI_VERSION;
692 cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
693 V4L2_CAP_STREAMING |
694 V4L2_CAP_READWRITE;
695 return 0;
696}
697
Hans Verkuil78b526a2008-05-28 12:16:41 -0300698static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300699 struct v4l2_fmtdesc *f)
700{
Magnus Dammd891f472008-10-14 12:47:09 -0300701 struct vivi_fmt *fmt;
702
703 if (f->index >= ARRAY_SIZE(formats))
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300704 return -EINVAL;
705
Magnus Dammd891f472008-10-14 12:47:09 -0300706 fmt = &formats[f->index];
707
708 strlcpy(f->description, fmt->name, sizeof(f->description));
709 f->pixelformat = fmt->fourcc;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300710 return 0;
711}
712
Hans Verkuil78b526a2008-05-28 12:16:41 -0300713static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300714 struct v4l2_format *f)
715{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300716 struct vivi_fh *fh = priv;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300717
718 f->fmt.pix.width = fh->width;
719 f->fmt.pix.height = fh->height;
720 f->fmt.pix.field = fh->vb_vidq.field;
721 f->fmt.pix.pixelformat = fh->fmt->fourcc;
722 f->fmt.pix.bytesperline =
723 (f->fmt.pix.width * fh->fmt->depth) >> 3;
724 f->fmt.pix.sizeimage =
725 f->fmt.pix.height * f->fmt.pix.bytesperline;
726
727 return (0);
728}
729
Hans Verkuil78b526a2008-05-28 12:16:41 -0300730static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300731 struct v4l2_format *f)
732{
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300733 struct vivi_fh *fh = priv;
734 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300735 struct vivi_fmt *fmt;
736 enum v4l2_field field;
737 unsigned int maxw, maxh;
738
Magnus Dammd891f472008-10-14 12:47:09 -0300739 fmt = get_format(f);
740 if (!fmt) {
741 dprintk(dev, 1, "Fourcc format (0x%08x) invalid.\n",
742 f->fmt.pix.pixelformat);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300743 return -EINVAL;
744 }
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300745
746 field = f->fmt.pix.field;
747
748 if (field == V4L2_FIELD_ANY) {
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300749 field = V4L2_FIELD_INTERLACED;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300750 } else if (V4L2_FIELD_INTERLACED != field) {
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300751 dprintk(dev, 1, "Field type invalid.\n");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300752 return -EINVAL;
753 }
754
755 maxw = norm_maxw();
756 maxh = norm_maxh();
757
758 f->fmt.pix.field = field;
759 if (f->fmt.pix.height < 32)
760 f->fmt.pix.height = 32;
761 if (f->fmt.pix.height > maxh)
762 f->fmt.pix.height = maxh;
763 if (f->fmt.pix.width < 48)
764 f->fmt.pix.width = 48;
765 if (f->fmt.pix.width > maxw)
766 f->fmt.pix.width = maxw;
767 f->fmt.pix.width &= ~0x03;
768 f->fmt.pix.bytesperline =
769 (f->fmt.pix.width * fmt->depth) >> 3;
770 f->fmt.pix.sizeimage =
771 f->fmt.pix.height * f->fmt.pix.bytesperline;
772
773 return 0;
774}
775
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300776/*FIXME: This seems to be generic enough to be at videodev2 */
Hans Verkuil78b526a2008-05-28 12:16:41 -0300777static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300778 struct v4l2_format *f)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300779{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300780 struct vivi_fh *fh = priv;
Brandon Philips78718e52008-04-02 18:10:59 -0300781 struct videobuf_queue *q = &fh->vb_vidq;
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300782 unsigned char r, g, b;
Magnus Dammd891f472008-10-14 12:47:09 -0300783 int k, is_yuv;
Brandon Philips78718e52008-04-02 18:10:59 -0300784
Hans Verkuil78b526a2008-05-28 12:16:41 -0300785 int ret = vidioc_try_fmt_vid_cap(file, fh, f);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300786 if (ret < 0)
787 return (ret);
788
Brandon Philips78718e52008-04-02 18:10:59 -0300789 mutex_lock(&q->vb_lock);
790
791 if (videobuf_queue_is_busy(&fh->vb_vidq)) {
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300792 dprintk(fh->dev, 1, "%s queue busy\n", __func__);
Brandon Philips78718e52008-04-02 18:10:59 -0300793 ret = -EBUSY;
794 goto out;
795 }
796
Magnus Dammd891f472008-10-14 12:47:09 -0300797 fh->fmt = get_format(f);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300798 fh->width = f->fmt.pix.width;
799 fh->height = f->fmt.pix.height;
800 fh->vb_vidq.field = f->fmt.pix.field;
801 fh->type = f->type;
802
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300803 /* precalculate color bar values to speed up rendering */
804 for (k = 0; k < 8; k++) {
805 r = bars[k][0];
806 g = bars[k][1];
807 b = bars[k][2];
Magnus Dammd891f472008-10-14 12:47:09 -0300808 is_yuv = 0;
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300809
Magnus Dammd891f472008-10-14 12:47:09 -0300810 switch (fh->fmt->fourcc) {
811 case V4L2_PIX_FMT_YUYV:
Magnus Dammfca36ba2008-10-14 12:47:25 -0300812 case V4L2_PIX_FMT_UYVY:
Magnus Dammd891f472008-10-14 12:47:09 -0300813 is_yuv = 1;
814 break;
Magnus Dammaeadb5d2008-10-14 12:47:35 -0300815 case V4L2_PIX_FMT_RGB565:
816 case V4L2_PIX_FMT_RGB565X:
817 r >>= 3;
818 g >>= 2;
819 b >>= 3;
820 break;
Magnus Dammd891f472008-10-14 12:47:09 -0300821 }
822
823 if (is_yuv) {
824 fh->bars[k][0] = TO_Y(r, g, b); /* Luma */
825 fh->bars[k][1] = TO_U(r, g, b); /* Cb */
826 fh->bars[k][2] = TO_V(r, g, b); /* Cr */
827 } else {
828 fh->bars[k][0] = r;
829 fh->bars[k][1] = g;
830 fh->bars[k][2] = b;
831 }
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300832 }
833
Brandon Philips78718e52008-04-02 18:10:59 -0300834 ret = 0;
835out:
836 mutex_unlock(&q->vb_lock);
837
838 return (ret);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300839}
840
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300841static int vidioc_reqbufs(struct file *file, void *priv,
842 struct v4l2_requestbuffers *p)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300843{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300844 struct vivi_fh *fh = priv;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300845
846 return (videobuf_reqbufs(&fh->vb_vidq, p));
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300847}
848
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300849static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300850{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300851 struct vivi_fh *fh = priv;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300852
853 return (videobuf_querybuf(&fh->vb_vidq, p));
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300854}
855
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300856static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300857{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300858 struct vivi_fh *fh = priv;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300859
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300860 return (videobuf_qbuf(&fh->vb_vidq, p));
861}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300862
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300863static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300864{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300865 struct vivi_fh *fh = priv;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300866
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300867 return (videobuf_dqbuf(&fh->vb_vidq, p,
868 file->f_flags & O_NONBLOCK));
869}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300870
Mauro Carvalho Chehab0dfa9ab2006-08-08 09:10:10 -0300871#ifdef CONFIG_VIDEO_V4L1_COMPAT
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300872static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300873{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300874 struct vivi_fh *fh = priv;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300875
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300876 return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300877}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300878#endif
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300879
Adrian Bunkdc46ace2006-06-23 06:42:44 -0300880static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300881{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300882 struct vivi_fh *fh = priv;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300883
884 if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
885 return -EINVAL;
886 if (i != fh->type)
887 return -EINVAL;
888
Brandon Philipsba32bd92007-09-27 20:55:17 -0300889 return videobuf_streamon(&fh->vb_vidq);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300890}
891
Adrian Bunkdc46ace2006-06-23 06:42:44 -0300892static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300893{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300894 struct vivi_fh *fh = priv;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300895
896 if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
897 return -EINVAL;
898 if (i != fh->type)
899 return -EINVAL;
900
Brandon Philipsba32bd92007-09-27 20:55:17 -0300901 return videobuf_streamoff(&fh->vb_vidq);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300902}
903
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300904static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300905{
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300906 return 0;
907}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300908
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300909/* only one input in this sample driver */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300910static int vidioc_enum_input(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300911 struct v4l2_input *inp)
912{
913 if (inp->index != 0)
914 return -EINVAL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300915
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300916 inp->type = V4L2_INPUT_TYPE_CAMERA;
Mauro Carvalho Chehab784c6682007-12-13 06:35:26 -0300917 inp->std = V4L2_STD_525_60;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300918 strcpy(inp->name, "Camera");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300919
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300920 return (0);
921}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300922
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300923static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300924{
925 *i = 0;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300926
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300927 return (0);
928}
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300929static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300930{
931 if (i > 0)
932 return -EINVAL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300933
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300934 return (0);
935}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300936
937 /* --- controls ---------------------------------------------- */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300938static int vidioc_queryctrl(struct file *file, void *priv,
939 struct v4l2_queryctrl *qc)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300940{
941 int i;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300942
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300943 for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
944 if (qc->id && qc->id == vivi_qctrl[i].id) {
945 memcpy(qc, &(vivi_qctrl[i]),
946 sizeof(*qc));
947 return (0);
948 }
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300949
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300950 return -EINVAL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300951}
952
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300953static int vidioc_g_ctrl(struct file *file, void *priv,
954 struct v4l2_control *ctrl)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300955{
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300956 int i;
957
958 for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
959 if (ctrl->id == vivi_qctrl[i].id) {
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300960 ctrl->value = qctl_regs[i];
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300961 return (0);
962 }
963
964 return -EINVAL;
965}
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300966static int vidioc_s_ctrl(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300967 struct v4l2_control *ctrl)
968{
969 int i;
970
971 for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
972 if (ctrl->id == vivi_qctrl[i].id) {
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300973 if (ctrl->value < vivi_qctrl[i].minimum
974 || ctrl->value > vivi_qctrl[i].maximum) {
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300975 return (-ERANGE);
976 }
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300977 qctl_regs[i] = ctrl->value;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300978 return (0);
979 }
980 return -EINVAL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300981}
982
983/* ------------------------------------------------------------------
984 File operations for the device
985 ------------------------------------------------------------------*/
986
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300987static int vivi_open(struct inode *inode, struct file *file)
988{
989 int minor = iminor(inode);
Trent Piephoa991f442007-10-10 05:37:43 -0300990 struct vivi_dev *dev;
Mauro Carvalho Chehab63b79cf2008-04-26 08:25:18 -0300991 struct vivi_fh *fh = NULL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300992 int i;
Brandon Philipsaa9dbac2008-04-02 18:10:59 -0300993 int retval = 0;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300994
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300995 printk(KERN_DEBUG "vivi: open called (minor=%d)\n", minor);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300996
Hans Verkuild56dc612008-07-30 08:43:36 -0300997 lock_kernel();
Trent Piephoa991f442007-10-10 05:37:43 -0300998 list_for_each_entry(dev, &vivi_devlist, vivi_devlist)
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -0300999 if (dev->vfd->minor == minor)
Trent Piephoa991f442007-10-10 05:37:43 -03001000 goto found;
Hans Verkuild56dc612008-07-30 08:43:36 -03001001 unlock_kernel();
Trent Piephoa991f442007-10-10 05:37:43 -03001002 return -ENODEV;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001003
Trent Piephoa991f442007-10-10 05:37:43 -03001004found:
Brandon Philipsaa9dbac2008-04-02 18:10:59 -03001005 mutex_lock(&dev->mutex);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001006 dev->users++;
1007
Brandon Philipsaa9dbac2008-04-02 18:10:59 -03001008 if (dev->users > 1) {
1009 dev->users--;
1010 retval = -EBUSY;
1011 goto unlock;
1012 }
1013
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -03001014 dprintk(dev, 1, "open minor=%d type=%s users=%d\n", minor,
Trent Piephoa991f442007-10-10 05:37:43 -03001015 v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001016
1017 /* allocate + initialize per filehandle data */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001018 fh = kzalloc(sizeof(*fh), GFP_KERNEL);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001019 if (NULL == fh) {
1020 dev->users--;
Brandon Philipsaa9dbac2008-04-02 18:10:59 -03001021 retval = -ENOMEM;
1022 goto unlock;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001023 }
Brandon Philipsaa9dbac2008-04-02 18:10:59 -03001024unlock:
1025 mutex_unlock(&dev->mutex);
Hans Verkuild56dc612008-07-30 08:43:36 -03001026 if (retval) {
1027 unlock_kernel();
Brandon Philipsaa9dbac2008-04-02 18:10:59 -03001028 return retval;
Hans Verkuild56dc612008-07-30 08:43:36 -03001029 }
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001030
1031 file->private_data = fh;
1032 fh->dev = dev;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001033
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001034 fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
Magnus Dammd891f472008-10-14 12:47:09 -03001035 fh->fmt = &formats[0];
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001036 fh->width = 640;
1037 fh->height = 480;
1038
1039 /* Put all controls at a sane state */
1040 for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001041 qctl_regs[i] = vivi_qctrl[i].default_value;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001042
1043 /* Resets frame counters */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001044 dev->h = 0;
1045 dev->m = 0;
1046 dev->s = 0;
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -03001047 dev->ms = 0;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001048 dev->mv_count = 0;
1049 dev->jiffies = jiffies;
1050 sprintf(dev->timestr, "%02d:%02d:%02d:%03d",
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -03001051 dev->h, dev->m, dev->s, dev->ms);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001052
Mauro Carvalho Chehab5a037702007-08-02 23:31:54 -03001053 videobuf_queue_vmalloc_init(&fh->vb_vidq, &vivi_video_qops,
Mauro Carvalho Chehab55862ac2007-12-13 16:13:37 -03001054 NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED,
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001055 sizeof(struct vivi_buffer), fh);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001056
Brandon Philips78718e52008-04-02 18:10:59 -03001057 vivi_start_thread(fh);
Hans Verkuild56dc612008-07-30 08:43:36 -03001058 unlock_kernel();
Brandon Philips78718e52008-04-02 18:10:59 -03001059
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001060 return 0;
1061}
1062
1063static ssize_t
1064vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
1065{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001066 struct vivi_fh *fh = file->private_data;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001067
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001068 if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
Mauro Carvalho Chehabacb09af2007-07-29 22:56:11 -03001069 return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001070 file->f_flags & O_NONBLOCK);
1071 }
1072 return 0;
1073}
1074
1075static unsigned int
1076vivi_poll(struct file *file, struct poll_table_struct *wait)
1077{
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001078 struct vivi_fh *fh = file->private_data;
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -03001079 struct vivi_dev *dev = fh->dev;
Brandon Philips85c7c70bc2007-09-27 20:55:02 -03001080 struct videobuf_queue *q = &fh->vb_vidq;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001081
Harvey Harrison7e28adb2008-04-08 23:20:00 -03001082 dprintk(dev, 1, "%s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001083
1084 if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
1085 return POLLERR;
1086
Brandon Philips85c7c70bc2007-09-27 20:55:02 -03001087 return videobuf_poll_stream(file, q, wait);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001088}
1089
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001090static int vivi_close(struct inode *inode, struct file *file)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001091{
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001092 struct vivi_fh *fh = file->private_data;
1093 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001094 struct vivi_dmaqueue *vidq = &dev->vidq;
1095
1096 int minor = iminor(inode);
1097
1098 vivi_stop_thread(vidq);
Brandon Philips053fcb62007-11-13 20:11:26 -03001099 videobuf_stop(&fh->vb_vidq);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001100 videobuf_mmap_free(&fh->vb_vidq);
1101
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001102 kfree(fh);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001103
Brandon Philipsaa9dbac2008-04-02 18:10:59 -03001104 mutex_lock(&dev->mutex);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001105 dev->users--;
Brandon Philipsaa9dbac2008-04-02 18:10:59 -03001106 mutex_unlock(&dev->mutex);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001107
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -03001108 dprintk(dev, 1, "close called (minor=%d, users=%d)\n",
1109 minor, dev->users);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001110
1111 return 0;
1112}
1113
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001114static int vivi_release(void)
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001115{
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001116 struct vivi_dev *dev;
1117 struct list_head *list;
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001118
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001119 while (!list_empty(&vivi_devlist)) {
1120 list = vivi_devlist.next;
1121 list_del(list);
1122 dev = list_entry(list, struct vivi_dev, vivi_devlist);
1123
Carl Karsten745271a2008-06-10 00:02:32 -03001124 if (-1 != dev->vfd->minor) {
Adrian Bunk8da9bae2008-09-03 17:12:25 -03001125 printk(KERN_INFO "%s: unregistering /dev/video%d\n",
1126 VIVI_MODULE_NAME, dev->vfd->minor);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001127 video_unregister_device(dev->vfd);
Carl Karsten745271a2008-06-10 00:02:32 -03001128 } else {
Adrian Bunk8da9bae2008-09-03 17:12:25 -03001129 printk(KERN_INFO "%s: releasing /dev/video%d\n",
Mauro Carvalho Chehab584ce482008-06-10 15:21:49 -03001130 VIVI_MODULE_NAME, dev->vfd->minor);
Adrian Bunk8da9bae2008-09-03 17:12:25 -03001131 video_device_release(dev->vfd);
Carl Karsten745271a2008-06-10 00:02:32 -03001132 }
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001133
1134 kfree(dev);
1135 }
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001136
1137 return 0;
1138}
1139
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001140static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001141{
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -03001142 struct vivi_fh *fh = file->private_data;
1143 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001144 int ret;
1145
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -03001146 dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001147
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001148 ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001149
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -03001150 dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n",
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001151 (unsigned long)vma->vm_start,
1152 (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
1153 ret);
1154
1155 return ret;
1156}
1157
Arjan van de Venfa027c22007-02-12 00:55:33 -08001158static const struct file_operations vivi_fops = {
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001159 .owner = THIS_MODULE,
1160 .open = vivi_open,
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001161 .release = vivi_close,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001162 .read = vivi_read,
1163 .poll = vivi_poll,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001164 .ioctl = video_ioctl2, /* V4L2 ioctl handler */
Mauro Carvalho Chehabfbde31d2008-04-13 14:57:44 -03001165 .compat_ioctl = v4l_compat_ioctl32,
Mauro Carvalho Chehab5a037702007-08-02 23:31:54 -03001166 .mmap = vivi_mmap,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001167 .llseek = no_llseek,
1168};
1169
Hans Verkuila3998102008-07-21 02:57:38 -03001170static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001171 .vidioc_querycap = vidioc_querycap,
Hans Verkuil78b526a2008-05-28 12:16:41 -03001172 .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
1173 .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
1174 .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
1175 .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001176 .vidioc_reqbufs = vidioc_reqbufs,
1177 .vidioc_querybuf = vidioc_querybuf,
1178 .vidioc_qbuf = vidioc_qbuf,
1179 .vidioc_dqbuf = vidioc_dqbuf,
1180 .vidioc_s_std = vidioc_s_std,
1181 .vidioc_enum_input = vidioc_enum_input,
1182 .vidioc_g_input = vidioc_g_input,
1183 .vidioc_s_input = vidioc_s_input,
1184 .vidioc_queryctrl = vidioc_queryctrl,
1185 .vidioc_g_ctrl = vidioc_g_ctrl,
1186 .vidioc_s_ctrl = vidioc_s_ctrl,
1187 .vidioc_streamon = vidioc_streamon,
1188 .vidioc_streamoff = vidioc_streamoff,
Mauro Carvalho Chehab0dfa9ab2006-08-08 09:10:10 -03001189#ifdef CONFIG_VIDEO_V4L1_COMPAT
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001190 .vidiocgmbuf = vidiocgmbuf,
1191#endif
Hans Verkuila3998102008-07-21 02:57:38 -03001192};
1193
1194static struct video_device vivi_template = {
1195 .name = "vivi",
Hans Verkuila3998102008-07-21 02:57:38 -03001196 .fops = &vivi_fops,
1197 .ioctl_ops = &vivi_ioctl_ops,
1198 .minor = -1,
1199 .release = video_device_release,
1200
Mauro Carvalho Chehab784c6682007-12-13 06:35:26 -03001201 .tvnorms = V4L2_STD_525_60,
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -03001202 .current_norm = V4L2_STD_NTSC_M,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001203};
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001204/* -----------------------------------------------------------------
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001205 Initialization and module stuff
1206 ------------------------------------------------------------------*/
1207
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001208/* This routine allocates from 1 to n_devs virtual drivers.
1209
1210 The real maximum number of virtual drivers will depend on how many drivers
1211 will succeed. This is limited to the maximum number of devices that
1212 videodev supports. Since there are 64 minors for video grabbers, this is
1213 currently the theoretical maximum limit. However, a further limit does
1214 exist at videodev that forbids any driver to register more than 32 video
1215 grabbers.
1216 */
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001217static int __init vivi_init(void)
1218{
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001219 int ret = -ENOMEM, i;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001220 struct vivi_dev *dev;
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001221 struct video_device *vfd;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001222
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001223 if (n_devs <= 0)
1224 n_devs = 1;
1225
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001226 for (i = 0; i < n_devs; i++) {
1227 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001228 if (!dev)
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001229 break;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001230
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001231 /* init video dma queues */
1232 INIT_LIST_HEAD(&dev->vidq.active);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001233 init_waitqueue_head(&dev->vidq.wq);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001234
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001235 /* initialize locks */
Mauro Carvalho Chehab55862ac2007-12-13 16:13:37 -03001236 spin_lock_init(&dev->slock);
Brandon Philipsaa9dbac2008-04-02 18:10:59 -03001237 mutex_init(&dev->mutex);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001238
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001239 vfd = video_device_alloc();
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001240 if (!vfd) {
1241 kfree(dev);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001242 break;
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001243 }
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001244
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001245 *vfd = vivi_template;
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001246
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001247 ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001248 if (ret < 0) {
1249 video_device_release(vfd);
1250 kfree(dev);
1251
1252 /* If some registers succeeded, keep driver */
1253 if (i)
1254 ret = 0;
1255
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001256 break;
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001257 }
1258
1259 /* Now that everything is fine, let's add it to device list */
1260 list_add_tail(&dev->vivi_devlist, &vivi_devlist);
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001261
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001262 snprintf(vfd->name, sizeof(vfd->name), "%s (%i)",
1263 vivi_template.name, vfd->minor);
1264
1265 if (video_nr >= 0)
1266 video_nr++;
1267
1268 dev->vfd = vfd;
Carl Karsten745271a2008-06-10 00:02:32 -03001269 printk(KERN_INFO "%s: V4L2 device registered as /dev/video%d\n",
Mauro Carvalho Chehab584ce482008-06-10 15:21:49 -03001270 VIVI_MODULE_NAME, vfd->minor);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001271 }
1272
1273 if (ret < 0) {
1274 vivi_release();
1275 printk(KERN_INFO "Error %d while loading vivi driver\n", ret);
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001276 } else {
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001277 printk(KERN_INFO "Video Technology Magazine Virtual Video "
Carl Karsten745271a2008-06-10 00:02:32 -03001278 "Capture Board ver %u.%u.%u successfully loaded.\n",
1279 (VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF,
1280 VIVI_VERSION & 0xFF);
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001281
1282 /* n_devs will reflect the actual number of allocated devices */
1283 n_devs = i;
1284 }
1285
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001286 return ret;
1287}
1288
1289static void __exit vivi_exit(void)
1290{
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001291 vivi_release();
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001292}
1293
1294module_init(vivi_init);
1295module_exit(vivi_exit);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001296
1297MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
1298MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
1299MODULE_LICENSE("Dual BSD/GPL");
1300
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001301module_param(video_nr, uint, 0444);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001302MODULE_PARM_DESC(video_nr, "video iminor start number");
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001303
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001304module_param(n_devs, uint, 0444);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001305MODULE_PARM_DESC(n_devs, "number of video devices to create");
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001306
Mauro Carvalho Chehab8996b3f2007-12-13 06:36:22 -03001307module_param_named(debug, vivi_template.debug, int, 0444);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001308MODULE_PARM_DESC(debug, "activates debug info");
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001309
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001310module_param(vid_limit, int, 0644);
1311MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");