blob: f55d77db1558f80d8540ff38181bd3817ef92b07 [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
131static struct vivi_fmt format = {
132 .name = "4:2:2, packed, YUYV",
133 .fourcc = V4L2_PIX_FMT_YUYV,
134 .depth = 16,
135};
136
137struct sg_to_addr {
138 int pos;
139 struct scatterlist *sg;
140};
141
142/* buffer for one video frame */
143struct vivi_buffer {
144 /* common v4l buffer stuff -- must be first */
145 struct videobuf_buffer vb;
146
147 struct vivi_fmt *fmt;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300148};
149
150struct vivi_dmaqueue {
151 struct list_head active;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300152
153 /* thread for generating video stream*/
154 struct task_struct *kthread;
155 wait_queue_head_t wq;
156 /* Counters to control fps rate */
157 int frame;
158 int ini_jiffies;
159};
160
161static LIST_HEAD(vivi_devlist);
162
163struct vivi_dev {
164 struct list_head vivi_devlist;
165
Mauro Carvalho Chehab55862ac2007-12-13 16:13:37 -0300166 spinlock_t slock;
Brandon Philipsaa9dbac2008-04-02 18:10:59 -0300167 struct mutex mutex;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300168
169 int users;
170
171 /* various device info */
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -0300172 struct video_device *vfd;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300173
174 struct vivi_dmaqueue vidq;
175
176 /* Several counters */
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -0300177 int h, m, s, ms;
178 unsigned long jiffies;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300179 char timestr[13];
Mauro Carvalho Chehab025341d2007-12-10 04:43:38 -0300180
181 int mv_count; /* Controls bars movement */
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300182};
183
184struct vivi_fh {
185 struct vivi_dev *dev;
186
187 /* video capture */
188 struct vivi_fmt *fmt;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300189 unsigned int width, height;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300190 struct videobuf_queue vb_vidq;
191
192 enum v4l2_buf_type type;
193};
194
195/* ------------------------------------------------------------------
196 DMA and thread functions
197 ------------------------------------------------------------------*/
198
199/* Bars and Colors should match positions */
200
201enum colors {
202 WHITE,
203 AMBAR,
204 CYAN,
205 GREEN,
206 MAGENTA,
207 RED,
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300208 BLUE,
209 BLACK,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300210};
211
212static u8 bars[8][3] = {
213 /* R G B */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300214 {204, 204, 204}, /* white */
215 {208, 208, 0}, /* ambar */
216 { 0, 206, 206}, /* cyan */
217 { 0, 239, 0}, /* green */
218 {239, 0, 239}, /* magenta */
219 {205, 0, 0}, /* red */
220 { 0, 0, 255}, /* blue */
221 { 0, 0, 0}, /* black */
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300222};
223
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300224#define TO_Y(r, g, b) \
225 (((16829 * r + 33039 * g + 6416 * b + 32768) >> 16) + 16)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300226/* RGB to V(Cr) Color transform */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300227#define TO_V(r, g, b) \
228 (((28784 * r - 24103 * g - 4681 * b + 32768) >> 16) + 128)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300229/* RGB to U(Cb) Color transform */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300230#define TO_U(r, g, b) \
231 (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300232
233#define TSTAMP_MIN_Y 24
234#define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
235#define TSTAMP_MIN_X 64
236
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300237static void gen_line(char *basep, int inipos, int wmax,
238 int hmax, int line, int count, char *timestr)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300239{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300240 int w, i, j, y;
241 int pos = inipos;
242 char *p, *s;
243 u8 chr, r, g, b, color;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300244
245 /* We will just duplicate the second pixel at the packet */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300246 wmax /= 2;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300247
248 /* Generate a standard color bar pattern */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300249 for (w = 0; w < wmax; w++) {
250 int colorpos = ((w + count) * 8/(wmax + 1)) % 8;
251 r = bars[colorpos][0];
252 g = bars[colorpos][1];
253 b = bars[colorpos][2];
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300254
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300255 for (color = 0; color < 4; color++) {
256 p = basep + pos;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300257
258 switch (color) {
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300259 case 0:
260 case 2:
261 *p = TO_Y(r, g, b); /* Luma */
262 break;
263 case 1:
264 *p = TO_U(r, g, b); /* Cb */
265 break;
266 case 3:
267 *p = TO_V(r, g, b); /* Cr */
268 break;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300269 }
270 pos++;
271 }
272 }
273
274 /* Checks if it is possible to show timestamp */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300275 if (TSTAMP_MAX_Y >= hmax)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300276 goto end;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300277 if (TSTAMP_MIN_X + strlen(timestr) >= wmax)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300278 goto end;
279
280 /* Print stream time */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300281 if (line >= TSTAMP_MIN_Y && line <= TSTAMP_MAX_Y) {
282 j = TSTAMP_MIN_X;
283 for (s = timestr; *s; s++) {
284 chr = rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y];
285 for (i = 0; i < 7; i++) {
286 if (chr & 1 << (7 - i)) {
287 /* Font color*/
288 r = 0;
289 g = 198;
290 b = 0;
291 } else {
292 /* Background color */
293 r = bars[BLACK][0];
294 g = bars[BLACK][1];
295 b = bars[BLACK][2];
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300296 }
297
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300298 pos = inipos + j * 2;
299 for (color = 0; color < 4; color++) {
300 p = basep + pos;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300301
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300302 y = TO_Y(r, g, b);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300303
304 switch (color) {
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300305 case 0:
306 case 2:
307 *p = TO_Y(r, g, b); /* Luma */
308 break;
309 case 1:
310 *p = TO_U(r, g, b); /* Cb */
311 break;
312 case 3:
313 *p = TO_V(r, g, b); /* Cr */
314 break;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300315 }
316 pos++;
317 }
318 j++;
319 }
320 }
321 }
322
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300323end:
Mauro Carvalho Chehabb50e7fe2007-01-25 05:00:01 -0300324 return;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300325}
Brandon Philips78718e52008-04-02 18:10:59 -0300326
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300327static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300328{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300329 int h , pos = 0;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300330 int hmax = buf->vb.height;
331 int wmax = buf->vb.width;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300332 struct timeval ts;
Marcin Slusarz5c554e62008-06-22 09:11:40 -0300333 char *tmpbuf;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300334 void *vbuf = videobuf_to_vmalloc(&buf->vb);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300335
Marcin Slusarz5c554e62008-06-22 09:11:40 -0300336 if (!vbuf)
Mauro Carvalho Chehab5a037702007-08-02 23:31:54 -0300337 return;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300338
Marcin Slusarz5c554e62008-06-22 09:11:40 -0300339 tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC);
340 if (!tmpbuf)
Brandon Philips78718e52008-04-02 18:10:59 -0300341 return;
342
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300343 for (h = 0; h < hmax; h++) {
Mauro Carvalho Chehab025341d2007-12-10 04:43:38 -0300344 gen_line(tmpbuf, 0, wmax, hmax, h, dev->mv_count,
Mauro Carvalho Chehab3bef5e42007-09-22 02:01:33 -0300345 dev->timestr);
Brandon Philips78718e52008-04-02 18:10:59 -0300346 memcpy(vbuf + pos, tmpbuf, wmax * 2);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300347 pos += wmax*2;
348 }
349
Mauro Carvalho Chehab025341d2007-12-10 04:43:38 -0300350 dev->mv_count++;
Mauro Carvalho Chehab3bef5e42007-09-22 02:01:33 -0300351
Mauro Carvalho Chehab5a037702007-08-02 23:31:54 -0300352 kfree(tmpbuf);
353
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300354 /* Updates stream time */
355
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -0300356 dev->ms += jiffies_to_msecs(jiffies-dev->jiffies);
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300357 dev->jiffies = jiffies;
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -0300358 if (dev->ms >= 1000) {
359 dev->ms -= 1000;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300360 dev->s++;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300361 if (dev->s >= 60) {
362 dev->s -= 60;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300363 dev->m++;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300364 if (dev->m > 60) {
365 dev->m -= 60;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300366 dev->h++;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300367 if (dev->h > 24)
368 dev->h -= 24;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300369 }
370 }
371 }
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300372 sprintf(dev->timestr, "%02d:%02d:%02d:%03d",
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -0300373 dev->h, dev->m, dev->s, dev->ms);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300374
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300375 dprintk(dev, 2, "vivifill at %s: Buffer 0x%08lx size= %d\n",
376 dev->timestr, (unsigned long)tmpbuf, pos);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300377
378 /* Advice that buffer was filled */
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300379 buf->vb.field_count++;
380 do_gettimeofday(&ts);
381 buf->vb.ts = ts;
Brandon Philips78718e52008-04-02 18:10:59 -0300382 buf->vb.state = VIDEOBUF_DONE;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300383}
384
Brandon Philips78718e52008-04-02 18:10:59 -0300385static void vivi_thread_tick(struct vivi_fh *fh)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300386{
Brandon Philips78718e52008-04-02 18:10:59 -0300387 struct vivi_buffer *buf;
388 struct vivi_dev *dev = fh->dev;
389 struct vivi_dmaqueue *dma_q = &dev->vidq;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300390
Brandon Philips78718e52008-04-02 18:10:59 -0300391 unsigned long flags = 0;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300392
Brandon Philips78718e52008-04-02 18:10:59 -0300393 dprintk(dev, 1, "Thread tick\n");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300394
Brandon Philips78718e52008-04-02 18:10:59 -0300395 spin_lock_irqsave(&dev->slock, flags);
396 if (list_empty(&dma_q->active)) {
397 dprintk(dev, 1, "No active queue to serve\n");
398 goto unlock;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300399 }
Brandon Philips78718e52008-04-02 18:10:59 -0300400
401 buf = list_entry(dma_q->active.next,
402 struct vivi_buffer, vb.queue);
403
404 /* Nobody is waiting on this buffer, return */
405 if (!waitqueue_active(&buf->vb.done))
406 goto unlock;
407
408 list_del(&buf->vb.queue);
409
410 do_gettimeofday(&buf->vb.ts);
411
412 /* Fill buffer */
413 vivi_fillbuff(dev, buf);
414 dprintk(dev, 1, "filled buffer %p\n", buf);
415
416 wake_up(&buf->vb.done);
417 dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i);
418unlock:
419 spin_unlock_irqrestore(&dev->slock, flags);
420 return;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300421}
422
Mauro Carvalho Chehab6594ad82007-12-13 16:15:41 -0300423#define frames_to_ms(frames) \
424 ((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR)
425
Brandon Philips78718e52008-04-02 18:10:59 -0300426static void vivi_sleep(struct vivi_fh *fh)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300427{
Brandon Philips78718e52008-04-02 18:10:59 -0300428 struct vivi_dev *dev = fh->dev;
429 struct vivi_dmaqueue *dma_q = &dev->vidq;
430 int timeout;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300431 DECLARE_WAITQUEUE(wait, current);
432
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300433 dprintk(dev, 1, "%s dma_q=0x%08lx\n", __func__,
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300434 (unsigned long)dma_q);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300435
436 add_wait_queue(&dma_q->wq, &wait);
Mauro Carvalho Chehab6594ad82007-12-13 16:15:41 -0300437 if (kthread_should_stop())
438 goto stop_task;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300439
Mauro Carvalho Chehab6594ad82007-12-13 16:15:41 -0300440 /* Calculate time to wake up */
Brandon Philips78718e52008-04-02 18:10:59 -0300441 timeout = msecs_to_jiffies(frames_to_ms(1));
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300442
Brandon Philips78718e52008-04-02 18:10:59 -0300443 vivi_thread_tick(fh);
Mauro Carvalho Chehab6594ad82007-12-13 16:15:41 -0300444
445 schedule_timeout_interruptible(timeout);
446
447stop_task:
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300448 remove_wait_queue(&dma_q->wq, &wait);
449 try_to_freeze();
450}
451
Adrian Bunk972c3512006-04-27 21:06:50 -0300452static int vivi_thread(void *data)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300453{
Brandon Philips78718e52008-04-02 18:10:59 -0300454 struct vivi_fh *fh = data;
455 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300456
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300457 dprintk(dev, 1, "thread started\n");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300458
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700459 set_freezable();
Mauro Carvalho Chehab0b600512007-01-14 08:33:24 -0300460
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300461 for (;;) {
Brandon Philips78718e52008-04-02 18:10:59 -0300462 vivi_sleep(fh);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300463
464 if (kthread_should_stop())
465 break;
466 }
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300467 dprintk(dev, 1, "thread: exit\n");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300468 return 0;
469}
470
Brandon Philips78718e52008-04-02 18:10:59 -0300471static int vivi_start_thread(struct vivi_fh *fh)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300472{
Brandon Philips78718e52008-04-02 18:10:59 -0300473 struct vivi_dev *dev = fh->dev;
474 struct vivi_dmaqueue *dma_q = &dev->vidq;
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300475
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300476 dma_q->frame = 0;
477 dma_q->ini_jiffies = jiffies;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300478
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300479 dprintk(dev, 1, "%s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300480
Brandon Philips78718e52008-04-02 18:10:59 -0300481 dma_q->kthread = kthread_run(vivi_thread, fh, "vivi");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300482
Akinobu Mita054afee2006-12-20 10:04:00 -0300483 if (IS_ERR(dma_q->kthread)) {
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300484 printk(KERN_ERR "vivi: kernel_thread() failed\n");
Akinobu Mita054afee2006-12-20 10:04:00 -0300485 return PTR_ERR(dma_q->kthread);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300486 }
Mauro Carvalho Chehab0b600512007-01-14 08:33:24 -0300487 /* Wakes thread */
488 wake_up_interruptible(&dma_q->wq);
489
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300490 dprintk(dev, 1, "returning from %s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300491 return 0;
492}
493
Adrian Bunk972c3512006-04-27 21:06:50 -0300494static void vivi_stop_thread(struct vivi_dmaqueue *dma_q)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300495{
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300496 struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
497
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300498 dprintk(dev, 1, "%s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300499 /* shutdown control thread */
500 if (dma_q->kthread) {
501 kthread_stop(dma_q->kthread);
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300502 dma_q->kthread = NULL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300503 }
504}
505
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300506/* ------------------------------------------------------------------
507 Videobuf operations
508 ------------------------------------------------------------------*/
509static int
510buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
511{
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300512 struct vivi_fh *fh = vq->priv_data;
513 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300514
515 *size = fh->width*fh->height*2;
516
517 if (0 == *count)
518 *count = 32;
Mauro Carvalho Chehab6bb27902007-08-23 16:41:14 -0300519
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300520 while (*size * *count > vid_limit * 1024 * 1024)
521 (*count)--;
Mauro Carvalho Chehab6bb27902007-08-23 16:41:14 -0300522
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300523 dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__,
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300524 *count, *size);
Mauro Carvalho Chehab6bb27902007-08-23 16:41:14 -0300525
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300526 return 0;
527}
528
Adrian Bunk972c3512006-04-27 21:06:50 -0300529static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300530{
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300531 struct vivi_fh *fh = vq->priv_data;
532 struct vivi_dev *dev = fh->dev;
533
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300534 dprintk(dev, 1, "%s, state: %i\n", __func__, buf->vb.state);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300535
536 if (in_interrupt())
537 BUG();
538
Mauro Carvalho Chehab5a037702007-08-02 23:31:54 -0300539 videobuf_vmalloc_free(&buf->vb);
Mauro Carvalho Chehabfbde31d2008-04-13 14:57:44 -0300540 dprintk(dev, 1, "free_buffer: freed\n");
Brandon Philips0fc06862007-11-06 20:02:36 -0300541 buf->vb.state = VIDEOBUF_NEEDS_INIT;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300542}
543
544#define norm_maxw() 1024
545#define norm_maxh() 768
546static int
547buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
548 enum v4l2_field field)
549{
550 struct vivi_fh *fh = vq->priv_data;
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300551 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300552 struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
Brandon Philips78718e52008-04-02 18:10:59 -0300553 int rc;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300554
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300555 dprintk(dev, 1, "%s, field=%d\n", __func__, field);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300556
557 BUG_ON(NULL == fh->fmt);
Brandon Philips78718e52008-04-02 18:10:59 -0300558
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300559 if (fh->width < 48 || fh->width > norm_maxw() ||
560 fh->height < 32 || fh->height > norm_maxh())
561 return -EINVAL;
Brandon Philips78718e52008-04-02 18:10:59 -0300562
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300563 buf->vb.size = fh->width*fh->height*2;
564 if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
565 return -EINVAL;
566
Brandon Philips78718e52008-04-02 18:10:59 -0300567 /* These properties only change when queue is idle, see s_fmt */
568 buf->fmt = fh->fmt;
569 buf->vb.width = fh->width;
570 buf->vb.height = fh->height;
571 buf->vb.field = field;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300572
Brandon Philips0fc06862007-11-06 20:02:36 -0300573 if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300574 rc = videobuf_iolock(vq, &buf->vb, NULL);
575 if (rc < 0)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300576 goto fail;
577 }
578
Brandon Philips0fc06862007-11-06 20:02:36 -0300579 buf->vb.state = VIDEOBUF_PREPARED;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300580
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300581 return 0;
582
583fail:
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300584 free_buffer(vq, buf);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300585 return rc;
586}
587
588static void
589buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
590{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300591 struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
592 struct vivi_fh *fh = vq->priv_data;
593 struct vivi_dev *dev = fh->dev;
Brandon Philips78718e52008-04-02 18:10:59 -0300594 struct vivi_dmaqueue *vidq = &dev->vidq;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300595
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300596 dprintk(dev, 1, "%s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300597
Brandon Philips78718e52008-04-02 18:10:59 -0300598 buf->vb.state = VIDEOBUF_QUEUED;
599 list_add_tail(&buf->vb.queue, &vidq->active);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300600}
601
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300602static void buffer_release(struct videobuf_queue *vq,
603 struct videobuf_buffer *vb)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300604{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300605 struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300606 struct vivi_fh *fh = vq->priv_data;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300607 struct vivi_dev *dev = (struct vivi_dev *)fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300608
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300609 dprintk(dev, 1, "%s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300610
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300611 free_buffer(vq, buf);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300612}
613
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300614static struct videobuf_queue_ops vivi_video_qops = {
615 .buf_setup = buffer_setup,
616 .buf_prepare = buffer_prepare,
617 .buf_queue = buffer_queue,
618 .buf_release = buffer_release,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300619};
620
621/* ------------------------------------------------------------------
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300622 IOCTL vidioc handling
623 ------------------------------------------------------------------*/
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300624static int vidioc_querycap(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300625 struct v4l2_capability *cap)
626{
627 strcpy(cap->driver, "vivi");
628 strcpy(cap->card, "vivi");
629 cap->version = VIVI_VERSION;
630 cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
631 V4L2_CAP_STREAMING |
632 V4L2_CAP_READWRITE;
633 return 0;
634}
635
Hans Verkuil78b526a2008-05-28 12:16:41 -0300636static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300637 struct v4l2_fmtdesc *f)
638{
639 if (f->index > 0)
640 return -EINVAL;
641
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300642 strlcpy(f->description, format.name, sizeof(f->description));
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300643 f->pixelformat = format.fourcc;
644 return 0;
645}
646
Hans Verkuil78b526a2008-05-28 12:16:41 -0300647static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300648 struct v4l2_format *f)
649{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300650 struct vivi_fh *fh = priv;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300651
652 f->fmt.pix.width = fh->width;
653 f->fmt.pix.height = fh->height;
654 f->fmt.pix.field = fh->vb_vidq.field;
655 f->fmt.pix.pixelformat = fh->fmt->fourcc;
656 f->fmt.pix.bytesperline =
657 (f->fmt.pix.width * fh->fmt->depth) >> 3;
658 f->fmt.pix.sizeimage =
659 f->fmt.pix.height * f->fmt.pix.bytesperline;
660
661 return (0);
662}
663
Hans Verkuil78b526a2008-05-28 12:16:41 -0300664static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300665 struct v4l2_format *f)
666{
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300667 struct vivi_fh *fh = priv;
668 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300669 struct vivi_fmt *fmt;
670 enum v4l2_field field;
671 unsigned int maxw, maxh;
672
673 if (format.fourcc != f->fmt.pix.pixelformat) {
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300674 dprintk(dev, 1, "Fourcc format (0x%08x) invalid. "
675 "Driver accepts only 0x%08x\n",
676 f->fmt.pix.pixelformat, format.fourcc);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300677 return -EINVAL;
678 }
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300679 fmt = &format;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300680
681 field = f->fmt.pix.field;
682
683 if (field == V4L2_FIELD_ANY) {
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300684 field = V4L2_FIELD_INTERLACED;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300685 } else if (V4L2_FIELD_INTERLACED != field) {
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300686 dprintk(dev, 1, "Field type invalid.\n");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300687 return -EINVAL;
688 }
689
690 maxw = norm_maxw();
691 maxh = norm_maxh();
692
693 f->fmt.pix.field = field;
694 if (f->fmt.pix.height < 32)
695 f->fmt.pix.height = 32;
696 if (f->fmt.pix.height > maxh)
697 f->fmt.pix.height = maxh;
698 if (f->fmt.pix.width < 48)
699 f->fmt.pix.width = 48;
700 if (f->fmt.pix.width > maxw)
701 f->fmt.pix.width = maxw;
702 f->fmt.pix.width &= ~0x03;
703 f->fmt.pix.bytesperline =
704 (f->fmt.pix.width * fmt->depth) >> 3;
705 f->fmt.pix.sizeimage =
706 f->fmt.pix.height * f->fmt.pix.bytesperline;
707
708 return 0;
709}
710
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300711/*FIXME: This seems to be generic enough to be at videodev2 */
Hans Verkuil78b526a2008-05-28 12:16:41 -0300712static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300713 struct v4l2_format *f)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300714{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300715 struct vivi_fh *fh = priv;
Brandon Philips78718e52008-04-02 18:10:59 -0300716 struct videobuf_queue *q = &fh->vb_vidq;
717
Hans Verkuil78b526a2008-05-28 12:16:41 -0300718 int ret = vidioc_try_fmt_vid_cap(file, fh, f);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300719 if (ret < 0)
720 return (ret);
721
Brandon Philips78718e52008-04-02 18:10:59 -0300722 mutex_lock(&q->vb_lock);
723
724 if (videobuf_queue_is_busy(&fh->vb_vidq)) {
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300725 dprintk(fh->dev, 1, "%s queue busy\n", __func__);
Brandon Philips78718e52008-04-02 18:10:59 -0300726 ret = -EBUSY;
727 goto out;
728 }
729
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300730 fh->fmt = &format;
731 fh->width = f->fmt.pix.width;
732 fh->height = f->fmt.pix.height;
733 fh->vb_vidq.field = f->fmt.pix.field;
734 fh->type = f->type;
735
Brandon Philips78718e52008-04-02 18:10:59 -0300736 ret = 0;
737out:
738 mutex_unlock(&q->vb_lock);
739
740 return (ret);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300741}
742
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300743static int vidioc_reqbufs(struct file *file, void *priv,
744 struct v4l2_requestbuffers *p)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300745{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300746 struct vivi_fh *fh = priv;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300747
748 return (videobuf_reqbufs(&fh->vb_vidq, p));
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300749}
750
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300751static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300752{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300753 struct vivi_fh *fh = priv;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300754
755 return (videobuf_querybuf(&fh->vb_vidq, p));
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300756}
757
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300758static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300759{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300760 struct vivi_fh *fh = priv;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300761
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300762 return (videobuf_qbuf(&fh->vb_vidq, p));
763}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300764
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300765static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300766{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300767 struct vivi_fh *fh = priv;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300768
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300769 return (videobuf_dqbuf(&fh->vb_vidq, p,
770 file->f_flags & O_NONBLOCK));
771}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300772
Mauro Carvalho Chehab0dfa9ab2006-08-08 09:10:10 -0300773#ifdef CONFIG_VIDEO_V4L1_COMPAT
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300774static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300775{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300776 struct vivi_fh *fh = priv;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300777
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300778 return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300779}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300780#endif
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300781
Adrian Bunkdc46ace2006-06-23 06:42:44 -0300782static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300783{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300784 struct vivi_fh *fh = priv;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300785
786 if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
787 return -EINVAL;
788 if (i != fh->type)
789 return -EINVAL;
790
Brandon Philipsba32bd92007-09-27 20:55:17 -0300791 return videobuf_streamon(&fh->vb_vidq);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300792}
793
Adrian Bunkdc46ace2006-06-23 06:42:44 -0300794static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300795{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300796 struct vivi_fh *fh = priv;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300797
798 if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
799 return -EINVAL;
800 if (i != fh->type)
801 return -EINVAL;
802
Brandon Philipsba32bd92007-09-27 20:55:17 -0300803 return videobuf_streamoff(&fh->vb_vidq);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300804}
805
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300806static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300807{
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300808 return 0;
809}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300810
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300811/* only one input in this sample driver */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300812static int vidioc_enum_input(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300813 struct v4l2_input *inp)
814{
815 if (inp->index != 0)
816 return -EINVAL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300817
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300818 inp->type = V4L2_INPUT_TYPE_CAMERA;
Mauro Carvalho Chehab784c6682007-12-13 06:35:26 -0300819 inp->std = V4L2_STD_525_60;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300820 strcpy(inp->name, "Camera");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300821
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300822 return (0);
823}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300824
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300825static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300826{
827 *i = 0;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300828
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300829 return (0);
830}
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300831static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300832{
833 if (i > 0)
834 return -EINVAL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300835
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300836 return (0);
837}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300838
839 /* --- controls ---------------------------------------------- */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300840static int vidioc_queryctrl(struct file *file, void *priv,
841 struct v4l2_queryctrl *qc)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300842{
843 int i;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300844
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300845 for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
846 if (qc->id && qc->id == vivi_qctrl[i].id) {
847 memcpy(qc, &(vivi_qctrl[i]),
848 sizeof(*qc));
849 return (0);
850 }
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300851
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300852 return -EINVAL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300853}
854
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300855static int vidioc_g_ctrl(struct file *file, void *priv,
856 struct v4l2_control *ctrl)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300857{
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300858 int i;
859
860 for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
861 if (ctrl->id == vivi_qctrl[i].id) {
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300862 ctrl->value = qctl_regs[i];
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300863 return (0);
864 }
865
866 return -EINVAL;
867}
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300868static int vidioc_s_ctrl(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300869 struct v4l2_control *ctrl)
870{
871 int i;
872
873 for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
874 if (ctrl->id == vivi_qctrl[i].id) {
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300875 if (ctrl->value < vivi_qctrl[i].minimum
876 || ctrl->value > vivi_qctrl[i].maximum) {
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300877 return (-ERANGE);
878 }
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300879 qctl_regs[i] = ctrl->value;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300880 return (0);
881 }
882 return -EINVAL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300883}
884
885/* ------------------------------------------------------------------
886 File operations for the device
887 ------------------------------------------------------------------*/
888
889#define line_buf_size(norm) (norm_maxw(norm)*(format.depth+7)/8)
890
891static int vivi_open(struct inode *inode, struct file *file)
892{
893 int minor = iminor(inode);
Trent Piephoa991f442007-10-10 05:37:43 -0300894 struct vivi_dev *dev;
Mauro Carvalho Chehab63b79cf2008-04-26 08:25:18 -0300895 struct vivi_fh *fh = NULL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300896 int i;
Brandon Philipsaa9dbac2008-04-02 18:10:59 -0300897 int retval = 0;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300898
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300899 printk(KERN_DEBUG "vivi: open called (minor=%d)\n", minor);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300900
Trent Piephoa991f442007-10-10 05:37:43 -0300901 list_for_each_entry(dev, &vivi_devlist, vivi_devlist)
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -0300902 if (dev->vfd->minor == minor)
Trent Piephoa991f442007-10-10 05:37:43 -0300903 goto found;
904 return -ENODEV;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300905
Trent Piephoa991f442007-10-10 05:37:43 -0300906found:
Brandon Philipsaa9dbac2008-04-02 18:10:59 -0300907 mutex_lock(&dev->mutex);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300908 dev->users++;
909
Brandon Philipsaa9dbac2008-04-02 18:10:59 -0300910 if (dev->users > 1) {
911 dev->users--;
912 retval = -EBUSY;
913 goto unlock;
914 }
915
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300916 dprintk(dev, 1, "open minor=%d type=%s users=%d\n", minor,
Trent Piephoa991f442007-10-10 05:37:43 -0300917 v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300918
919 /* allocate + initialize per filehandle data */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300920 fh = kzalloc(sizeof(*fh), GFP_KERNEL);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300921 if (NULL == fh) {
922 dev->users--;
Brandon Philipsaa9dbac2008-04-02 18:10:59 -0300923 retval = -ENOMEM;
924 goto unlock;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300925 }
Brandon Philipsaa9dbac2008-04-02 18:10:59 -0300926unlock:
927 mutex_unlock(&dev->mutex);
928 if (retval)
929 return retval;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300930
931 file->private_data = fh;
932 fh->dev = dev;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300933
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300934 fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
935 fh->fmt = &format;
936 fh->width = 640;
937 fh->height = 480;
938
939 /* Put all controls at a sane state */
940 for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300941 qctl_regs[i] = vivi_qctrl[i].default_value;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300942
943 /* Resets frame counters */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300944 dev->h = 0;
945 dev->m = 0;
946 dev->s = 0;
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -0300947 dev->ms = 0;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300948 dev->mv_count = 0;
949 dev->jiffies = jiffies;
950 sprintf(dev->timestr, "%02d:%02d:%02d:%03d",
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -0300951 dev->h, dev->m, dev->s, dev->ms);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300952
Mauro Carvalho Chehab5a037702007-08-02 23:31:54 -0300953 videobuf_queue_vmalloc_init(&fh->vb_vidq, &vivi_video_qops,
Mauro Carvalho Chehab55862ac2007-12-13 16:13:37 -0300954 NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED,
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300955 sizeof(struct vivi_buffer), fh);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300956
Brandon Philips78718e52008-04-02 18:10:59 -0300957 vivi_start_thread(fh);
958
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300959 return 0;
960}
961
962static ssize_t
963vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
964{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300965 struct vivi_fh *fh = file->private_data;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300966
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300967 if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
Mauro Carvalho Chehabacb09af2007-07-29 22:56:11 -0300968 return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300969 file->f_flags & O_NONBLOCK);
970 }
971 return 0;
972}
973
974static unsigned int
975vivi_poll(struct file *file, struct poll_table_struct *wait)
976{
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300977 struct vivi_fh *fh = file->private_data;
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300978 struct vivi_dev *dev = fh->dev;
Brandon Philips85c7c70bc2007-09-27 20:55:02 -0300979 struct videobuf_queue *q = &fh->vb_vidq;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300980
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300981 dprintk(dev, 1, "%s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300982
983 if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
984 return POLLERR;
985
Brandon Philips85c7c70bc2007-09-27 20:55:02 -0300986 return videobuf_poll_stream(file, q, wait);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300987}
988
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -0300989static int vivi_close(struct inode *inode, struct file *file)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300990{
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300991 struct vivi_fh *fh = file->private_data;
992 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300993 struct vivi_dmaqueue *vidq = &dev->vidq;
994
995 int minor = iminor(inode);
996
997 vivi_stop_thread(vidq);
Brandon Philips053fcb62007-11-13 20:11:26 -0300998 videobuf_stop(&fh->vb_vidq);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300999 videobuf_mmap_free(&fh->vb_vidq);
1000
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001001 kfree(fh);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001002
Brandon Philipsaa9dbac2008-04-02 18:10:59 -03001003 mutex_lock(&dev->mutex);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001004 dev->users--;
Brandon Philipsaa9dbac2008-04-02 18:10:59 -03001005 mutex_unlock(&dev->mutex);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001006
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -03001007 dprintk(dev, 1, "close called (minor=%d, users=%d)\n",
1008 minor, dev->users);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001009
1010 return 0;
1011}
1012
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001013static int vivi_release(void)
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001014{
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001015 struct vivi_dev *dev;
1016 struct list_head *list;
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001017
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001018 while (!list_empty(&vivi_devlist)) {
1019 list = vivi_devlist.next;
1020 list_del(list);
1021 dev = list_entry(list, struct vivi_dev, vivi_devlist);
1022
Carl Karsten745271a2008-06-10 00:02:32 -03001023 if (-1 != dev->vfd->minor) {
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001024 video_unregister_device(dev->vfd);
Carl Karsten745271a2008-06-10 00:02:32 -03001025 printk(KERN_INFO "%s: /dev/video%d unregistered.\n",
Mauro Carvalho Chehab584ce482008-06-10 15:21:49 -03001026 VIVI_MODULE_NAME, dev->vfd->minor);
Carl Karsten745271a2008-06-10 00:02:32 -03001027 } else {
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001028 video_device_release(dev->vfd);
Carl Karsten745271a2008-06-10 00:02:32 -03001029 printk(KERN_INFO "%s: /dev/video%d released.\n",
Mauro Carvalho Chehab584ce482008-06-10 15:21:49 -03001030 VIVI_MODULE_NAME, dev->vfd->minor);
Carl Karsten745271a2008-06-10 00:02:32 -03001031 }
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001032
1033 kfree(dev);
1034 }
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001035
1036 return 0;
1037}
1038
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001039static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001040{
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -03001041 struct vivi_fh *fh = file->private_data;
1042 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001043 int ret;
1044
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -03001045 dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001046
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001047 ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001048
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -03001049 dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n",
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001050 (unsigned long)vma->vm_start,
1051 (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
1052 ret);
1053
1054 return ret;
1055}
1056
Arjan van de Venfa027c22007-02-12 00:55:33 -08001057static const struct file_operations vivi_fops = {
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001058 .owner = THIS_MODULE,
1059 .open = vivi_open,
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001060 .release = vivi_close,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001061 .read = vivi_read,
1062 .poll = vivi_poll,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001063 .ioctl = video_ioctl2, /* V4L2 ioctl handler */
Mauro Carvalho Chehabfbde31d2008-04-13 14:57:44 -03001064 .compat_ioctl = v4l_compat_ioctl32,
Mauro Carvalho Chehab5a037702007-08-02 23:31:54 -03001065 .mmap = vivi_mmap,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001066 .llseek = no_llseek,
1067};
1068
Hans Verkuila3998102008-07-21 02:57:38 -03001069static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001070 .vidioc_querycap = vidioc_querycap,
Hans Verkuil78b526a2008-05-28 12:16:41 -03001071 .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
1072 .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
1073 .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
1074 .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001075 .vidioc_reqbufs = vidioc_reqbufs,
1076 .vidioc_querybuf = vidioc_querybuf,
1077 .vidioc_qbuf = vidioc_qbuf,
1078 .vidioc_dqbuf = vidioc_dqbuf,
1079 .vidioc_s_std = vidioc_s_std,
1080 .vidioc_enum_input = vidioc_enum_input,
1081 .vidioc_g_input = vidioc_g_input,
1082 .vidioc_s_input = vidioc_s_input,
1083 .vidioc_queryctrl = vidioc_queryctrl,
1084 .vidioc_g_ctrl = vidioc_g_ctrl,
1085 .vidioc_s_ctrl = vidioc_s_ctrl,
1086 .vidioc_streamon = vidioc_streamon,
1087 .vidioc_streamoff = vidioc_streamoff,
Mauro Carvalho Chehab0dfa9ab2006-08-08 09:10:10 -03001088#ifdef CONFIG_VIDEO_V4L1_COMPAT
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001089 .vidiocgmbuf = vidiocgmbuf,
1090#endif
Hans Verkuila3998102008-07-21 02:57:38 -03001091};
1092
1093static struct video_device vivi_template = {
1094 .name = "vivi",
Hans Verkuila3998102008-07-21 02:57:38 -03001095 .fops = &vivi_fops,
1096 .ioctl_ops = &vivi_ioctl_ops,
1097 .minor = -1,
1098 .release = video_device_release,
1099
Mauro Carvalho Chehab784c6682007-12-13 06:35:26 -03001100 .tvnorms = V4L2_STD_525_60,
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -03001101 .current_norm = V4L2_STD_NTSC_M,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001102};
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001103/* -----------------------------------------------------------------
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001104 Initialization and module stuff
1105 ------------------------------------------------------------------*/
1106
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001107/* This routine allocates from 1 to n_devs virtual drivers.
1108
1109 The real maximum number of virtual drivers will depend on how many drivers
1110 will succeed. This is limited to the maximum number of devices that
1111 videodev supports. Since there are 64 minors for video grabbers, this is
1112 currently the theoretical maximum limit. However, a further limit does
1113 exist at videodev that forbids any driver to register more than 32 video
1114 grabbers.
1115 */
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001116static int __init vivi_init(void)
1117{
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001118 int ret = -ENOMEM, i;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001119 struct vivi_dev *dev;
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001120 struct video_device *vfd;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001121
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001122 if (n_devs <= 0)
1123 n_devs = 1;
1124
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001125 for (i = 0; i < n_devs; i++) {
1126 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001127 if (!dev)
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001128 break;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001129
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001130 /* init video dma queues */
1131 INIT_LIST_HEAD(&dev->vidq.active);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001132 init_waitqueue_head(&dev->vidq.wq);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001133
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001134 /* initialize locks */
Mauro Carvalho Chehab55862ac2007-12-13 16:13:37 -03001135 spin_lock_init(&dev->slock);
Brandon Philipsaa9dbac2008-04-02 18:10:59 -03001136 mutex_init(&dev->mutex);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001137
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001138 vfd = video_device_alloc();
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001139 if (!vfd) {
1140 kfree(dev);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001141 break;
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001142 }
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001143
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001144 *vfd = vivi_template;
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001145
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001146 ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001147 if (ret < 0) {
1148 video_device_release(vfd);
1149 kfree(dev);
1150
1151 /* If some registers succeeded, keep driver */
1152 if (i)
1153 ret = 0;
1154
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001155 break;
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001156 }
1157
1158 /* Now that everything is fine, let's add it to device list */
1159 list_add_tail(&dev->vivi_devlist, &vivi_devlist);
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001160
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001161 snprintf(vfd->name, sizeof(vfd->name), "%s (%i)",
1162 vivi_template.name, vfd->minor);
1163
1164 if (video_nr >= 0)
1165 video_nr++;
1166
1167 dev->vfd = vfd;
Carl Karsten745271a2008-06-10 00:02:32 -03001168 printk(KERN_INFO "%s: V4L2 device registered as /dev/video%d\n",
Mauro Carvalho Chehab584ce482008-06-10 15:21:49 -03001169 VIVI_MODULE_NAME, vfd->minor);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001170 }
1171
1172 if (ret < 0) {
1173 vivi_release();
1174 printk(KERN_INFO "Error %d while loading vivi driver\n", ret);
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001175 } else {
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001176 printk(KERN_INFO "Video Technology Magazine Virtual Video "
Carl Karsten745271a2008-06-10 00:02:32 -03001177 "Capture Board ver %u.%u.%u successfully loaded.\n",
1178 (VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF,
1179 VIVI_VERSION & 0xFF);
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001180
1181 /* n_devs will reflect the actual number of allocated devices */
1182 n_devs = i;
1183 }
1184
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001185 return ret;
1186}
1187
1188static void __exit vivi_exit(void)
1189{
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001190 vivi_release();
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001191}
1192
1193module_init(vivi_init);
1194module_exit(vivi_exit);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001195
1196MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
1197MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
1198MODULE_LICENSE("Dual BSD/GPL");
1199
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001200module_param(video_nr, uint, 0444);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001201MODULE_PARM_DESC(video_nr, "video iminor start number");
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001202
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001203module_param(n_devs, uint, 0444);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001204MODULE_PARM_DESC(n_devs, "number of video devices to create");
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001205
Mauro Carvalho Chehab8996b3f2007-12-13 06:36:22 -03001206module_param_named(debug, vivi_template.debug, int, 0444);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001207MODULE_PARM_DESC(debug, "activates debug info");
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001208
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001209module_param(vid_limit, int, 0644);
1210MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");