blob: 2a6ebc126c09ad6c7aa18acf271a516e740ed610 [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 },
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300142};
143
Magnus Dammd891f472008-10-14 12:47:09 -0300144static struct vivi_fmt *get_format(struct v4l2_format *f)
145{
146 struct vivi_fmt *fmt;
147 unsigned int k;
148
149 for (k = 0; k < ARRAY_SIZE(formats); k++) {
150 fmt = &formats[k];
151 if (fmt->fourcc == f->fmt.pix.pixelformat)
152 break;
153 }
154
155 if (k == ARRAY_SIZE(formats))
156 return NULL;
157
158 return &formats[k];
159}
160
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300161struct sg_to_addr {
162 int pos;
163 struct scatterlist *sg;
164};
165
166/* buffer for one video frame */
167struct vivi_buffer {
168 /* common v4l buffer stuff -- must be first */
169 struct videobuf_buffer vb;
170
171 struct vivi_fmt *fmt;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300172};
173
174struct vivi_dmaqueue {
175 struct list_head active;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300176
177 /* thread for generating video stream*/
178 struct task_struct *kthread;
179 wait_queue_head_t wq;
180 /* Counters to control fps rate */
181 int frame;
182 int ini_jiffies;
183};
184
185static LIST_HEAD(vivi_devlist);
186
187struct vivi_dev {
188 struct list_head vivi_devlist;
189
Mauro Carvalho Chehab55862ac2007-12-13 16:13:37 -0300190 spinlock_t slock;
Brandon Philipsaa9dbac2008-04-02 18:10:59 -0300191 struct mutex mutex;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300192
193 int users;
194
195 /* various device info */
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -0300196 struct video_device *vfd;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300197
198 struct vivi_dmaqueue vidq;
199
200 /* Several counters */
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -0300201 int h, m, s, ms;
202 unsigned long jiffies;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300203 char timestr[13];
Mauro Carvalho Chehab025341d2007-12-10 04:43:38 -0300204
205 int mv_count; /* Controls bars movement */
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300206};
207
208struct vivi_fh {
209 struct vivi_dev *dev;
210
211 /* video capture */
212 struct vivi_fmt *fmt;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300213 unsigned int width, height;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300214 struct videobuf_queue vb_vidq;
215
216 enum v4l2_buf_type type;
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300217 unsigned char bars[8][3];
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300218};
219
220/* ------------------------------------------------------------------
221 DMA and thread functions
222 ------------------------------------------------------------------*/
223
224/* Bars and Colors should match positions */
225
226enum colors {
227 WHITE,
228 AMBAR,
229 CYAN,
230 GREEN,
231 MAGENTA,
232 RED,
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300233 BLUE,
234 BLACK,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300235};
236
237static u8 bars[8][3] = {
238 /* R G B */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300239 {204, 204, 204}, /* white */
240 {208, 208, 0}, /* ambar */
241 { 0, 206, 206}, /* cyan */
242 { 0, 239, 0}, /* green */
243 {239, 0, 239}, /* magenta */
244 {205, 0, 0}, /* red */
245 { 0, 0, 255}, /* blue */
246 { 0, 0, 0}, /* black */
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300247};
248
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300249#define TO_Y(r, g, b) \
250 (((16829 * r + 33039 * g + 6416 * b + 32768) >> 16) + 16)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300251/* RGB to V(Cr) Color transform */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300252#define TO_V(r, g, b) \
253 (((28784 * r - 24103 * g - 4681 * b + 32768) >> 16) + 128)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300254/* RGB to U(Cb) Color transform */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300255#define TO_U(r, g, b) \
256 (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300257
258#define TSTAMP_MIN_Y 24
259#define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
260#define TSTAMP_MIN_X 64
261
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300262static void gen_twopix(struct vivi_fh *fh, unsigned char *buf, int colorpos)
263{
264 unsigned char r_y, g_u, b_v;
265 unsigned char *p;
266 int color;
267
268 r_y = fh->bars[colorpos][0]; /* R or precalculated Y */
269 g_u = fh->bars[colorpos][1]; /* G or precalculated U */
270 b_v = fh->bars[colorpos][2]; /* B or precalculated V */
271
272 for (color = 0; color < 4; color++) {
273 p = buf + color;
274
Magnus Dammd891f472008-10-14 12:47:09 -0300275 switch (fh->fmt->fourcc) {
276 case V4L2_PIX_FMT_YUYV:
277 switch (color) {
278 case 0:
279 case 2:
280 *p = r_y;
281 break;
282 case 1:
283 *p = g_u;
284 break;
285 case 3:
286 *p = b_v;
287 break;
288 }
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300289 break;
Magnus Dammfca36ba2008-10-14 12:47:25 -0300290 case V4L2_PIX_FMT_UYVY:
291 switch (color) {
292 case 1:
293 case 3:
294 *p = r_y;
295 break;
296 case 0:
297 *p = g_u;
298 break;
299 case 2:
300 *p = b_v;
301 break;
302 }
303 break;
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300304 }
305 }
306}
307
308static void gen_line(struct vivi_fh *fh, char *basep, int inipos, int wmax,
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300309 int hmax, int line, int count, char *timestr)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300310{
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300311 int w, i, j;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300312 int pos = inipos;
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300313 char *s;
314 u8 chr;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300315
316 /* We will just duplicate the second pixel at the packet */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300317 wmax /= 2;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300318
319 /* Generate a standard color bar pattern */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300320 for (w = 0; w < wmax; w++) {
321 int colorpos = ((w + count) * 8/(wmax + 1)) % 8;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300322
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300323 gen_twopix(fh, basep + pos, colorpos);
324 pos += 4; /* only 16 bpp supported for now */
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300325 }
326
327 /* Checks if it is possible to show timestamp */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300328 if (TSTAMP_MAX_Y >= hmax)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300329 goto end;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300330 if (TSTAMP_MIN_X + strlen(timestr) >= wmax)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300331 goto end;
332
333 /* Print stream time */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300334 if (line >= TSTAMP_MIN_Y && line <= TSTAMP_MAX_Y) {
335 j = TSTAMP_MIN_X;
336 for (s = timestr; *s; s++) {
337 chr = rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y];
338 for (i = 0; i < 7; i++) {
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300339 pos = inipos + j * 2;
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300340 /* Draw white font on black background */
341 if (chr & 1 << (7 - i))
342 gen_twopix(fh, basep + pos, WHITE);
343 else
344 gen_twopix(fh, basep + pos, BLACK);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300345 j++;
346 }
347 }
348 }
349
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300350end:
Mauro Carvalho Chehabb50e7fe2007-01-25 05:00:01 -0300351 return;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300352}
Brandon Philips78718e52008-04-02 18:10:59 -0300353
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300354static void vivi_fillbuff(struct vivi_fh *fh, struct vivi_buffer *buf)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300355{
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300356 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300357 int h , pos = 0;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300358 int hmax = buf->vb.height;
359 int wmax = buf->vb.width;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300360 struct timeval ts;
Marcin Slusarz5c554e62008-06-22 09:11:40 -0300361 char *tmpbuf;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300362 void *vbuf = videobuf_to_vmalloc(&buf->vb);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300363
Marcin Slusarz5c554e62008-06-22 09:11:40 -0300364 if (!vbuf)
Mauro Carvalho Chehab5a037702007-08-02 23:31:54 -0300365 return;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300366
Marcin Slusarz5c554e62008-06-22 09:11:40 -0300367 tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC);
368 if (!tmpbuf)
Brandon Philips78718e52008-04-02 18:10:59 -0300369 return;
370
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300371 for (h = 0; h < hmax; h++) {
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300372 gen_line(fh, tmpbuf, 0, wmax, hmax, h, dev->mv_count,
Mauro Carvalho Chehab3bef5e42007-09-22 02:01:33 -0300373 dev->timestr);
Brandon Philips78718e52008-04-02 18:10:59 -0300374 memcpy(vbuf + pos, tmpbuf, wmax * 2);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300375 pos += wmax*2;
376 }
377
Mauro Carvalho Chehab025341d2007-12-10 04:43:38 -0300378 dev->mv_count++;
Mauro Carvalho Chehab3bef5e42007-09-22 02:01:33 -0300379
Mauro Carvalho Chehab5a037702007-08-02 23:31:54 -0300380 kfree(tmpbuf);
381
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300382 /* Updates stream time */
383
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -0300384 dev->ms += jiffies_to_msecs(jiffies-dev->jiffies);
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300385 dev->jiffies = jiffies;
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -0300386 if (dev->ms >= 1000) {
387 dev->ms -= 1000;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300388 dev->s++;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300389 if (dev->s >= 60) {
390 dev->s -= 60;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300391 dev->m++;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300392 if (dev->m > 60) {
393 dev->m -= 60;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300394 dev->h++;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300395 if (dev->h > 24)
396 dev->h -= 24;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300397 }
398 }
399 }
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300400 sprintf(dev->timestr, "%02d:%02d:%02d:%03d",
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -0300401 dev->h, dev->m, dev->s, dev->ms);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300402
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300403 dprintk(dev, 2, "vivifill at %s: Buffer 0x%08lx size= %d\n",
404 dev->timestr, (unsigned long)tmpbuf, pos);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300405
406 /* Advice that buffer was filled */
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300407 buf->vb.field_count++;
408 do_gettimeofday(&ts);
409 buf->vb.ts = ts;
Brandon Philips78718e52008-04-02 18:10:59 -0300410 buf->vb.state = VIDEOBUF_DONE;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300411}
412
Brandon Philips78718e52008-04-02 18:10:59 -0300413static void vivi_thread_tick(struct vivi_fh *fh)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300414{
Brandon Philips78718e52008-04-02 18:10:59 -0300415 struct vivi_buffer *buf;
416 struct vivi_dev *dev = fh->dev;
417 struct vivi_dmaqueue *dma_q = &dev->vidq;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300418
Brandon Philips78718e52008-04-02 18:10:59 -0300419 unsigned long flags = 0;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300420
Brandon Philips78718e52008-04-02 18:10:59 -0300421 dprintk(dev, 1, "Thread tick\n");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300422
Brandon Philips78718e52008-04-02 18:10:59 -0300423 spin_lock_irqsave(&dev->slock, flags);
424 if (list_empty(&dma_q->active)) {
425 dprintk(dev, 1, "No active queue to serve\n");
426 goto unlock;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300427 }
Brandon Philips78718e52008-04-02 18:10:59 -0300428
429 buf = list_entry(dma_q->active.next,
430 struct vivi_buffer, vb.queue);
431
432 /* Nobody is waiting on this buffer, return */
433 if (!waitqueue_active(&buf->vb.done))
434 goto unlock;
435
436 list_del(&buf->vb.queue);
437
438 do_gettimeofday(&buf->vb.ts);
439
440 /* Fill buffer */
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300441 vivi_fillbuff(fh, buf);
Brandon Philips78718e52008-04-02 18:10:59 -0300442 dprintk(dev, 1, "filled buffer %p\n", buf);
443
444 wake_up(&buf->vb.done);
445 dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i);
446unlock:
447 spin_unlock_irqrestore(&dev->slock, flags);
448 return;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300449}
450
Mauro Carvalho Chehab6594ad82007-12-13 16:15:41 -0300451#define frames_to_ms(frames) \
452 ((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR)
453
Brandon Philips78718e52008-04-02 18:10:59 -0300454static void vivi_sleep(struct vivi_fh *fh)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300455{
Brandon Philips78718e52008-04-02 18:10:59 -0300456 struct vivi_dev *dev = fh->dev;
457 struct vivi_dmaqueue *dma_q = &dev->vidq;
458 int timeout;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300459 DECLARE_WAITQUEUE(wait, current);
460
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300461 dprintk(dev, 1, "%s dma_q=0x%08lx\n", __func__,
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300462 (unsigned long)dma_q);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300463
464 add_wait_queue(&dma_q->wq, &wait);
Mauro Carvalho Chehab6594ad82007-12-13 16:15:41 -0300465 if (kthread_should_stop())
466 goto stop_task;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300467
Mauro Carvalho Chehab6594ad82007-12-13 16:15:41 -0300468 /* Calculate time to wake up */
Brandon Philips78718e52008-04-02 18:10:59 -0300469 timeout = msecs_to_jiffies(frames_to_ms(1));
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300470
Brandon Philips78718e52008-04-02 18:10:59 -0300471 vivi_thread_tick(fh);
Mauro Carvalho Chehab6594ad82007-12-13 16:15:41 -0300472
473 schedule_timeout_interruptible(timeout);
474
475stop_task:
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300476 remove_wait_queue(&dma_q->wq, &wait);
477 try_to_freeze();
478}
479
Adrian Bunk972c3512006-04-27 21:06:50 -0300480static int vivi_thread(void *data)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300481{
Brandon Philips78718e52008-04-02 18:10:59 -0300482 struct vivi_fh *fh = data;
483 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300484
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300485 dprintk(dev, 1, "thread started\n");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300486
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700487 set_freezable();
Mauro Carvalho Chehab0b600512007-01-14 08:33:24 -0300488
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300489 for (;;) {
Brandon Philips78718e52008-04-02 18:10:59 -0300490 vivi_sleep(fh);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300491
492 if (kthread_should_stop())
493 break;
494 }
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300495 dprintk(dev, 1, "thread: exit\n");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300496 return 0;
497}
498
Brandon Philips78718e52008-04-02 18:10:59 -0300499static int vivi_start_thread(struct vivi_fh *fh)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300500{
Brandon Philips78718e52008-04-02 18:10:59 -0300501 struct vivi_dev *dev = fh->dev;
502 struct vivi_dmaqueue *dma_q = &dev->vidq;
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300503
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300504 dma_q->frame = 0;
505 dma_q->ini_jiffies = jiffies;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300506
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300507 dprintk(dev, 1, "%s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300508
Brandon Philips78718e52008-04-02 18:10:59 -0300509 dma_q->kthread = kthread_run(vivi_thread, fh, "vivi");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300510
Akinobu Mita054afee2006-12-20 10:04:00 -0300511 if (IS_ERR(dma_q->kthread)) {
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300512 printk(KERN_ERR "vivi: kernel_thread() failed\n");
Akinobu Mita054afee2006-12-20 10:04:00 -0300513 return PTR_ERR(dma_q->kthread);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300514 }
Mauro Carvalho Chehab0b600512007-01-14 08:33:24 -0300515 /* Wakes thread */
516 wake_up_interruptible(&dma_q->wq);
517
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300518 dprintk(dev, 1, "returning from %s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300519 return 0;
520}
521
Adrian Bunk972c3512006-04-27 21:06:50 -0300522static void vivi_stop_thread(struct vivi_dmaqueue *dma_q)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300523{
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300524 struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
525
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300526 dprintk(dev, 1, "%s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300527 /* shutdown control thread */
528 if (dma_q->kthread) {
529 kthread_stop(dma_q->kthread);
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300530 dma_q->kthread = NULL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300531 }
532}
533
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300534/* ------------------------------------------------------------------
535 Videobuf operations
536 ------------------------------------------------------------------*/
537static int
538buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
539{
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300540 struct vivi_fh *fh = vq->priv_data;
541 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300542
543 *size = fh->width*fh->height*2;
544
545 if (0 == *count)
546 *count = 32;
Mauro Carvalho Chehab6bb27902007-08-23 16:41:14 -0300547
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300548 while (*size * *count > vid_limit * 1024 * 1024)
549 (*count)--;
Mauro Carvalho Chehab6bb27902007-08-23 16:41:14 -0300550
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300551 dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__,
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300552 *count, *size);
Mauro Carvalho Chehab6bb27902007-08-23 16:41:14 -0300553
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300554 return 0;
555}
556
Adrian Bunk972c3512006-04-27 21:06:50 -0300557static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300558{
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300559 struct vivi_fh *fh = vq->priv_data;
560 struct vivi_dev *dev = fh->dev;
561
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300562 dprintk(dev, 1, "%s, state: %i\n", __func__, buf->vb.state);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300563
564 if (in_interrupt())
565 BUG();
566
Mauro Carvalho Chehab5a037702007-08-02 23:31:54 -0300567 videobuf_vmalloc_free(&buf->vb);
Mauro Carvalho Chehabfbde31d2008-04-13 14:57:44 -0300568 dprintk(dev, 1, "free_buffer: freed\n");
Brandon Philips0fc06862007-11-06 20:02:36 -0300569 buf->vb.state = VIDEOBUF_NEEDS_INIT;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300570}
571
572#define norm_maxw() 1024
573#define norm_maxh() 768
574static int
575buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
576 enum v4l2_field field)
577{
578 struct vivi_fh *fh = vq->priv_data;
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300579 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300580 struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
Brandon Philips78718e52008-04-02 18:10:59 -0300581 int rc;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300582
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300583 dprintk(dev, 1, "%s, field=%d\n", __func__, field);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300584
585 BUG_ON(NULL == fh->fmt);
Brandon Philips78718e52008-04-02 18:10:59 -0300586
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300587 if (fh->width < 48 || fh->width > norm_maxw() ||
588 fh->height < 32 || fh->height > norm_maxh())
589 return -EINVAL;
Brandon Philips78718e52008-04-02 18:10:59 -0300590
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300591 buf->vb.size = fh->width*fh->height*2;
592 if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
593 return -EINVAL;
594
Brandon Philips78718e52008-04-02 18:10:59 -0300595 /* These properties only change when queue is idle, see s_fmt */
596 buf->fmt = fh->fmt;
597 buf->vb.width = fh->width;
598 buf->vb.height = fh->height;
599 buf->vb.field = field;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300600
Brandon Philips0fc06862007-11-06 20:02:36 -0300601 if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300602 rc = videobuf_iolock(vq, &buf->vb, NULL);
603 if (rc < 0)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300604 goto fail;
605 }
606
Brandon Philips0fc06862007-11-06 20:02:36 -0300607 buf->vb.state = VIDEOBUF_PREPARED;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300608
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300609 return 0;
610
611fail:
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300612 free_buffer(vq, buf);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300613 return rc;
614}
615
616static void
617buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
618{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300619 struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
620 struct vivi_fh *fh = vq->priv_data;
621 struct vivi_dev *dev = fh->dev;
Brandon Philips78718e52008-04-02 18:10:59 -0300622 struct vivi_dmaqueue *vidq = &dev->vidq;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300623
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300624 dprintk(dev, 1, "%s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300625
Brandon Philips78718e52008-04-02 18:10:59 -0300626 buf->vb.state = VIDEOBUF_QUEUED;
627 list_add_tail(&buf->vb.queue, &vidq->active);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300628}
629
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300630static void buffer_release(struct videobuf_queue *vq,
631 struct videobuf_buffer *vb)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300632{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300633 struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300634 struct vivi_fh *fh = vq->priv_data;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300635 struct vivi_dev *dev = (struct vivi_dev *)fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300636
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300637 dprintk(dev, 1, "%s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300638
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300639 free_buffer(vq, buf);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300640}
641
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300642static struct videobuf_queue_ops vivi_video_qops = {
643 .buf_setup = buffer_setup,
644 .buf_prepare = buffer_prepare,
645 .buf_queue = buffer_queue,
646 .buf_release = buffer_release,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300647};
648
649/* ------------------------------------------------------------------
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300650 IOCTL vidioc handling
651 ------------------------------------------------------------------*/
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300652static int vidioc_querycap(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300653 struct v4l2_capability *cap)
654{
655 strcpy(cap->driver, "vivi");
656 strcpy(cap->card, "vivi");
657 cap->version = VIVI_VERSION;
658 cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
659 V4L2_CAP_STREAMING |
660 V4L2_CAP_READWRITE;
661 return 0;
662}
663
Hans Verkuil78b526a2008-05-28 12:16:41 -0300664static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300665 struct v4l2_fmtdesc *f)
666{
Magnus Dammd891f472008-10-14 12:47:09 -0300667 struct vivi_fmt *fmt;
668
669 if (f->index >= ARRAY_SIZE(formats))
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300670 return -EINVAL;
671
Magnus Dammd891f472008-10-14 12:47:09 -0300672 fmt = &formats[f->index];
673
674 strlcpy(f->description, fmt->name, sizeof(f->description));
675 f->pixelformat = fmt->fourcc;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300676 return 0;
677}
678
Hans Verkuil78b526a2008-05-28 12:16:41 -0300679static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300680 struct v4l2_format *f)
681{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300682 struct vivi_fh *fh = priv;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300683
684 f->fmt.pix.width = fh->width;
685 f->fmt.pix.height = fh->height;
686 f->fmt.pix.field = fh->vb_vidq.field;
687 f->fmt.pix.pixelformat = fh->fmt->fourcc;
688 f->fmt.pix.bytesperline =
689 (f->fmt.pix.width * fh->fmt->depth) >> 3;
690 f->fmt.pix.sizeimage =
691 f->fmt.pix.height * f->fmt.pix.bytesperline;
692
693 return (0);
694}
695
Hans Verkuil78b526a2008-05-28 12:16:41 -0300696static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300697 struct v4l2_format *f)
698{
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300699 struct vivi_fh *fh = priv;
700 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300701 struct vivi_fmt *fmt;
702 enum v4l2_field field;
703 unsigned int maxw, maxh;
704
Magnus Dammd891f472008-10-14 12:47:09 -0300705 fmt = get_format(f);
706 if (!fmt) {
707 dprintk(dev, 1, "Fourcc format (0x%08x) invalid.\n",
708 f->fmt.pix.pixelformat);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300709 return -EINVAL;
710 }
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300711
712 field = f->fmt.pix.field;
713
714 if (field == V4L2_FIELD_ANY) {
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300715 field = V4L2_FIELD_INTERLACED;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300716 } else if (V4L2_FIELD_INTERLACED != field) {
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300717 dprintk(dev, 1, "Field type invalid.\n");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300718 return -EINVAL;
719 }
720
721 maxw = norm_maxw();
722 maxh = norm_maxh();
723
724 f->fmt.pix.field = field;
725 if (f->fmt.pix.height < 32)
726 f->fmt.pix.height = 32;
727 if (f->fmt.pix.height > maxh)
728 f->fmt.pix.height = maxh;
729 if (f->fmt.pix.width < 48)
730 f->fmt.pix.width = 48;
731 if (f->fmt.pix.width > maxw)
732 f->fmt.pix.width = maxw;
733 f->fmt.pix.width &= ~0x03;
734 f->fmt.pix.bytesperline =
735 (f->fmt.pix.width * fmt->depth) >> 3;
736 f->fmt.pix.sizeimage =
737 f->fmt.pix.height * f->fmt.pix.bytesperline;
738
739 return 0;
740}
741
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300742/*FIXME: This seems to be generic enough to be at videodev2 */
Hans Verkuil78b526a2008-05-28 12:16:41 -0300743static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300744 struct v4l2_format *f)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300745{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300746 struct vivi_fh *fh = priv;
Brandon Philips78718e52008-04-02 18:10:59 -0300747 struct videobuf_queue *q = &fh->vb_vidq;
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300748 unsigned char r, g, b;
Magnus Dammd891f472008-10-14 12:47:09 -0300749 int k, is_yuv;
Brandon Philips78718e52008-04-02 18:10:59 -0300750
Hans Verkuil78b526a2008-05-28 12:16:41 -0300751 int ret = vidioc_try_fmt_vid_cap(file, fh, f);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300752 if (ret < 0)
753 return (ret);
754
Brandon Philips78718e52008-04-02 18:10:59 -0300755 mutex_lock(&q->vb_lock);
756
757 if (videobuf_queue_is_busy(&fh->vb_vidq)) {
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300758 dprintk(fh->dev, 1, "%s queue busy\n", __func__);
Brandon Philips78718e52008-04-02 18:10:59 -0300759 ret = -EBUSY;
760 goto out;
761 }
762
Magnus Dammd891f472008-10-14 12:47:09 -0300763 fh->fmt = get_format(f);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300764 fh->width = f->fmt.pix.width;
765 fh->height = f->fmt.pix.height;
766 fh->vb_vidq.field = f->fmt.pix.field;
767 fh->type = f->type;
768
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300769 /* precalculate color bar values to speed up rendering */
770 for (k = 0; k < 8; k++) {
771 r = bars[k][0];
772 g = bars[k][1];
773 b = bars[k][2];
Magnus Dammd891f472008-10-14 12:47:09 -0300774 is_yuv = 0;
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300775
Magnus Dammd891f472008-10-14 12:47:09 -0300776 switch (fh->fmt->fourcc) {
777 case V4L2_PIX_FMT_YUYV:
Magnus Dammfca36ba2008-10-14 12:47:25 -0300778 case V4L2_PIX_FMT_UYVY:
Magnus Dammd891f472008-10-14 12:47:09 -0300779 is_yuv = 1;
780 break;
781 }
782
783 if (is_yuv) {
784 fh->bars[k][0] = TO_Y(r, g, b); /* Luma */
785 fh->bars[k][1] = TO_U(r, g, b); /* Cb */
786 fh->bars[k][2] = TO_V(r, g, b); /* Cr */
787 } else {
788 fh->bars[k][0] = r;
789 fh->bars[k][1] = g;
790 fh->bars[k][2] = b;
791 }
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300792 }
793
Brandon Philips78718e52008-04-02 18:10:59 -0300794 ret = 0;
795out:
796 mutex_unlock(&q->vb_lock);
797
798 return (ret);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300799}
800
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300801static int vidioc_reqbufs(struct file *file, void *priv,
802 struct v4l2_requestbuffers *p)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300803{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300804 struct vivi_fh *fh = priv;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300805
806 return (videobuf_reqbufs(&fh->vb_vidq, p));
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300807}
808
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300809static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300810{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300811 struct vivi_fh *fh = priv;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300812
813 return (videobuf_querybuf(&fh->vb_vidq, p));
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300814}
815
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300816static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300817{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300818 struct vivi_fh *fh = priv;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300819
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300820 return (videobuf_qbuf(&fh->vb_vidq, p));
821}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300822
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300823static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300824{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300825 struct vivi_fh *fh = priv;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300826
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300827 return (videobuf_dqbuf(&fh->vb_vidq, p,
828 file->f_flags & O_NONBLOCK));
829}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300830
Mauro Carvalho Chehab0dfa9ab2006-08-08 09:10:10 -0300831#ifdef CONFIG_VIDEO_V4L1_COMPAT
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300832static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300833{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300834 struct vivi_fh *fh = priv;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300835
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300836 return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300837}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300838#endif
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300839
Adrian Bunkdc46ace2006-06-23 06:42:44 -0300840static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300841{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300842 struct vivi_fh *fh = priv;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300843
844 if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
845 return -EINVAL;
846 if (i != fh->type)
847 return -EINVAL;
848
Brandon Philipsba32bd92007-09-27 20:55:17 -0300849 return videobuf_streamon(&fh->vb_vidq);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300850}
851
Adrian Bunkdc46ace2006-06-23 06:42:44 -0300852static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300853{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300854 struct vivi_fh *fh = priv;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300855
856 if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
857 return -EINVAL;
858 if (i != fh->type)
859 return -EINVAL;
860
Brandon Philipsba32bd92007-09-27 20:55:17 -0300861 return videobuf_streamoff(&fh->vb_vidq);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300862}
863
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300864static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300865{
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300866 return 0;
867}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300868
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300869/* only one input in this sample driver */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300870static int vidioc_enum_input(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300871 struct v4l2_input *inp)
872{
873 if (inp->index != 0)
874 return -EINVAL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300875
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300876 inp->type = V4L2_INPUT_TYPE_CAMERA;
Mauro Carvalho Chehab784c6682007-12-13 06:35:26 -0300877 inp->std = V4L2_STD_525_60;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300878 strcpy(inp->name, "Camera");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300879
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300880 return (0);
881}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300882
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300883static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300884{
885 *i = 0;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300886
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300887 return (0);
888}
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300889static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300890{
891 if (i > 0)
892 return -EINVAL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300893
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300894 return (0);
895}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300896
897 /* --- controls ---------------------------------------------- */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300898static int vidioc_queryctrl(struct file *file, void *priv,
899 struct v4l2_queryctrl *qc)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300900{
901 int i;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300902
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300903 for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
904 if (qc->id && qc->id == vivi_qctrl[i].id) {
905 memcpy(qc, &(vivi_qctrl[i]),
906 sizeof(*qc));
907 return (0);
908 }
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300909
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300910 return -EINVAL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300911}
912
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300913static int vidioc_g_ctrl(struct file *file, void *priv,
914 struct v4l2_control *ctrl)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300915{
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300916 int i;
917
918 for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
919 if (ctrl->id == vivi_qctrl[i].id) {
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300920 ctrl->value = qctl_regs[i];
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300921 return (0);
922 }
923
924 return -EINVAL;
925}
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300926static int vidioc_s_ctrl(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300927 struct v4l2_control *ctrl)
928{
929 int i;
930
931 for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
932 if (ctrl->id == vivi_qctrl[i].id) {
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300933 if (ctrl->value < vivi_qctrl[i].minimum
934 || ctrl->value > vivi_qctrl[i].maximum) {
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300935 return (-ERANGE);
936 }
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300937 qctl_regs[i] = ctrl->value;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300938 return (0);
939 }
940 return -EINVAL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300941}
942
943/* ------------------------------------------------------------------
944 File operations for the device
945 ------------------------------------------------------------------*/
946
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300947static int vivi_open(struct inode *inode, struct file *file)
948{
949 int minor = iminor(inode);
Trent Piephoa991f442007-10-10 05:37:43 -0300950 struct vivi_dev *dev;
Mauro Carvalho Chehab63b79cf2008-04-26 08:25:18 -0300951 struct vivi_fh *fh = NULL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300952 int i;
Brandon Philipsaa9dbac2008-04-02 18:10:59 -0300953 int retval = 0;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300954
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300955 printk(KERN_DEBUG "vivi: open called (minor=%d)\n", minor);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300956
Hans Verkuild56dc612008-07-30 08:43:36 -0300957 lock_kernel();
Trent Piephoa991f442007-10-10 05:37:43 -0300958 list_for_each_entry(dev, &vivi_devlist, vivi_devlist)
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -0300959 if (dev->vfd->minor == minor)
Trent Piephoa991f442007-10-10 05:37:43 -0300960 goto found;
Hans Verkuild56dc612008-07-30 08:43:36 -0300961 unlock_kernel();
Trent Piephoa991f442007-10-10 05:37:43 -0300962 return -ENODEV;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300963
Trent Piephoa991f442007-10-10 05:37:43 -0300964found:
Brandon Philipsaa9dbac2008-04-02 18:10:59 -0300965 mutex_lock(&dev->mutex);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300966 dev->users++;
967
Brandon Philipsaa9dbac2008-04-02 18:10:59 -0300968 if (dev->users > 1) {
969 dev->users--;
970 retval = -EBUSY;
971 goto unlock;
972 }
973
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300974 dprintk(dev, 1, "open minor=%d type=%s users=%d\n", minor,
Trent Piephoa991f442007-10-10 05:37:43 -0300975 v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300976
977 /* allocate + initialize per filehandle data */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300978 fh = kzalloc(sizeof(*fh), GFP_KERNEL);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300979 if (NULL == fh) {
980 dev->users--;
Brandon Philipsaa9dbac2008-04-02 18:10:59 -0300981 retval = -ENOMEM;
982 goto unlock;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300983 }
Brandon Philipsaa9dbac2008-04-02 18:10:59 -0300984unlock:
985 mutex_unlock(&dev->mutex);
Hans Verkuild56dc612008-07-30 08:43:36 -0300986 if (retval) {
987 unlock_kernel();
Brandon Philipsaa9dbac2008-04-02 18:10:59 -0300988 return retval;
Hans Verkuild56dc612008-07-30 08:43:36 -0300989 }
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300990
991 file->private_data = fh;
992 fh->dev = dev;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300993
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300994 fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
Magnus Dammd891f472008-10-14 12:47:09 -0300995 fh->fmt = &formats[0];
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300996 fh->width = 640;
997 fh->height = 480;
998
999 /* Put all controls at a sane state */
1000 for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001001 qctl_regs[i] = vivi_qctrl[i].default_value;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001002
1003 /* Resets frame counters */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001004 dev->h = 0;
1005 dev->m = 0;
1006 dev->s = 0;
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -03001007 dev->ms = 0;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001008 dev->mv_count = 0;
1009 dev->jiffies = jiffies;
1010 sprintf(dev->timestr, "%02d:%02d:%02d:%03d",
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -03001011 dev->h, dev->m, dev->s, dev->ms);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001012
Mauro Carvalho Chehab5a037702007-08-02 23:31:54 -03001013 videobuf_queue_vmalloc_init(&fh->vb_vidq, &vivi_video_qops,
Mauro Carvalho Chehab55862ac2007-12-13 16:13:37 -03001014 NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED,
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001015 sizeof(struct vivi_buffer), fh);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001016
Brandon Philips78718e52008-04-02 18:10:59 -03001017 vivi_start_thread(fh);
Hans Verkuild56dc612008-07-30 08:43:36 -03001018 unlock_kernel();
Brandon Philips78718e52008-04-02 18:10:59 -03001019
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001020 return 0;
1021}
1022
1023static ssize_t
1024vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
1025{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001026 struct vivi_fh *fh = file->private_data;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001027
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001028 if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
Mauro Carvalho Chehabacb09af2007-07-29 22:56:11 -03001029 return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001030 file->f_flags & O_NONBLOCK);
1031 }
1032 return 0;
1033}
1034
1035static unsigned int
1036vivi_poll(struct file *file, struct poll_table_struct *wait)
1037{
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001038 struct vivi_fh *fh = file->private_data;
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -03001039 struct vivi_dev *dev = fh->dev;
Brandon Philips85c7c70bc2007-09-27 20:55:02 -03001040 struct videobuf_queue *q = &fh->vb_vidq;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001041
Harvey Harrison7e28adb2008-04-08 23:20:00 -03001042 dprintk(dev, 1, "%s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001043
1044 if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
1045 return POLLERR;
1046
Brandon Philips85c7c70bc2007-09-27 20:55:02 -03001047 return videobuf_poll_stream(file, q, wait);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001048}
1049
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001050static int vivi_close(struct inode *inode, struct file *file)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001051{
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001052 struct vivi_fh *fh = file->private_data;
1053 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001054 struct vivi_dmaqueue *vidq = &dev->vidq;
1055
1056 int minor = iminor(inode);
1057
1058 vivi_stop_thread(vidq);
Brandon Philips053fcb62007-11-13 20:11:26 -03001059 videobuf_stop(&fh->vb_vidq);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001060 videobuf_mmap_free(&fh->vb_vidq);
1061
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001062 kfree(fh);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001063
Brandon Philipsaa9dbac2008-04-02 18:10:59 -03001064 mutex_lock(&dev->mutex);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001065 dev->users--;
Brandon Philipsaa9dbac2008-04-02 18:10:59 -03001066 mutex_unlock(&dev->mutex);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001067
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -03001068 dprintk(dev, 1, "close called (minor=%d, users=%d)\n",
1069 minor, dev->users);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001070
1071 return 0;
1072}
1073
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001074static int vivi_release(void)
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001075{
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001076 struct vivi_dev *dev;
1077 struct list_head *list;
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001078
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001079 while (!list_empty(&vivi_devlist)) {
1080 list = vivi_devlist.next;
1081 list_del(list);
1082 dev = list_entry(list, struct vivi_dev, vivi_devlist);
1083
Carl Karsten745271a2008-06-10 00:02:32 -03001084 if (-1 != dev->vfd->minor) {
Adrian Bunk8da9bae2008-09-03 17:12:25 -03001085 printk(KERN_INFO "%s: unregistering /dev/video%d\n",
1086 VIVI_MODULE_NAME, dev->vfd->minor);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001087 video_unregister_device(dev->vfd);
Carl Karsten745271a2008-06-10 00:02:32 -03001088 } else {
Adrian Bunk8da9bae2008-09-03 17:12:25 -03001089 printk(KERN_INFO "%s: releasing /dev/video%d\n",
Mauro Carvalho Chehab584ce482008-06-10 15:21:49 -03001090 VIVI_MODULE_NAME, dev->vfd->minor);
Adrian Bunk8da9bae2008-09-03 17:12:25 -03001091 video_device_release(dev->vfd);
Carl Karsten745271a2008-06-10 00:02:32 -03001092 }
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001093
1094 kfree(dev);
1095 }
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001096
1097 return 0;
1098}
1099
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001100static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001101{
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -03001102 struct vivi_fh *fh = file->private_data;
1103 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001104 int ret;
1105
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -03001106 dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001107
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001108 ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001109
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -03001110 dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n",
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001111 (unsigned long)vma->vm_start,
1112 (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
1113 ret);
1114
1115 return ret;
1116}
1117
Arjan van de Venfa027c22007-02-12 00:55:33 -08001118static const struct file_operations vivi_fops = {
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001119 .owner = THIS_MODULE,
1120 .open = vivi_open,
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001121 .release = vivi_close,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001122 .read = vivi_read,
1123 .poll = vivi_poll,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001124 .ioctl = video_ioctl2, /* V4L2 ioctl handler */
Mauro Carvalho Chehabfbde31d2008-04-13 14:57:44 -03001125 .compat_ioctl = v4l_compat_ioctl32,
Mauro Carvalho Chehab5a037702007-08-02 23:31:54 -03001126 .mmap = vivi_mmap,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001127 .llseek = no_llseek,
1128};
1129
Hans Verkuila3998102008-07-21 02:57:38 -03001130static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001131 .vidioc_querycap = vidioc_querycap,
Hans Verkuil78b526a2008-05-28 12:16:41 -03001132 .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
1133 .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
1134 .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
1135 .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001136 .vidioc_reqbufs = vidioc_reqbufs,
1137 .vidioc_querybuf = vidioc_querybuf,
1138 .vidioc_qbuf = vidioc_qbuf,
1139 .vidioc_dqbuf = vidioc_dqbuf,
1140 .vidioc_s_std = vidioc_s_std,
1141 .vidioc_enum_input = vidioc_enum_input,
1142 .vidioc_g_input = vidioc_g_input,
1143 .vidioc_s_input = vidioc_s_input,
1144 .vidioc_queryctrl = vidioc_queryctrl,
1145 .vidioc_g_ctrl = vidioc_g_ctrl,
1146 .vidioc_s_ctrl = vidioc_s_ctrl,
1147 .vidioc_streamon = vidioc_streamon,
1148 .vidioc_streamoff = vidioc_streamoff,
Mauro Carvalho Chehab0dfa9ab2006-08-08 09:10:10 -03001149#ifdef CONFIG_VIDEO_V4L1_COMPAT
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001150 .vidiocgmbuf = vidiocgmbuf,
1151#endif
Hans Verkuila3998102008-07-21 02:57:38 -03001152};
1153
1154static struct video_device vivi_template = {
1155 .name = "vivi",
Hans Verkuila3998102008-07-21 02:57:38 -03001156 .fops = &vivi_fops,
1157 .ioctl_ops = &vivi_ioctl_ops,
1158 .minor = -1,
1159 .release = video_device_release,
1160
Mauro Carvalho Chehab784c6682007-12-13 06:35:26 -03001161 .tvnorms = V4L2_STD_525_60,
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -03001162 .current_norm = V4L2_STD_NTSC_M,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001163};
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001164/* -----------------------------------------------------------------
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001165 Initialization and module stuff
1166 ------------------------------------------------------------------*/
1167
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001168/* This routine allocates from 1 to n_devs virtual drivers.
1169
1170 The real maximum number of virtual drivers will depend on how many drivers
1171 will succeed. This is limited to the maximum number of devices that
1172 videodev supports. Since there are 64 minors for video grabbers, this is
1173 currently the theoretical maximum limit. However, a further limit does
1174 exist at videodev that forbids any driver to register more than 32 video
1175 grabbers.
1176 */
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001177static int __init vivi_init(void)
1178{
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001179 int ret = -ENOMEM, i;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001180 struct vivi_dev *dev;
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001181 struct video_device *vfd;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001182
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001183 if (n_devs <= 0)
1184 n_devs = 1;
1185
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001186 for (i = 0; i < n_devs; i++) {
1187 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001188 if (!dev)
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001189 break;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001190
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001191 /* init video dma queues */
1192 INIT_LIST_HEAD(&dev->vidq.active);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001193 init_waitqueue_head(&dev->vidq.wq);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001194
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001195 /* initialize locks */
Mauro Carvalho Chehab55862ac2007-12-13 16:13:37 -03001196 spin_lock_init(&dev->slock);
Brandon Philipsaa9dbac2008-04-02 18:10:59 -03001197 mutex_init(&dev->mutex);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001198
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001199 vfd = video_device_alloc();
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001200 if (!vfd) {
1201 kfree(dev);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001202 break;
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001203 }
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001204
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001205 *vfd = vivi_template;
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001206
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001207 ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001208 if (ret < 0) {
1209 video_device_release(vfd);
1210 kfree(dev);
1211
1212 /* If some registers succeeded, keep driver */
1213 if (i)
1214 ret = 0;
1215
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001216 break;
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001217 }
1218
1219 /* Now that everything is fine, let's add it to device list */
1220 list_add_tail(&dev->vivi_devlist, &vivi_devlist);
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001221
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001222 snprintf(vfd->name, sizeof(vfd->name), "%s (%i)",
1223 vivi_template.name, vfd->minor);
1224
1225 if (video_nr >= 0)
1226 video_nr++;
1227
1228 dev->vfd = vfd;
Carl Karsten745271a2008-06-10 00:02:32 -03001229 printk(KERN_INFO "%s: V4L2 device registered as /dev/video%d\n",
Mauro Carvalho Chehab584ce482008-06-10 15:21:49 -03001230 VIVI_MODULE_NAME, vfd->minor);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001231 }
1232
1233 if (ret < 0) {
1234 vivi_release();
1235 printk(KERN_INFO "Error %d while loading vivi driver\n", ret);
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001236 } else {
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001237 printk(KERN_INFO "Video Technology Magazine Virtual Video "
Carl Karsten745271a2008-06-10 00:02:32 -03001238 "Capture Board ver %u.%u.%u successfully loaded.\n",
1239 (VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF,
1240 VIVI_VERSION & 0xFF);
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001241
1242 /* n_devs will reflect the actual number of allocated devices */
1243 n_devs = i;
1244 }
1245
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001246 return ret;
1247}
1248
1249static void __exit vivi_exit(void)
1250{
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001251 vivi_release();
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001252}
1253
1254module_init(vivi_init);
1255module_exit(vivi_exit);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001256
1257MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
1258MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
1259MODULE_LICENSE("Dual BSD/GPL");
1260
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001261module_param(video_nr, uint, 0444);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001262MODULE_PARM_DESC(video_nr, "video iminor start number");
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001263
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001264module_param(n_devs, uint, 0444);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001265MODULE_PARM_DESC(n_devs, "number of video devices to create");
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001266
Mauro Carvalho Chehab8996b3f2007-12-13 06:36:22 -03001267module_param_named(debug, vivi_template.debug, int, 0444);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001268MODULE_PARM_DESC(debug, "activates debug info");
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001269
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001270module_param(vid_limit, int, 0644);
1271MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");