blob: 81d5aa5cf3317c336ecbaf7c666e75d793514dab [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 },
Magnus Dammdef52392008-10-14 12:47:43 -0300152 {
153 .name = "RGB555 (LE)",
154 .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
155 .depth = 16,
156 },
157 {
158 .name = "RGB555 (BE)",
159 .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
160 .depth = 16,
161 },
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300162};
163
Magnus Dammd891f472008-10-14 12:47:09 -0300164static struct vivi_fmt *get_format(struct v4l2_format *f)
165{
166 struct vivi_fmt *fmt;
167 unsigned int k;
168
169 for (k = 0; k < ARRAY_SIZE(formats); k++) {
170 fmt = &formats[k];
171 if (fmt->fourcc == f->fmt.pix.pixelformat)
172 break;
173 }
174
175 if (k == ARRAY_SIZE(formats))
176 return NULL;
177
178 return &formats[k];
179}
180
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300181struct sg_to_addr {
182 int pos;
183 struct scatterlist *sg;
184};
185
186/* buffer for one video frame */
187struct vivi_buffer {
188 /* common v4l buffer stuff -- must be first */
189 struct videobuf_buffer vb;
190
191 struct vivi_fmt *fmt;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300192};
193
194struct vivi_dmaqueue {
195 struct list_head active;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300196
197 /* thread for generating video stream*/
198 struct task_struct *kthread;
199 wait_queue_head_t wq;
200 /* Counters to control fps rate */
201 int frame;
202 int ini_jiffies;
203};
204
205static LIST_HEAD(vivi_devlist);
206
207struct vivi_dev {
208 struct list_head vivi_devlist;
209
Mauro Carvalho Chehab55862ac2007-12-13 16:13:37 -0300210 spinlock_t slock;
Brandon Philipsaa9dbac2008-04-02 18:10:59 -0300211 struct mutex mutex;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300212
213 int users;
214
215 /* various device info */
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -0300216 struct video_device *vfd;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300217
218 struct vivi_dmaqueue vidq;
219
220 /* Several counters */
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -0300221 int h, m, s, ms;
222 unsigned long jiffies;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300223 char timestr[13];
Mauro Carvalho Chehab025341d2007-12-10 04:43:38 -0300224
225 int mv_count; /* Controls bars movement */
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300226};
227
228struct vivi_fh {
229 struct vivi_dev *dev;
230
231 /* video capture */
232 struct vivi_fmt *fmt;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300233 unsigned int width, height;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300234 struct videobuf_queue vb_vidq;
235
236 enum v4l2_buf_type type;
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300237 unsigned char bars[8][3];
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300238};
239
240/* ------------------------------------------------------------------
241 DMA and thread functions
242 ------------------------------------------------------------------*/
243
244/* Bars and Colors should match positions */
245
246enum colors {
247 WHITE,
248 AMBAR,
249 CYAN,
250 GREEN,
251 MAGENTA,
252 RED,
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300253 BLUE,
254 BLACK,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300255};
256
257static u8 bars[8][3] = {
258 /* R G B */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300259 {204, 204, 204}, /* white */
260 {208, 208, 0}, /* ambar */
261 { 0, 206, 206}, /* cyan */
262 { 0, 239, 0}, /* green */
263 {239, 0, 239}, /* magenta */
264 {205, 0, 0}, /* red */
265 { 0, 0, 255}, /* blue */
266 { 0, 0, 0}, /* black */
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300267};
268
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300269#define TO_Y(r, g, b) \
270 (((16829 * r + 33039 * g + 6416 * b + 32768) >> 16) + 16)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300271/* RGB to V(Cr) Color transform */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300272#define TO_V(r, g, b) \
273 (((28784 * r - 24103 * g - 4681 * b + 32768) >> 16) + 128)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300274/* RGB to U(Cb) Color transform */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300275#define TO_U(r, g, b) \
276 (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300277
278#define TSTAMP_MIN_Y 24
279#define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
280#define TSTAMP_MIN_X 64
281
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300282static void gen_twopix(struct vivi_fh *fh, unsigned char *buf, int colorpos)
283{
284 unsigned char r_y, g_u, b_v;
285 unsigned char *p;
286 int color;
287
288 r_y = fh->bars[colorpos][0]; /* R or precalculated Y */
289 g_u = fh->bars[colorpos][1]; /* G or precalculated U */
290 b_v = fh->bars[colorpos][2]; /* B or precalculated V */
291
292 for (color = 0; color < 4; color++) {
293 p = buf + color;
294
Magnus Dammd891f472008-10-14 12:47:09 -0300295 switch (fh->fmt->fourcc) {
296 case V4L2_PIX_FMT_YUYV:
297 switch (color) {
298 case 0:
299 case 2:
300 *p = r_y;
301 break;
302 case 1:
303 *p = g_u;
304 break;
305 case 3:
306 *p = b_v;
307 break;
308 }
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300309 break;
Magnus Dammfca36ba2008-10-14 12:47:25 -0300310 case V4L2_PIX_FMT_UYVY:
311 switch (color) {
312 case 1:
313 case 3:
314 *p = r_y;
315 break;
316 case 0:
317 *p = g_u;
318 break;
319 case 2:
320 *p = b_v;
321 break;
322 }
323 break;
Magnus Dammaeadb5d2008-10-14 12:47:35 -0300324 case V4L2_PIX_FMT_RGB565:
325 switch (color) {
326 case 0:
327 case 2:
328 *p = (g_u << 5) | b_v;
329 break;
330 case 1:
331 case 3:
332 *p = (r_y << 3) | (g_u >> 3);
333 break;
334 }
335 break;
336 case V4L2_PIX_FMT_RGB565X:
337 switch (color) {
338 case 0:
339 case 2:
340 *p = (r_y << 3) | (g_u >> 3);
341 break;
342 case 1:
343 case 3:
344 *p = (g_u << 5) | b_v;
345 break;
346 }
347 break;
Magnus Dammdef52392008-10-14 12:47:43 -0300348 case V4L2_PIX_FMT_RGB555:
349 switch (color) {
350 case 0:
351 case 2:
352 *p = (g_u << 5) | b_v;
353 break;
354 case 1:
355 case 3:
356 *p = (r_y << 2) | (g_u >> 3);
357 break;
358 }
359 break;
360 case V4L2_PIX_FMT_RGB555X:
361 switch (color) {
362 case 0:
363 case 2:
364 *p = (r_y << 2) | (g_u >> 3);
365 break;
366 case 1:
367 case 3:
368 *p = (g_u << 5) | b_v;
369 break;
370 }
371 break;
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300372 }
373 }
374}
375
376static void gen_line(struct vivi_fh *fh, char *basep, int inipos, int wmax,
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300377 int hmax, int line, int count, char *timestr)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300378{
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300379 int w, i, j;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300380 int pos = inipos;
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300381 char *s;
382 u8 chr;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300383
384 /* We will just duplicate the second pixel at the packet */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300385 wmax /= 2;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300386
387 /* Generate a standard color bar pattern */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300388 for (w = 0; w < wmax; w++) {
389 int colorpos = ((w + count) * 8/(wmax + 1)) % 8;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300390
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300391 gen_twopix(fh, basep + pos, colorpos);
392 pos += 4; /* only 16 bpp supported for now */
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300393 }
394
395 /* Checks if it is possible to show timestamp */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300396 if (TSTAMP_MAX_Y >= hmax)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300397 goto end;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300398 if (TSTAMP_MIN_X + strlen(timestr) >= wmax)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300399 goto end;
400
401 /* Print stream time */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300402 if (line >= TSTAMP_MIN_Y && line <= TSTAMP_MAX_Y) {
403 j = TSTAMP_MIN_X;
404 for (s = timestr; *s; s++) {
405 chr = rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y];
406 for (i = 0; i < 7; i++) {
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300407 pos = inipos + j * 2;
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300408 /* Draw white font on black background */
409 if (chr & 1 << (7 - i))
410 gen_twopix(fh, basep + pos, WHITE);
411 else
412 gen_twopix(fh, basep + pos, BLACK);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300413 j++;
414 }
415 }
416 }
417
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300418end:
Mauro Carvalho Chehabb50e7fe2007-01-25 05:00:01 -0300419 return;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300420}
Brandon Philips78718e52008-04-02 18:10:59 -0300421
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300422static void vivi_fillbuff(struct vivi_fh *fh, struct vivi_buffer *buf)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300423{
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300424 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300425 int h , pos = 0;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300426 int hmax = buf->vb.height;
427 int wmax = buf->vb.width;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300428 struct timeval ts;
Marcin Slusarz5c554e62008-06-22 09:11:40 -0300429 char *tmpbuf;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300430 void *vbuf = videobuf_to_vmalloc(&buf->vb);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300431
Marcin Slusarz5c554e62008-06-22 09:11:40 -0300432 if (!vbuf)
Mauro Carvalho Chehab5a037702007-08-02 23:31:54 -0300433 return;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300434
Marcin Slusarz5c554e62008-06-22 09:11:40 -0300435 tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC);
436 if (!tmpbuf)
Brandon Philips78718e52008-04-02 18:10:59 -0300437 return;
438
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300439 for (h = 0; h < hmax; h++) {
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300440 gen_line(fh, tmpbuf, 0, wmax, hmax, h, dev->mv_count,
Mauro Carvalho Chehab3bef5e42007-09-22 02:01:33 -0300441 dev->timestr);
Brandon Philips78718e52008-04-02 18:10:59 -0300442 memcpy(vbuf + pos, tmpbuf, wmax * 2);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300443 pos += wmax*2;
444 }
445
Mauro Carvalho Chehab025341d2007-12-10 04:43:38 -0300446 dev->mv_count++;
Mauro Carvalho Chehab3bef5e42007-09-22 02:01:33 -0300447
Mauro Carvalho Chehab5a037702007-08-02 23:31:54 -0300448 kfree(tmpbuf);
449
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300450 /* Updates stream time */
451
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -0300452 dev->ms += jiffies_to_msecs(jiffies-dev->jiffies);
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300453 dev->jiffies = jiffies;
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -0300454 if (dev->ms >= 1000) {
455 dev->ms -= 1000;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300456 dev->s++;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300457 if (dev->s >= 60) {
458 dev->s -= 60;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300459 dev->m++;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300460 if (dev->m > 60) {
461 dev->m -= 60;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300462 dev->h++;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300463 if (dev->h > 24)
464 dev->h -= 24;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300465 }
466 }
467 }
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300468 sprintf(dev->timestr, "%02d:%02d:%02d:%03d",
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -0300469 dev->h, dev->m, dev->s, dev->ms);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300470
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300471 dprintk(dev, 2, "vivifill at %s: Buffer 0x%08lx size= %d\n",
472 dev->timestr, (unsigned long)tmpbuf, pos);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300473
474 /* Advice that buffer was filled */
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300475 buf->vb.field_count++;
476 do_gettimeofday(&ts);
477 buf->vb.ts = ts;
Brandon Philips78718e52008-04-02 18:10:59 -0300478 buf->vb.state = VIDEOBUF_DONE;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300479}
480
Brandon Philips78718e52008-04-02 18:10:59 -0300481static void vivi_thread_tick(struct vivi_fh *fh)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300482{
Brandon Philips78718e52008-04-02 18:10:59 -0300483 struct vivi_buffer *buf;
484 struct vivi_dev *dev = fh->dev;
485 struct vivi_dmaqueue *dma_q = &dev->vidq;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300486
Brandon Philips78718e52008-04-02 18:10:59 -0300487 unsigned long flags = 0;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300488
Brandon Philips78718e52008-04-02 18:10:59 -0300489 dprintk(dev, 1, "Thread tick\n");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300490
Brandon Philips78718e52008-04-02 18:10:59 -0300491 spin_lock_irqsave(&dev->slock, flags);
492 if (list_empty(&dma_q->active)) {
493 dprintk(dev, 1, "No active queue to serve\n");
494 goto unlock;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300495 }
Brandon Philips78718e52008-04-02 18:10:59 -0300496
497 buf = list_entry(dma_q->active.next,
498 struct vivi_buffer, vb.queue);
499
500 /* Nobody is waiting on this buffer, return */
501 if (!waitqueue_active(&buf->vb.done))
502 goto unlock;
503
504 list_del(&buf->vb.queue);
505
506 do_gettimeofday(&buf->vb.ts);
507
508 /* Fill buffer */
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300509 vivi_fillbuff(fh, buf);
Brandon Philips78718e52008-04-02 18:10:59 -0300510 dprintk(dev, 1, "filled buffer %p\n", buf);
511
512 wake_up(&buf->vb.done);
513 dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i);
514unlock:
515 spin_unlock_irqrestore(&dev->slock, flags);
516 return;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300517}
518
Mauro Carvalho Chehab6594ad82007-12-13 16:15:41 -0300519#define frames_to_ms(frames) \
520 ((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR)
521
Brandon Philips78718e52008-04-02 18:10:59 -0300522static void vivi_sleep(struct vivi_fh *fh)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300523{
Brandon Philips78718e52008-04-02 18:10:59 -0300524 struct vivi_dev *dev = fh->dev;
525 struct vivi_dmaqueue *dma_q = &dev->vidq;
526 int timeout;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300527 DECLARE_WAITQUEUE(wait, current);
528
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300529 dprintk(dev, 1, "%s dma_q=0x%08lx\n", __func__,
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300530 (unsigned long)dma_q);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300531
532 add_wait_queue(&dma_q->wq, &wait);
Mauro Carvalho Chehab6594ad82007-12-13 16:15:41 -0300533 if (kthread_should_stop())
534 goto stop_task;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300535
Mauro Carvalho Chehab6594ad82007-12-13 16:15:41 -0300536 /* Calculate time to wake up */
Brandon Philips78718e52008-04-02 18:10:59 -0300537 timeout = msecs_to_jiffies(frames_to_ms(1));
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300538
Brandon Philips78718e52008-04-02 18:10:59 -0300539 vivi_thread_tick(fh);
Mauro Carvalho Chehab6594ad82007-12-13 16:15:41 -0300540
541 schedule_timeout_interruptible(timeout);
542
543stop_task:
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300544 remove_wait_queue(&dma_q->wq, &wait);
545 try_to_freeze();
546}
547
Adrian Bunk972c3512006-04-27 21:06:50 -0300548static int vivi_thread(void *data)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300549{
Brandon Philips78718e52008-04-02 18:10:59 -0300550 struct vivi_fh *fh = data;
551 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300552
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300553 dprintk(dev, 1, "thread started\n");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300554
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700555 set_freezable();
Mauro Carvalho Chehab0b600512007-01-14 08:33:24 -0300556
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300557 for (;;) {
Brandon Philips78718e52008-04-02 18:10:59 -0300558 vivi_sleep(fh);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300559
560 if (kthread_should_stop())
561 break;
562 }
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300563 dprintk(dev, 1, "thread: exit\n");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300564 return 0;
565}
566
Brandon Philips78718e52008-04-02 18:10:59 -0300567static int vivi_start_thread(struct vivi_fh *fh)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300568{
Brandon Philips78718e52008-04-02 18:10:59 -0300569 struct vivi_dev *dev = fh->dev;
570 struct vivi_dmaqueue *dma_q = &dev->vidq;
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300571
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300572 dma_q->frame = 0;
573 dma_q->ini_jiffies = jiffies;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300574
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300575 dprintk(dev, 1, "%s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300576
Brandon Philips78718e52008-04-02 18:10:59 -0300577 dma_q->kthread = kthread_run(vivi_thread, fh, "vivi");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300578
Akinobu Mita054afee2006-12-20 10:04:00 -0300579 if (IS_ERR(dma_q->kthread)) {
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300580 printk(KERN_ERR "vivi: kernel_thread() failed\n");
Akinobu Mita054afee2006-12-20 10:04:00 -0300581 return PTR_ERR(dma_q->kthread);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300582 }
Mauro Carvalho Chehab0b600512007-01-14 08:33:24 -0300583 /* Wakes thread */
584 wake_up_interruptible(&dma_q->wq);
585
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300586 dprintk(dev, 1, "returning from %s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300587 return 0;
588}
589
Adrian Bunk972c3512006-04-27 21:06:50 -0300590static void vivi_stop_thread(struct vivi_dmaqueue *dma_q)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300591{
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300592 struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
593
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300594 dprintk(dev, 1, "%s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300595 /* shutdown control thread */
596 if (dma_q->kthread) {
597 kthread_stop(dma_q->kthread);
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300598 dma_q->kthread = NULL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300599 }
600}
601
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300602/* ------------------------------------------------------------------
603 Videobuf operations
604 ------------------------------------------------------------------*/
605static int
606buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
607{
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300608 struct vivi_fh *fh = vq->priv_data;
609 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300610
611 *size = fh->width*fh->height*2;
612
613 if (0 == *count)
614 *count = 32;
Mauro Carvalho Chehab6bb27902007-08-23 16:41:14 -0300615
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300616 while (*size * *count > vid_limit * 1024 * 1024)
617 (*count)--;
Mauro Carvalho Chehab6bb27902007-08-23 16:41:14 -0300618
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300619 dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__,
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300620 *count, *size);
Mauro Carvalho Chehab6bb27902007-08-23 16:41:14 -0300621
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300622 return 0;
623}
624
Adrian Bunk972c3512006-04-27 21:06:50 -0300625static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300626{
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300627 struct vivi_fh *fh = vq->priv_data;
628 struct vivi_dev *dev = fh->dev;
629
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300630 dprintk(dev, 1, "%s, state: %i\n", __func__, buf->vb.state);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300631
632 if (in_interrupt())
633 BUG();
634
Mauro Carvalho Chehab5a037702007-08-02 23:31:54 -0300635 videobuf_vmalloc_free(&buf->vb);
Mauro Carvalho Chehabfbde31d2008-04-13 14:57:44 -0300636 dprintk(dev, 1, "free_buffer: freed\n");
Brandon Philips0fc06862007-11-06 20:02:36 -0300637 buf->vb.state = VIDEOBUF_NEEDS_INIT;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300638}
639
640#define norm_maxw() 1024
641#define norm_maxh() 768
642static int
643buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
644 enum v4l2_field field)
645{
646 struct vivi_fh *fh = vq->priv_data;
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300647 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300648 struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
Brandon Philips78718e52008-04-02 18:10:59 -0300649 int rc;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300650
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300651 dprintk(dev, 1, "%s, field=%d\n", __func__, field);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300652
653 BUG_ON(NULL == fh->fmt);
Brandon Philips78718e52008-04-02 18:10:59 -0300654
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300655 if (fh->width < 48 || fh->width > norm_maxw() ||
656 fh->height < 32 || fh->height > norm_maxh())
657 return -EINVAL;
Brandon Philips78718e52008-04-02 18:10:59 -0300658
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300659 buf->vb.size = fh->width*fh->height*2;
660 if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
661 return -EINVAL;
662
Brandon Philips78718e52008-04-02 18:10:59 -0300663 /* These properties only change when queue is idle, see s_fmt */
664 buf->fmt = fh->fmt;
665 buf->vb.width = fh->width;
666 buf->vb.height = fh->height;
667 buf->vb.field = field;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300668
Brandon Philips0fc06862007-11-06 20:02:36 -0300669 if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300670 rc = videobuf_iolock(vq, &buf->vb, NULL);
671 if (rc < 0)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300672 goto fail;
673 }
674
Brandon Philips0fc06862007-11-06 20:02:36 -0300675 buf->vb.state = VIDEOBUF_PREPARED;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300676
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300677 return 0;
678
679fail:
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300680 free_buffer(vq, buf);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300681 return rc;
682}
683
684static void
685buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
686{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300687 struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
688 struct vivi_fh *fh = vq->priv_data;
689 struct vivi_dev *dev = fh->dev;
Brandon Philips78718e52008-04-02 18:10:59 -0300690 struct vivi_dmaqueue *vidq = &dev->vidq;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300691
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300692 dprintk(dev, 1, "%s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300693
Brandon Philips78718e52008-04-02 18:10:59 -0300694 buf->vb.state = VIDEOBUF_QUEUED;
695 list_add_tail(&buf->vb.queue, &vidq->active);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300696}
697
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300698static void buffer_release(struct videobuf_queue *vq,
699 struct videobuf_buffer *vb)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300700{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300701 struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300702 struct vivi_fh *fh = vq->priv_data;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300703 struct vivi_dev *dev = (struct vivi_dev *)fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300704
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300705 dprintk(dev, 1, "%s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300706
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300707 free_buffer(vq, buf);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300708}
709
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300710static struct videobuf_queue_ops vivi_video_qops = {
711 .buf_setup = buffer_setup,
712 .buf_prepare = buffer_prepare,
713 .buf_queue = buffer_queue,
714 .buf_release = buffer_release,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300715};
716
717/* ------------------------------------------------------------------
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300718 IOCTL vidioc handling
719 ------------------------------------------------------------------*/
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300720static int vidioc_querycap(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300721 struct v4l2_capability *cap)
722{
723 strcpy(cap->driver, "vivi");
724 strcpy(cap->card, "vivi");
725 cap->version = VIVI_VERSION;
726 cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
727 V4L2_CAP_STREAMING |
728 V4L2_CAP_READWRITE;
729 return 0;
730}
731
Hans Verkuil78b526a2008-05-28 12:16:41 -0300732static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300733 struct v4l2_fmtdesc *f)
734{
Magnus Dammd891f472008-10-14 12:47:09 -0300735 struct vivi_fmt *fmt;
736
737 if (f->index >= ARRAY_SIZE(formats))
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300738 return -EINVAL;
739
Magnus Dammd891f472008-10-14 12:47:09 -0300740 fmt = &formats[f->index];
741
742 strlcpy(f->description, fmt->name, sizeof(f->description));
743 f->pixelformat = fmt->fourcc;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300744 return 0;
745}
746
Hans Verkuil78b526a2008-05-28 12:16:41 -0300747static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300748 struct v4l2_format *f)
749{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300750 struct vivi_fh *fh = priv;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300751
752 f->fmt.pix.width = fh->width;
753 f->fmt.pix.height = fh->height;
754 f->fmt.pix.field = fh->vb_vidq.field;
755 f->fmt.pix.pixelformat = fh->fmt->fourcc;
756 f->fmt.pix.bytesperline =
757 (f->fmt.pix.width * fh->fmt->depth) >> 3;
758 f->fmt.pix.sizeimage =
759 f->fmt.pix.height * f->fmt.pix.bytesperline;
760
761 return (0);
762}
763
Hans Verkuil78b526a2008-05-28 12:16:41 -0300764static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300765 struct v4l2_format *f)
766{
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300767 struct vivi_fh *fh = priv;
768 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300769 struct vivi_fmt *fmt;
770 enum v4l2_field field;
771 unsigned int maxw, maxh;
772
Magnus Dammd891f472008-10-14 12:47:09 -0300773 fmt = get_format(f);
774 if (!fmt) {
775 dprintk(dev, 1, "Fourcc format (0x%08x) invalid.\n",
776 f->fmt.pix.pixelformat);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300777 return -EINVAL;
778 }
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300779
780 field = f->fmt.pix.field;
781
782 if (field == V4L2_FIELD_ANY) {
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300783 field = V4L2_FIELD_INTERLACED;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300784 } else if (V4L2_FIELD_INTERLACED != field) {
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300785 dprintk(dev, 1, "Field type invalid.\n");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300786 return -EINVAL;
787 }
788
789 maxw = norm_maxw();
790 maxh = norm_maxh();
791
792 f->fmt.pix.field = field;
793 if (f->fmt.pix.height < 32)
794 f->fmt.pix.height = 32;
795 if (f->fmt.pix.height > maxh)
796 f->fmt.pix.height = maxh;
797 if (f->fmt.pix.width < 48)
798 f->fmt.pix.width = 48;
799 if (f->fmt.pix.width > maxw)
800 f->fmt.pix.width = maxw;
801 f->fmt.pix.width &= ~0x03;
802 f->fmt.pix.bytesperline =
803 (f->fmt.pix.width * fmt->depth) >> 3;
804 f->fmt.pix.sizeimage =
805 f->fmt.pix.height * f->fmt.pix.bytesperline;
806
807 return 0;
808}
809
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300810/*FIXME: This seems to be generic enough to be at videodev2 */
Hans Verkuil78b526a2008-05-28 12:16:41 -0300811static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300812 struct v4l2_format *f)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300813{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300814 struct vivi_fh *fh = priv;
Brandon Philips78718e52008-04-02 18:10:59 -0300815 struct videobuf_queue *q = &fh->vb_vidq;
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300816 unsigned char r, g, b;
Magnus Dammd891f472008-10-14 12:47:09 -0300817 int k, is_yuv;
Brandon Philips78718e52008-04-02 18:10:59 -0300818
Hans Verkuil78b526a2008-05-28 12:16:41 -0300819 int ret = vidioc_try_fmt_vid_cap(file, fh, f);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300820 if (ret < 0)
821 return (ret);
822
Brandon Philips78718e52008-04-02 18:10:59 -0300823 mutex_lock(&q->vb_lock);
824
825 if (videobuf_queue_is_busy(&fh->vb_vidq)) {
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300826 dprintk(fh->dev, 1, "%s queue busy\n", __func__);
Brandon Philips78718e52008-04-02 18:10:59 -0300827 ret = -EBUSY;
828 goto out;
829 }
830
Magnus Dammd891f472008-10-14 12:47:09 -0300831 fh->fmt = get_format(f);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300832 fh->width = f->fmt.pix.width;
833 fh->height = f->fmt.pix.height;
834 fh->vb_vidq.field = f->fmt.pix.field;
835 fh->type = f->type;
836
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300837 /* precalculate color bar values to speed up rendering */
838 for (k = 0; k < 8; k++) {
839 r = bars[k][0];
840 g = bars[k][1];
841 b = bars[k][2];
Magnus Dammd891f472008-10-14 12:47:09 -0300842 is_yuv = 0;
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300843
Magnus Dammd891f472008-10-14 12:47:09 -0300844 switch (fh->fmt->fourcc) {
845 case V4L2_PIX_FMT_YUYV:
Magnus Dammfca36ba2008-10-14 12:47:25 -0300846 case V4L2_PIX_FMT_UYVY:
Magnus Dammd891f472008-10-14 12:47:09 -0300847 is_yuv = 1;
848 break;
Magnus Dammaeadb5d2008-10-14 12:47:35 -0300849 case V4L2_PIX_FMT_RGB565:
850 case V4L2_PIX_FMT_RGB565X:
851 r >>= 3;
852 g >>= 2;
853 b >>= 3;
854 break;
Magnus Dammdef52392008-10-14 12:47:43 -0300855 case V4L2_PIX_FMT_RGB555:
856 case V4L2_PIX_FMT_RGB555X:
857 r >>= 3;
858 g >>= 3;
859 b >>= 3;
860 break;
Magnus Dammd891f472008-10-14 12:47:09 -0300861 }
862
863 if (is_yuv) {
864 fh->bars[k][0] = TO_Y(r, g, b); /* Luma */
865 fh->bars[k][1] = TO_U(r, g, b); /* Cb */
866 fh->bars[k][2] = TO_V(r, g, b); /* Cr */
867 } else {
868 fh->bars[k][0] = r;
869 fh->bars[k][1] = g;
870 fh->bars[k][2] = b;
871 }
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300872 }
873
Brandon Philips78718e52008-04-02 18:10:59 -0300874 ret = 0;
875out:
876 mutex_unlock(&q->vb_lock);
877
878 return (ret);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300879}
880
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300881static int vidioc_reqbufs(struct file *file, void *priv,
882 struct v4l2_requestbuffers *p)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300883{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300884 struct vivi_fh *fh = priv;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300885
886 return (videobuf_reqbufs(&fh->vb_vidq, p));
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300887}
888
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300889static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300890{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300891 struct vivi_fh *fh = priv;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300892
893 return (videobuf_querybuf(&fh->vb_vidq, p));
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300894}
895
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300896static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300897{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300898 struct vivi_fh *fh = priv;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300899
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300900 return (videobuf_qbuf(&fh->vb_vidq, p));
901}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300902
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300903static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300904{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300905 struct vivi_fh *fh = priv;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300906
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300907 return (videobuf_dqbuf(&fh->vb_vidq, p,
908 file->f_flags & O_NONBLOCK));
909}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300910
Mauro Carvalho Chehab0dfa9ab2006-08-08 09:10:10 -0300911#ifdef CONFIG_VIDEO_V4L1_COMPAT
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300912static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300913{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300914 struct vivi_fh *fh = priv;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300915
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300916 return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300917}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300918#endif
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300919
Adrian Bunkdc46ace2006-06-23 06:42:44 -0300920static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300921{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300922 struct vivi_fh *fh = priv;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300923
924 if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
925 return -EINVAL;
926 if (i != fh->type)
927 return -EINVAL;
928
Brandon Philipsba32bd92007-09-27 20:55:17 -0300929 return videobuf_streamon(&fh->vb_vidq);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300930}
931
Adrian Bunkdc46ace2006-06-23 06:42:44 -0300932static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300933{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300934 struct vivi_fh *fh = priv;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300935
936 if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
937 return -EINVAL;
938 if (i != fh->type)
939 return -EINVAL;
940
Brandon Philipsba32bd92007-09-27 20:55:17 -0300941 return videobuf_streamoff(&fh->vb_vidq);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300942}
943
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300944static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300945{
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300946 return 0;
947}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300948
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300949/* only one input in this sample driver */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300950static int vidioc_enum_input(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300951 struct v4l2_input *inp)
952{
953 if (inp->index != 0)
954 return -EINVAL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300955
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300956 inp->type = V4L2_INPUT_TYPE_CAMERA;
Mauro Carvalho Chehab784c6682007-12-13 06:35:26 -0300957 inp->std = V4L2_STD_525_60;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300958 strcpy(inp->name, "Camera");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300959
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300960 return (0);
961}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300962
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300963static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300964{
965 *i = 0;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300966
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300967 return (0);
968}
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300969static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300970{
971 if (i > 0)
972 return -EINVAL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300973
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300974 return (0);
975}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300976
977 /* --- controls ---------------------------------------------- */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300978static int vidioc_queryctrl(struct file *file, void *priv,
979 struct v4l2_queryctrl *qc)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300980{
981 int i;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300982
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300983 for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
984 if (qc->id && qc->id == vivi_qctrl[i].id) {
985 memcpy(qc, &(vivi_qctrl[i]),
986 sizeof(*qc));
987 return (0);
988 }
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300989
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300990 return -EINVAL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300991}
992
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300993static int vidioc_g_ctrl(struct file *file, void *priv,
994 struct v4l2_control *ctrl)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300995{
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300996 int i;
997
998 for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
999 if (ctrl->id == vivi_qctrl[i].id) {
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001000 ctrl->value = qctl_regs[i];
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001001 return (0);
1002 }
1003
1004 return -EINVAL;
1005}
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001006static int vidioc_s_ctrl(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001007 struct v4l2_control *ctrl)
1008{
1009 int i;
1010
1011 for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
1012 if (ctrl->id == vivi_qctrl[i].id) {
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001013 if (ctrl->value < vivi_qctrl[i].minimum
1014 || ctrl->value > vivi_qctrl[i].maximum) {
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001015 return (-ERANGE);
1016 }
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001017 qctl_regs[i] = ctrl->value;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001018 return (0);
1019 }
1020 return -EINVAL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001021}
1022
1023/* ------------------------------------------------------------------
1024 File operations for the device
1025 ------------------------------------------------------------------*/
1026
Hans Verkuilbec43662008-12-30 06:58:20 -03001027static int vivi_open(struct file *file)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001028{
Hans Verkuilbec43662008-12-30 06:58:20 -03001029 int minor = video_devdata(file)->minor;
Trent Piephoa991f442007-10-10 05:37:43 -03001030 struct vivi_dev *dev;
Mauro Carvalho Chehab63b79cf2008-04-26 08:25:18 -03001031 struct vivi_fh *fh = NULL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001032 int i;
Brandon Philipsaa9dbac2008-04-02 18:10:59 -03001033 int retval = 0;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001034
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001035 printk(KERN_DEBUG "vivi: open called (minor=%d)\n", minor);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001036
Hans Verkuild56dc612008-07-30 08:43:36 -03001037 lock_kernel();
Trent Piephoa991f442007-10-10 05:37:43 -03001038 list_for_each_entry(dev, &vivi_devlist, vivi_devlist)
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001039 if (dev->vfd->minor == minor)
Trent Piephoa991f442007-10-10 05:37:43 -03001040 goto found;
Hans Verkuild56dc612008-07-30 08:43:36 -03001041 unlock_kernel();
Trent Piephoa991f442007-10-10 05:37:43 -03001042 return -ENODEV;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001043
Trent Piephoa991f442007-10-10 05:37:43 -03001044found:
Brandon Philipsaa9dbac2008-04-02 18:10:59 -03001045 mutex_lock(&dev->mutex);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001046 dev->users++;
1047
Brandon Philipsaa9dbac2008-04-02 18:10:59 -03001048 if (dev->users > 1) {
1049 dev->users--;
1050 retval = -EBUSY;
1051 goto unlock;
1052 }
1053
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -03001054 dprintk(dev, 1, "open minor=%d type=%s users=%d\n", minor,
Trent Piephoa991f442007-10-10 05:37:43 -03001055 v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001056
1057 /* allocate + initialize per filehandle data */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001058 fh = kzalloc(sizeof(*fh), GFP_KERNEL);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001059 if (NULL == fh) {
1060 dev->users--;
Brandon Philipsaa9dbac2008-04-02 18:10:59 -03001061 retval = -ENOMEM;
1062 goto unlock;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001063 }
Brandon Philipsaa9dbac2008-04-02 18:10:59 -03001064unlock:
1065 mutex_unlock(&dev->mutex);
Hans Verkuild56dc612008-07-30 08:43:36 -03001066 if (retval) {
1067 unlock_kernel();
Brandon Philipsaa9dbac2008-04-02 18:10:59 -03001068 return retval;
Hans Verkuild56dc612008-07-30 08:43:36 -03001069 }
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001070
1071 file->private_data = fh;
1072 fh->dev = dev;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001073
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001074 fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
Magnus Dammd891f472008-10-14 12:47:09 -03001075 fh->fmt = &formats[0];
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001076 fh->width = 640;
1077 fh->height = 480;
1078
1079 /* Put all controls at a sane state */
1080 for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001081 qctl_regs[i] = vivi_qctrl[i].default_value;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001082
1083 /* Resets frame counters */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001084 dev->h = 0;
1085 dev->m = 0;
1086 dev->s = 0;
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -03001087 dev->ms = 0;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001088 dev->mv_count = 0;
1089 dev->jiffies = jiffies;
1090 sprintf(dev->timestr, "%02d:%02d:%02d:%03d",
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -03001091 dev->h, dev->m, dev->s, dev->ms);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001092
Mauro Carvalho Chehab5a037702007-08-02 23:31:54 -03001093 videobuf_queue_vmalloc_init(&fh->vb_vidq, &vivi_video_qops,
Mauro Carvalho Chehab55862ac2007-12-13 16:13:37 -03001094 NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED,
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001095 sizeof(struct vivi_buffer), fh);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001096
Brandon Philips78718e52008-04-02 18:10:59 -03001097 vivi_start_thread(fh);
Hans Verkuild56dc612008-07-30 08:43:36 -03001098 unlock_kernel();
Brandon Philips78718e52008-04-02 18:10:59 -03001099
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001100 return 0;
1101}
1102
1103static ssize_t
1104vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
1105{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001106 struct vivi_fh *fh = file->private_data;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001107
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001108 if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
Mauro Carvalho Chehabacb09af2007-07-29 22:56:11 -03001109 return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001110 file->f_flags & O_NONBLOCK);
1111 }
1112 return 0;
1113}
1114
1115static unsigned int
1116vivi_poll(struct file *file, struct poll_table_struct *wait)
1117{
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001118 struct vivi_fh *fh = file->private_data;
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -03001119 struct vivi_dev *dev = fh->dev;
Brandon Philips85c7c70bc2007-09-27 20:55:02 -03001120 struct videobuf_queue *q = &fh->vb_vidq;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001121
Harvey Harrison7e28adb2008-04-08 23:20:00 -03001122 dprintk(dev, 1, "%s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001123
1124 if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
1125 return POLLERR;
1126
Brandon Philips85c7c70bc2007-09-27 20:55:02 -03001127 return videobuf_poll_stream(file, q, wait);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001128}
1129
Hans Verkuilbec43662008-12-30 06:58:20 -03001130static int vivi_close(struct file *file)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001131{
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001132 struct vivi_fh *fh = file->private_data;
1133 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001134 struct vivi_dmaqueue *vidq = &dev->vidq;
1135
Hans Verkuilbec43662008-12-30 06:58:20 -03001136 int minor = video_devdata(file)->minor;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001137
1138 vivi_stop_thread(vidq);
Brandon Philips053fcb62007-11-13 20:11:26 -03001139 videobuf_stop(&fh->vb_vidq);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001140 videobuf_mmap_free(&fh->vb_vidq);
1141
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001142 kfree(fh);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001143
Brandon Philipsaa9dbac2008-04-02 18:10:59 -03001144 mutex_lock(&dev->mutex);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001145 dev->users--;
Brandon Philipsaa9dbac2008-04-02 18:10:59 -03001146 mutex_unlock(&dev->mutex);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001147
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -03001148 dprintk(dev, 1, "close called (minor=%d, users=%d)\n",
1149 minor, dev->users);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001150
1151 return 0;
1152}
1153
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001154static int vivi_release(void)
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001155{
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001156 struct vivi_dev *dev;
1157 struct list_head *list;
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001158
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001159 while (!list_empty(&vivi_devlist)) {
1160 list = vivi_devlist.next;
1161 list_del(list);
1162 dev = list_entry(list, struct vivi_dev, vivi_devlist);
1163
Carl Karsten745271a2008-06-10 00:02:32 -03001164 if (-1 != dev->vfd->minor) {
Adrian Bunk8da9bae2008-09-03 17:12:25 -03001165 printk(KERN_INFO "%s: unregistering /dev/video%d\n",
Hans Verkuilc6330fb2008-10-19 18:54:26 -03001166 VIVI_MODULE_NAME, dev->vfd->num);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001167 video_unregister_device(dev->vfd);
Carl Karsten745271a2008-06-10 00:02:32 -03001168 } else {
Adrian Bunk8da9bae2008-09-03 17:12:25 -03001169 printk(KERN_INFO "%s: releasing /dev/video%d\n",
Hans Verkuilc6330fb2008-10-19 18:54:26 -03001170 VIVI_MODULE_NAME, dev->vfd->num);
Adrian Bunk8da9bae2008-09-03 17:12:25 -03001171 video_device_release(dev->vfd);
Carl Karsten745271a2008-06-10 00:02:32 -03001172 }
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001173
1174 kfree(dev);
1175 }
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001176
1177 return 0;
1178}
1179
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001180static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001181{
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -03001182 struct vivi_fh *fh = file->private_data;
1183 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001184 int ret;
1185
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -03001186 dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001187
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001188 ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001189
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -03001190 dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n",
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001191 (unsigned long)vma->vm_start,
1192 (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
1193 ret);
1194
1195 return ret;
1196}
1197
Hans Verkuilbec43662008-12-30 06:58:20 -03001198static const struct v4l2_file_operations vivi_fops = {
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001199 .owner = THIS_MODULE,
1200 .open = vivi_open,
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001201 .release = vivi_close,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001202 .read = vivi_read,
1203 .poll = vivi_poll,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001204 .ioctl = video_ioctl2, /* V4L2 ioctl handler */
Mauro Carvalho Chehab5a037702007-08-02 23:31:54 -03001205 .mmap = vivi_mmap,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001206};
1207
Hans Verkuila3998102008-07-21 02:57:38 -03001208static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001209 .vidioc_querycap = vidioc_querycap,
Hans Verkuil78b526a2008-05-28 12:16:41 -03001210 .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
1211 .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
1212 .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
1213 .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001214 .vidioc_reqbufs = vidioc_reqbufs,
1215 .vidioc_querybuf = vidioc_querybuf,
1216 .vidioc_qbuf = vidioc_qbuf,
1217 .vidioc_dqbuf = vidioc_dqbuf,
1218 .vidioc_s_std = vidioc_s_std,
1219 .vidioc_enum_input = vidioc_enum_input,
1220 .vidioc_g_input = vidioc_g_input,
1221 .vidioc_s_input = vidioc_s_input,
1222 .vidioc_queryctrl = vidioc_queryctrl,
1223 .vidioc_g_ctrl = vidioc_g_ctrl,
1224 .vidioc_s_ctrl = vidioc_s_ctrl,
1225 .vidioc_streamon = vidioc_streamon,
1226 .vidioc_streamoff = vidioc_streamoff,
Mauro Carvalho Chehab0dfa9ab2006-08-08 09:10:10 -03001227#ifdef CONFIG_VIDEO_V4L1_COMPAT
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001228 .vidiocgmbuf = vidiocgmbuf,
1229#endif
Hans Verkuila3998102008-07-21 02:57:38 -03001230};
1231
1232static struct video_device vivi_template = {
1233 .name = "vivi",
Hans Verkuila3998102008-07-21 02:57:38 -03001234 .fops = &vivi_fops,
1235 .ioctl_ops = &vivi_ioctl_ops,
1236 .minor = -1,
1237 .release = video_device_release,
1238
Mauro Carvalho Chehab784c6682007-12-13 06:35:26 -03001239 .tvnorms = V4L2_STD_525_60,
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -03001240 .current_norm = V4L2_STD_NTSC_M,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001241};
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001242/* -----------------------------------------------------------------
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001243 Initialization and module stuff
1244 ------------------------------------------------------------------*/
1245
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001246/* This routine allocates from 1 to n_devs virtual drivers.
1247
1248 The real maximum number of virtual drivers will depend on how many drivers
1249 will succeed. This is limited to the maximum number of devices that
1250 videodev supports. Since there are 64 minors for video grabbers, this is
1251 currently the theoretical maximum limit. However, a further limit does
1252 exist at videodev that forbids any driver to register more than 32 video
1253 grabbers.
1254 */
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001255static int __init vivi_init(void)
1256{
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001257 int ret = -ENOMEM, i;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001258 struct vivi_dev *dev;
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001259 struct video_device *vfd;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001260
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001261 if (n_devs <= 0)
1262 n_devs = 1;
1263
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001264 for (i = 0; i < n_devs; i++) {
1265 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001266 if (!dev)
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001267 break;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001268
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001269 /* init video dma queues */
1270 INIT_LIST_HEAD(&dev->vidq.active);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001271 init_waitqueue_head(&dev->vidq.wq);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001272
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001273 /* initialize locks */
Mauro Carvalho Chehab55862ac2007-12-13 16:13:37 -03001274 spin_lock_init(&dev->slock);
Brandon Philipsaa9dbac2008-04-02 18:10:59 -03001275 mutex_init(&dev->mutex);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001276
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001277 vfd = video_device_alloc();
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001278 if (!vfd) {
1279 kfree(dev);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001280 break;
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001281 }
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001282
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001283 *vfd = vivi_template;
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001284
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001285 ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001286 if (ret < 0) {
1287 video_device_release(vfd);
1288 kfree(dev);
1289
1290 /* If some registers succeeded, keep driver */
1291 if (i)
1292 ret = 0;
1293
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001294 break;
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001295 }
1296
1297 /* Now that everything is fine, let's add it to device list */
1298 list_add_tail(&dev->vivi_devlist, &vivi_devlist);
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001299
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001300 snprintf(vfd->name, sizeof(vfd->name), "%s (%i)",
1301 vivi_template.name, vfd->minor);
1302
1303 if (video_nr >= 0)
1304 video_nr++;
1305
1306 dev->vfd = vfd;
Carl Karsten745271a2008-06-10 00:02:32 -03001307 printk(KERN_INFO "%s: V4L2 device registered as /dev/video%d\n",
Hans Verkuilc6330fb2008-10-19 18:54:26 -03001308 VIVI_MODULE_NAME, vfd->num);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001309 }
1310
1311 if (ret < 0) {
1312 vivi_release();
1313 printk(KERN_INFO "Error %d while loading vivi driver\n", ret);
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001314 } else {
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001315 printk(KERN_INFO "Video Technology Magazine Virtual Video "
Carl Karsten745271a2008-06-10 00:02:32 -03001316 "Capture Board ver %u.%u.%u successfully loaded.\n",
1317 (VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF,
1318 VIVI_VERSION & 0xFF);
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001319
1320 /* n_devs will reflect the actual number of allocated devices */
1321 n_devs = i;
1322 }
1323
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001324 return ret;
1325}
1326
1327static void __exit vivi_exit(void)
1328{
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001329 vivi_release();
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001330}
1331
1332module_init(vivi_init);
1333module_exit(vivi_exit);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001334
1335MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
1336MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
1337MODULE_LICENSE("Dual BSD/GPL");
1338
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001339module_param(video_nr, uint, 0444);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001340MODULE_PARM_DESC(video_nr, "video iminor start number");
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001341
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001342module_param(n_devs, uint, 0444);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001343MODULE_PARM_DESC(n_devs, "number of video devices to create");
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001344
Mauro Carvalho Chehab8996b3f2007-12-13 06:36:22 -03001345module_param_named(debug, vivi_template.debug, int, 0444);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001346MODULE_PARM_DESC(debug, "activates debug info");
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001347
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001348module_param(vid_limit, int, 0644);
1349MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");