blob: 0d1ad7f63d09480c4f359cb8cb317f908337116c [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;
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300193 unsigned char bars[8][3];
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300194};
195
196/* ------------------------------------------------------------------
197 DMA and thread functions
198 ------------------------------------------------------------------*/
199
200/* Bars and Colors should match positions */
201
202enum colors {
203 WHITE,
204 AMBAR,
205 CYAN,
206 GREEN,
207 MAGENTA,
208 RED,
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300209 BLUE,
210 BLACK,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300211};
212
213static u8 bars[8][3] = {
214 /* R G B */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300215 {204, 204, 204}, /* white */
216 {208, 208, 0}, /* ambar */
217 { 0, 206, 206}, /* cyan */
218 { 0, 239, 0}, /* green */
219 {239, 0, 239}, /* magenta */
220 {205, 0, 0}, /* red */
221 { 0, 0, 255}, /* blue */
222 { 0, 0, 0}, /* black */
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300223};
224
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300225#define TO_Y(r, g, b) \
226 (((16829 * r + 33039 * g + 6416 * b + 32768) >> 16) + 16)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300227/* RGB to V(Cr) Color transform */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300228#define TO_V(r, g, b) \
229 (((28784 * r - 24103 * g - 4681 * b + 32768) >> 16) + 128)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300230/* RGB to U(Cb) Color transform */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300231#define TO_U(r, g, b) \
232 (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300233
234#define TSTAMP_MIN_Y 24
235#define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
236#define TSTAMP_MIN_X 64
237
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300238static void gen_twopix(struct vivi_fh *fh, unsigned char *buf, int colorpos)
239{
240 unsigned char r_y, g_u, b_v;
241 unsigned char *p;
242 int color;
243
244 r_y = fh->bars[colorpos][0]; /* R or precalculated Y */
245 g_u = fh->bars[colorpos][1]; /* G or precalculated U */
246 b_v = fh->bars[colorpos][2]; /* B or precalculated V */
247
248 for (color = 0; color < 4; color++) {
249 p = buf + color;
250
251 switch (color) {
252 case 0:
253 case 2:
254 *p = r_y;
255 break;
256 case 1:
257 *p = g_u;
258 break;
259 case 3:
260 *p = b_v;
261 break;
262 }
263 }
264}
265
266static void gen_line(struct vivi_fh *fh, char *basep, int inipos, int wmax,
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300267 int hmax, int line, int count, char *timestr)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300268{
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300269 int w, i, j;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300270 int pos = inipos;
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300271 char *s;
272 u8 chr;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300273
274 /* We will just duplicate the second pixel at the packet */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300275 wmax /= 2;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300276
277 /* Generate a standard color bar pattern */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300278 for (w = 0; w < wmax; w++) {
279 int colorpos = ((w + count) * 8/(wmax + 1)) % 8;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300280
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300281 gen_twopix(fh, basep + pos, colorpos);
282 pos += 4; /* only 16 bpp supported for now */
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300283 }
284
285 /* Checks if it is possible to show timestamp */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300286 if (TSTAMP_MAX_Y >= hmax)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300287 goto end;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300288 if (TSTAMP_MIN_X + strlen(timestr) >= wmax)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300289 goto end;
290
291 /* Print stream time */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300292 if (line >= TSTAMP_MIN_Y && line <= TSTAMP_MAX_Y) {
293 j = TSTAMP_MIN_X;
294 for (s = timestr; *s; s++) {
295 chr = rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y];
296 for (i = 0; i < 7; i++) {
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300297 pos = inipos + j * 2;
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300298 /* Draw white font on black background */
299 if (chr & 1 << (7 - i))
300 gen_twopix(fh, basep + pos, WHITE);
301 else
302 gen_twopix(fh, basep + pos, BLACK);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300303 j++;
304 }
305 }
306 }
307
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300308end:
Mauro Carvalho Chehabb50e7fe2007-01-25 05:00:01 -0300309 return;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300310}
Brandon Philips78718e52008-04-02 18:10:59 -0300311
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300312static void vivi_fillbuff(struct vivi_fh *fh, struct vivi_buffer *buf)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300313{
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300314 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300315 int h , pos = 0;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300316 int hmax = buf->vb.height;
317 int wmax = buf->vb.width;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300318 struct timeval ts;
Marcin Slusarz5c554e62008-06-22 09:11:40 -0300319 char *tmpbuf;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300320 void *vbuf = videobuf_to_vmalloc(&buf->vb);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300321
Marcin Slusarz5c554e62008-06-22 09:11:40 -0300322 if (!vbuf)
Mauro Carvalho Chehab5a037702007-08-02 23:31:54 -0300323 return;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300324
Marcin Slusarz5c554e62008-06-22 09:11:40 -0300325 tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC);
326 if (!tmpbuf)
Brandon Philips78718e52008-04-02 18:10:59 -0300327 return;
328
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300329 for (h = 0; h < hmax; h++) {
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300330 gen_line(fh, tmpbuf, 0, wmax, hmax, h, dev->mv_count,
Mauro Carvalho Chehab3bef5e42007-09-22 02:01:33 -0300331 dev->timestr);
Brandon Philips78718e52008-04-02 18:10:59 -0300332 memcpy(vbuf + pos, tmpbuf, wmax * 2);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300333 pos += wmax*2;
334 }
335
Mauro Carvalho Chehab025341d2007-12-10 04:43:38 -0300336 dev->mv_count++;
Mauro Carvalho Chehab3bef5e42007-09-22 02:01:33 -0300337
Mauro Carvalho Chehab5a037702007-08-02 23:31:54 -0300338 kfree(tmpbuf);
339
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300340 /* Updates stream time */
341
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -0300342 dev->ms += jiffies_to_msecs(jiffies-dev->jiffies);
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300343 dev->jiffies = jiffies;
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -0300344 if (dev->ms >= 1000) {
345 dev->ms -= 1000;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300346 dev->s++;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300347 if (dev->s >= 60) {
348 dev->s -= 60;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300349 dev->m++;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300350 if (dev->m > 60) {
351 dev->m -= 60;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300352 dev->h++;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300353 if (dev->h > 24)
354 dev->h -= 24;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300355 }
356 }
357 }
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300358 sprintf(dev->timestr, "%02d:%02d:%02d:%03d",
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -0300359 dev->h, dev->m, dev->s, dev->ms);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300360
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300361 dprintk(dev, 2, "vivifill at %s: Buffer 0x%08lx size= %d\n",
362 dev->timestr, (unsigned long)tmpbuf, pos);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300363
364 /* Advice that buffer was filled */
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300365 buf->vb.field_count++;
366 do_gettimeofday(&ts);
367 buf->vb.ts = ts;
Brandon Philips78718e52008-04-02 18:10:59 -0300368 buf->vb.state = VIDEOBUF_DONE;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300369}
370
Brandon Philips78718e52008-04-02 18:10:59 -0300371static void vivi_thread_tick(struct vivi_fh *fh)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300372{
Brandon Philips78718e52008-04-02 18:10:59 -0300373 struct vivi_buffer *buf;
374 struct vivi_dev *dev = fh->dev;
375 struct vivi_dmaqueue *dma_q = &dev->vidq;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300376
Brandon Philips78718e52008-04-02 18:10:59 -0300377 unsigned long flags = 0;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300378
Brandon Philips78718e52008-04-02 18:10:59 -0300379 dprintk(dev, 1, "Thread tick\n");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300380
Brandon Philips78718e52008-04-02 18:10:59 -0300381 spin_lock_irqsave(&dev->slock, flags);
382 if (list_empty(&dma_q->active)) {
383 dprintk(dev, 1, "No active queue to serve\n");
384 goto unlock;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300385 }
Brandon Philips78718e52008-04-02 18:10:59 -0300386
387 buf = list_entry(dma_q->active.next,
388 struct vivi_buffer, vb.queue);
389
390 /* Nobody is waiting on this buffer, return */
391 if (!waitqueue_active(&buf->vb.done))
392 goto unlock;
393
394 list_del(&buf->vb.queue);
395
396 do_gettimeofday(&buf->vb.ts);
397
398 /* Fill buffer */
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300399 vivi_fillbuff(fh, buf);
Brandon Philips78718e52008-04-02 18:10:59 -0300400 dprintk(dev, 1, "filled buffer %p\n", buf);
401
402 wake_up(&buf->vb.done);
403 dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i);
404unlock:
405 spin_unlock_irqrestore(&dev->slock, flags);
406 return;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300407}
408
Mauro Carvalho Chehab6594ad82007-12-13 16:15:41 -0300409#define frames_to_ms(frames) \
410 ((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR)
411
Brandon Philips78718e52008-04-02 18:10:59 -0300412static void vivi_sleep(struct vivi_fh *fh)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300413{
Brandon Philips78718e52008-04-02 18:10:59 -0300414 struct vivi_dev *dev = fh->dev;
415 struct vivi_dmaqueue *dma_q = &dev->vidq;
416 int timeout;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300417 DECLARE_WAITQUEUE(wait, current);
418
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300419 dprintk(dev, 1, "%s dma_q=0x%08lx\n", __func__,
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300420 (unsigned long)dma_q);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300421
422 add_wait_queue(&dma_q->wq, &wait);
Mauro Carvalho Chehab6594ad82007-12-13 16:15:41 -0300423 if (kthread_should_stop())
424 goto stop_task;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300425
Mauro Carvalho Chehab6594ad82007-12-13 16:15:41 -0300426 /* Calculate time to wake up */
Brandon Philips78718e52008-04-02 18:10:59 -0300427 timeout = msecs_to_jiffies(frames_to_ms(1));
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300428
Brandon Philips78718e52008-04-02 18:10:59 -0300429 vivi_thread_tick(fh);
Mauro Carvalho Chehab6594ad82007-12-13 16:15:41 -0300430
431 schedule_timeout_interruptible(timeout);
432
433stop_task:
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300434 remove_wait_queue(&dma_q->wq, &wait);
435 try_to_freeze();
436}
437
Adrian Bunk972c3512006-04-27 21:06:50 -0300438static int vivi_thread(void *data)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300439{
Brandon Philips78718e52008-04-02 18:10:59 -0300440 struct vivi_fh *fh = data;
441 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300442
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300443 dprintk(dev, 1, "thread started\n");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300444
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700445 set_freezable();
Mauro Carvalho Chehab0b600512007-01-14 08:33:24 -0300446
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300447 for (;;) {
Brandon Philips78718e52008-04-02 18:10:59 -0300448 vivi_sleep(fh);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300449
450 if (kthread_should_stop())
451 break;
452 }
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300453 dprintk(dev, 1, "thread: exit\n");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300454 return 0;
455}
456
Brandon Philips78718e52008-04-02 18:10:59 -0300457static int vivi_start_thread(struct vivi_fh *fh)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300458{
Brandon Philips78718e52008-04-02 18:10:59 -0300459 struct vivi_dev *dev = fh->dev;
460 struct vivi_dmaqueue *dma_q = &dev->vidq;
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300461
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300462 dma_q->frame = 0;
463 dma_q->ini_jiffies = jiffies;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300464
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300465 dprintk(dev, 1, "%s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300466
Brandon Philips78718e52008-04-02 18:10:59 -0300467 dma_q->kthread = kthread_run(vivi_thread, fh, "vivi");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300468
Akinobu Mita054afee2006-12-20 10:04:00 -0300469 if (IS_ERR(dma_q->kthread)) {
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300470 printk(KERN_ERR "vivi: kernel_thread() failed\n");
Akinobu Mita054afee2006-12-20 10:04:00 -0300471 return PTR_ERR(dma_q->kthread);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300472 }
Mauro Carvalho Chehab0b600512007-01-14 08:33:24 -0300473 /* Wakes thread */
474 wake_up_interruptible(&dma_q->wq);
475
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300476 dprintk(dev, 1, "returning from %s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300477 return 0;
478}
479
Adrian Bunk972c3512006-04-27 21:06:50 -0300480static void vivi_stop_thread(struct vivi_dmaqueue *dma_q)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300481{
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300482 struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
483
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300484 dprintk(dev, 1, "%s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300485 /* shutdown control thread */
486 if (dma_q->kthread) {
487 kthread_stop(dma_q->kthread);
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300488 dma_q->kthread = NULL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300489 }
490}
491
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300492/* ------------------------------------------------------------------
493 Videobuf operations
494 ------------------------------------------------------------------*/
495static int
496buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
497{
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300498 struct vivi_fh *fh = vq->priv_data;
499 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300500
501 *size = fh->width*fh->height*2;
502
503 if (0 == *count)
504 *count = 32;
Mauro Carvalho Chehab6bb27902007-08-23 16:41:14 -0300505
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300506 while (*size * *count > vid_limit * 1024 * 1024)
507 (*count)--;
Mauro Carvalho Chehab6bb27902007-08-23 16:41:14 -0300508
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300509 dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__,
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300510 *count, *size);
Mauro Carvalho Chehab6bb27902007-08-23 16:41:14 -0300511
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300512 return 0;
513}
514
Adrian Bunk972c3512006-04-27 21:06:50 -0300515static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300516{
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300517 struct vivi_fh *fh = vq->priv_data;
518 struct vivi_dev *dev = fh->dev;
519
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300520 dprintk(dev, 1, "%s, state: %i\n", __func__, buf->vb.state);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300521
522 if (in_interrupt())
523 BUG();
524
Mauro Carvalho Chehab5a037702007-08-02 23:31:54 -0300525 videobuf_vmalloc_free(&buf->vb);
Mauro Carvalho Chehabfbde31d2008-04-13 14:57:44 -0300526 dprintk(dev, 1, "free_buffer: freed\n");
Brandon Philips0fc06862007-11-06 20:02:36 -0300527 buf->vb.state = VIDEOBUF_NEEDS_INIT;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300528}
529
530#define norm_maxw() 1024
531#define norm_maxh() 768
532static int
533buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
534 enum v4l2_field field)
535{
536 struct vivi_fh *fh = vq->priv_data;
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300537 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300538 struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
Brandon Philips78718e52008-04-02 18:10:59 -0300539 int rc;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300540
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300541 dprintk(dev, 1, "%s, field=%d\n", __func__, field);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300542
543 BUG_ON(NULL == fh->fmt);
Brandon Philips78718e52008-04-02 18:10:59 -0300544
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300545 if (fh->width < 48 || fh->width > norm_maxw() ||
546 fh->height < 32 || fh->height > norm_maxh())
547 return -EINVAL;
Brandon Philips78718e52008-04-02 18:10:59 -0300548
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300549 buf->vb.size = fh->width*fh->height*2;
550 if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
551 return -EINVAL;
552
Brandon Philips78718e52008-04-02 18:10:59 -0300553 /* These properties only change when queue is idle, see s_fmt */
554 buf->fmt = fh->fmt;
555 buf->vb.width = fh->width;
556 buf->vb.height = fh->height;
557 buf->vb.field = field;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300558
Brandon Philips0fc06862007-11-06 20:02:36 -0300559 if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300560 rc = videobuf_iolock(vq, &buf->vb, NULL);
561 if (rc < 0)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300562 goto fail;
563 }
564
Brandon Philips0fc06862007-11-06 20:02:36 -0300565 buf->vb.state = VIDEOBUF_PREPARED;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300566
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300567 return 0;
568
569fail:
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300570 free_buffer(vq, buf);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300571 return rc;
572}
573
574static void
575buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
576{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300577 struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
578 struct vivi_fh *fh = vq->priv_data;
579 struct vivi_dev *dev = fh->dev;
Brandon Philips78718e52008-04-02 18:10:59 -0300580 struct vivi_dmaqueue *vidq = &dev->vidq;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300581
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300582 dprintk(dev, 1, "%s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300583
Brandon Philips78718e52008-04-02 18:10:59 -0300584 buf->vb.state = VIDEOBUF_QUEUED;
585 list_add_tail(&buf->vb.queue, &vidq->active);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300586}
587
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300588static void buffer_release(struct videobuf_queue *vq,
589 struct videobuf_buffer *vb)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300590{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300591 struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300592 struct vivi_fh *fh = vq->priv_data;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300593 struct vivi_dev *dev = (struct vivi_dev *)fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300594
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300595 dprintk(dev, 1, "%s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300596
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300597 free_buffer(vq, buf);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300598}
599
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300600static struct videobuf_queue_ops vivi_video_qops = {
601 .buf_setup = buffer_setup,
602 .buf_prepare = buffer_prepare,
603 .buf_queue = buffer_queue,
604 .buf_release = buffer_release,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300605};
606
607/* ------------------------------------------------------------------
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300608 IOCTL vidioc handling
609 ------------------------------------------------------------------*/
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300610static int vidioc_querycap(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300611 struct v4l2_capability *cap)
612{
613 strcpy(cap->driver, "vivi");
614 strcpy(cap->card, "vivi");
615 cap->version = VIVI_VERSION;
616 cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
617 V4L2_CAP_STREAMING |
618 V4L2_CAP_READWRITE;
619 return 0;
620}
621
Hans Verkuil78b526a2008-05-28 12:16:41 -0300622static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300623 struct v4l2_fmtdesc *f)
624{
625 if (f->index > 0)
626 return -EINVAL;
627
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300628 strlcpy(f->description, format.name, sizeof(f->description));
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300629 f->pixelformat = format.fourcc;
630 return 0;
631}
632
Hans Verkuil78b526a2008-05-28 12:16:41 -0300633static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300634 struct v4l2_format *f)
635{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300636 struct vivi_fh *fh = priv;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300637
638 f->fmt.pix.width = fh->width;
639 f->fmt.pix.height = fh->height;
640 f->fmt.pix.field = fh->vb_vidq.field;
641 f->fmt.pix.pixelformat = fh->fmt->fourcc;
642 f->fmt.pix.bytesperline =
643 (f->fmt.pix.width * fh->fmt->depth) >> 3;
644 f->fmt.pix.sizeimage =
645 f->fmt.pix.height * f->fmt.pix.bytesperline;
646
647 return (0);
648}
649
Hans Verkuil78b526a2008-05-28 12:16:41 -0300650static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300651 struct v4l2_format *f)
652{
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300653 struct vivi_fh *fh = priv;
654 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300655 struct vivi_fmt *fmt;
656 enum v4l2_field field;
657 unsigned int maxw, maxh;
658
659 if (format.fourcc != f->fmt.pix.pixelformat) {
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300660 dprintk(dev, 1, "Fourcc format (0x%08x) invalid. "
661 "Driver accepts only 0x%08x\n",
662 f->fmt.pix.pixelformat, format.fourcc);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300663 return -EINVAL;
664 }
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300665 fmt = &format;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300666
667 field = f->fmt.pix.field;
668
669 if (field == V4L2_FIELD_ANY) {
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300670 field = V4L2_FIELD_INTERLACED;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300671 } else if (V4L2_FIELD_INTERLACED != field) {
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300672 dprintk(dev, 1, "Field type invalid.\n");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300673 return -EINVAL;
674 }
675
676 maxw = norm_maxw();
677 maxh = norm_maxh();
678
679 f->fmt.pix.field = field;
680 if (f->fmt.pix.height < 32)
681 f->fmt.pix.height = 32;
682 if (f->fmt.pix.height > maxh)
683 f->fmt.pix.height = maxh;
684 if (f->fmt.pix.width < 48)
685 f->fmt.pix.width = 48;
686 if (f->fmt.pix.width > maxw)
687 f->fmt.pix.width = maxw;
688 f->fmt.pix.width &= ~0x03;
689 f->fmt.pix.bytesperline =
690 (f->fmt.pix.width * fmt->depth) >> 3;
691 f->fmt.pix.sizeimage =
692 f->fmt.pix.height * f->fmt.pix.bytesperline;
693
694 return 0;
695}
696
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300697/*FIXME: This seems to be generic enough to be at videodev2 */
Hans Verkuil78b526a2008-05-28 12:16:41 -0300698static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300699 struct v4l2_format *f)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300700{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300701 struct vivi_fh *fh = priv;
Brandon Philips78718e52008-04-02 18:10:59 -0300702 struct videobuf_queue *q = &fh->vb_vidq;
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300703 unsigned char r, g, b;
704 int k;
Brandon Philips78718e52008-04-02 18:10:59 -0300705
Hans Verkuil78b526a2008-05-28 12:16:41 -0300706 int ret = vidioc_try_fmt_vid_cap(file, fh, f);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300707 if (ret < 0)
708 return (ret);
709
Brandon Philips78718e52008-04-02 18:10:59 -0300710 mutex_lock(&q->vb_lock);
711
712 if (videobuf_queue_is_busy(&fh->vb_vidq)) {
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300713 dprintk(fh->dev, 1, "%s queue busy\n", __func__);
Brandon Philips78718e52008-04-02 18:10:59 -0300714 ret = -EBUSY;
715 goto out;
716 }
717
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300718 fh->fmt = &format;
719 fh->width = f->fmt.pix.width;
720 fh->height = f->fmt.pix.height;
721 fh->vb_vidq.field = f->fmt.pix.field;
722 fh->type = f->type;
723
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300724 /* precalculate color bar values to speed up rendering */
725 for (k = 0; k < 8; k++) {
726 r = bars[k][0];
727 g = bars[k][1];
728 b = bars[k][2];
729
730 fh->bars[k][0] = TO_Y(r, g, b); /* Luma */
731 fh->bars[k][1] = TO_U(r, g, b); /* Cb */
732 fh->bars[k][2] = TO_V(r, g, b); /* Cr */
733 }
734
Brandon Philips78718e52008-04-02 18:10:59 -0300735 ret = 0;
736out:
737 mutex_unlock(&q->vb_lock);
738
739 return (ret);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300740}
741
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300742static int vidioc_reqbufs(struct file *file, void *priv,
743 struct v4l2_requestbuffers *p)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300744{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300745 struct vivi_fh *fh = priv;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300746
747 return (videobuf_reqbufs(&fh->vb_vidq, p));
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300748}
749
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300750static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300751{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300752 struct vivi_fh *fh = priv;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300753
754 return (videobuf_querybuf(&fh->vb_vidq, p));
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300755}
756
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300757static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300758{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300759 struct vivi_fh *fh = priv;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300760
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300761 return (videobuf_qbuf(&fh->vb_vidq, p));
762}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300763
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300764static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300765{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300766 struct vivi_fh *fh = priv;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300767
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300768 return (videobuf_dqbuf(&fh->vb_vidq, p,
769 file->f_flags & O_NONBLOCK));
770}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300771
Mauro Carvalho Chehab0dfa9ab2006-08-08 09:10:10 -0300772#ifdef CONFIG_VIDEO_V4L1_COMPAT
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300773static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300774{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300775 struct vivi_fh *fh = priv;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300776
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300777 return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300778}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300779#endif
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300780
Adrian Bunkdc46ace2006-06-23 06:42:44 -0300781static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300782{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300783 struct vivi_fh *fh = priv;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300784
785 if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
786 return -EINVAL;
787 if (i != fh->type)
788 return -EINVAL;
789
Brandon Philipsba32bd92007-09-27 20:55:17 -0300790 return videobuf_streamon(&fh->vb_vidq);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300791}
792
Adrian Bunkdc46ace2006-06-23 06:42:44 -0300793static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300794{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300795 struct vivi_fh *fh = priv;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300796
797 if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
798 return -EINVAL;
799 if (i != fh->type)
800 return -EINVAL;
801
Brandon Philipsba32bd92007-09-27 20:55:17 -0300802 return videobuf_streamoff(&fh->vb_vidq);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300803}
804
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300805static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300806{
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300807 return 0;
808}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300809
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300810/* only one input in this sample driver */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300811static int vidioc_enum_input(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300812 struct v4l2_input *inp)
813{
814 if (inp->index != 0)
815 return -EINVAL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300816
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300817 inp->type = V4L2_INPUT_TYPE_CAMERA;
Mauro Carvalho Chehab784c6682007-12-13 06:35:26 -0300818 inp->std = V4L2_STD_525_60;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300819 strcpy(inp->name, "Camera");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300820
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300821 return (0);
822}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300823
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300824static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300825{
826 *i = 0;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300827
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300828 return (0);
829}
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300830static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300831{
832 if (i > 0)
833 return -EINVAL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300834
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300835 return (0);
836}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300837
838 /* --- controls ---------------------------------------------- */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300839static int vidioc_queryctrl(struct file *file, void *priv,
840 struct v4l2_queryctrl *qc)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300841{
842 int i;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300843
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300844 for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
845 if (qc->id && qc->id == vivi_qctrl[i].id) {
846 memcpy(qc, &(vivi_qctrl[i]),
847 sizeof(*qc));
848 return (0);
849 }
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300850
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300851 return -EINVAL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300852}
853
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300854static int vidioc_g_ctrl(struct file *file, void *priv,
855 struct v4l2_control *ctrl)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300856{
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300857 int i;
858
859 for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
860 if (ctrl->id == vivi_qctrl[i].id) {
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300861 ctrl->value = qctl_regs[i];
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300862 return (0);
863 }
864
865 return -EINVAL;
866}
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300867static int vidioc_s_ctrl(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300868 struct v4l2_control *ctrl)
869{
870 int i;
871
872 for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
873 if (ctrl->id == vivi_qctrl[i].id) {
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300874 if (ctrl->value < vivi_qctrl[i].minimum
875 || ctrl->value > vivi_qctrl[i].maximum) {
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300876 return (-ERANGE);
877 }
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300878 qctl_regs[i] = ctrl->value;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300879 return (0);
880 }
881 return -EINVAL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300882}
883
884/* ------------------------------------------------------------------
885 File operations for the device
886 ------------------------------------------------------------------*/
887
888#define line_buf_size(norm) (norm_maxw(norm)*(format.depth+7)/8)
889
890static int vivi_open(struct inode *inode, struct file *file)
891{
892 int minor = iminor(inode);
Trent Piephoa991f442007-10-10 05:37:43 -0300893 struct vivi_dev *dev;
Mauro Carvalho Chehab63b79cf2008-04-26 08:25:18 -0300894 struct vivi_fh *fh = NULL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300895 int i;
Brandon Philipsaa9dbac2008-04-02 18:10:59 -0300896 int retval = 0;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300897
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300898 printk(KERN_DEBUG "vivi: open called (minor=%d)\n", minor);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300899
Hans Verkuild56dc612008-07-30 08:43:36 -0300900 lock_kernel();
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;
Hans Verkuild56dc612008-07-30 08:43:36 -0300904 unlock_kernel();
Trent Piephoa991f442007-10-10 05:37:43 -0300905 return -ENODEV;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300906
Trent Piephoa991f442007-10-10 05:37:43 -0300907found:
Brandon Philipsaa9dbac2008-04-02 18:10:59 -0300908 mutex_lock(&dev->mutex);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300909 dev->users++;
910
Brandon Philipsaa9dbac2008-04-02 18:10:59 -0300911 if (dev->users > 1) {
912 dev->users--;
913 retval = -EBUSY;
914 goto unlock;
915 }
916
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300917 dprintk(dev, 1, "open minor=%d type=%s users=%d\n", minor,
Trent Piephoa991f442007-10-10 05:37:43 -0300918 v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300919
920 /* allocate + initialize per filehandle data */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300921 fh = kzalloc(sizeof(*fh), GFP_KERNEL);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300922 if (NULL == fh) {
923 dev->users--;
Brandon Philipsaa9dbac2008-04-02 18:10:59 -0300924 retval = -ENOMEM;
925 goto unlock;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300926 }
Brandon Philipsaa9dbac2008-04-02 18:10:59 -0300927unlock:
928 mutex_unlock(&dev->mutex);
Hans Verkuild56dc612008-07-30 08:43:36 -0300929 if (retval) {
930 unlock_kernel();
Brandon Philipsaa9dbac2008-04-02 18:10:59 -0300931 return retval;
Hans Verkuild56dc612008-07-30 08:43:36 -0300932 }
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300933
934 file->private_data = fh;
935 fh->dev = dev;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300936
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300937 fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
938 fh->fmt = &format;
939 fh->width = 640;
940 fh->height = 480;
941
942 /* Put all controls at a sane state */
943 for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300944 qctl_regs[i] = vivi_qctrl[i].default_value;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300945
946 /* Resets frame counters */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300947 dev->h = 0;
948 dev->m = 0;
949 dev->s = 0;
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -0300950 dev->ms = 0;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300951 dev->mv_count = 0;
952 dev->jiffies = jiffies;
953 sprintf(dev->timestr, "%02d:%02d:%02d:%03d",
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -0300954 dev->h, dev->m, dev->s, dev->ms);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300955
Mauro Carvalho Chehab5a037702007-08-02 23:31:54 -0300956 videobuf_queue_vmalloc_init(&fh->vb_vidq, &vivi_video_qops,
Mauro Carvalho Chehab55862ac2007-12-13 16:13:37 -0300957 NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED,
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300958 sizeof(struct vivi_buffer), fh);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300959
Brandon Philips78718e52008-04-02 18:10:59 -0300960 vivi_start_thread(fh);
Hans Verkuild56dc612008-07-30 08:43:36 -0300961 unlock_kernel();
Brandon Philips78718e52008-04-02 18:10:59 -0300962
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300963 return 0;
964}
965
966static ssize_t
967vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
968{
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300969 struct vivi_fh *fh = file->private_data;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300970
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300971 if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
Mauro Carvalho Chehabacb09af2007-07-29 22:56:11 -0300972 return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300973 file->f_flags & O_NONBLOCK);
974 }
975 return 0;
976}
977
978static unsigned int
979vivi_poll(struct file *file, struct poll_table_struct *wait)
980{
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300981 struct vivi_fh *fh = file->private_data;
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300982 struct vivi_dev *dev = fh->dev;
Brandon Philips85c7c70bc2007-09-27 20:55:02 -0300983 struct videobuf_queue *q = &fh->vb_vidq;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300984
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300985 dprintk(dev, 1, "%s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300986
987 if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
988 return POLLERR;
989
Brandon Philips85c7c70bc2007-09-27 20:55:02 -0300990 return videobuf_poll_stream(file, q, wait);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300991}
992
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -0300993static int vivi_close(struct inode *inode, struct file *file)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300994{
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300995 struct vivi_fh *fh = file->private_data;
996 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300997 struct vivi_dmaqueue *vidq = &dev->vidq;
998
999 int minor = iminor(inode);
1000
1001 vivi_stop_thread(vidq);
Brandon Philips053fcb62007-11-13 20:11:26 -03001002 videobuf_stop(&fh->vb_vidq);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001003 videobuf_mmap_free(&fh->vb_vidq);
1004
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001005 kfree(fh);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001006
Brandon Philipsaa9dbac2008-04-02 18:10:59 -03001007 mutex_lock(&dev->mutex);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001008 dev->users--;
Brandon Philipsaa9dbac2008-04-02 18:10:59 -03001009 mutex_unlock(&dev->mutex);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001010
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -03001011 dprintk(dev, 1, "close called (minor=%d, users=%d)\n",
1012 minor, dev->users);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001013
1014 return 0;
1015}
1016
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001017static int vivi_release(void)
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001018{
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001019 struct vivi_dev *dev;
1020 struct list_head *list;
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001021
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001022 while (!list_empty(&vivi_devlist)) {
1023 list = vivi_devlist.next;
1024 list_del(list);
1025 dev = list_entry(list, struct vivi_dev, vivi_devlist);
1026
Carl Karsten745271a2008-06-10 00:02:32 -03001027 if (-1 != dev->vfd->minor) {
Adrian Bunk8da9bae2008-09-03 17:12:25 -03001028 printk(KERN_INFO "%s: unregistering /dev/video%d\n",
1029 VIVI_MODULE_NAME, dev->vfd->minor);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001030 video_unregister_device(dev->vfd);
Carl Karsten745271a2008-06-10 00:02:32 -03001031 } else {
Adrian Bunk8da9bae2008-09-03 17:12:25 -03001032 printk(KERN_INFO "%s: releasing /dev/video%d\n",
Mauro Carvalho Chehab584ce482008-06-10 15:21:49 -03001033 VIVI_MODULE_NAME, dev->vfd->minor);
Adrian Bunk8da9bae2008-09-03 17:12:25 -03001034 video_device_release(dev->vfd);
Carl Karsten745271a2008-06-10 00:02:32 -03001035 }
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001036
1037 kfree(dev);
1038 }
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001039
1040 return 0;
1041}
1042
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001043static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001044{
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -03001045 struct vivi_fh *fh = file->private_data;
1046 struct vivi_dev *dev = fh->dev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001047 int ret;
1048
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -03001049 dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001050
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001051 ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001052
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -03001053 dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n",
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001054 (unsigned long)vma->vm_start,
1055 (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
1056 ret);
1057
1058 return ret;
1059}
1060
Arjan van de Venfa027c22007-02-12 00:55:33 -08001061static const struct file_operations vivi_fops = {
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001062 .owner = THIS_MODULE,
1063 .open = vivi_open,
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001064 .release = vivi_close,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001065 .read = vivi_read,
1066 .poll = vivi_poll,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001067 .ioctl = video_ioctl2, /* V4L2 ioctl handler */
Mauro Carvalho Chehabfbde31d2008-04-13 14:57:44 -03001068 .compat_ioctl = v4l_compat_ioctl32,
Mauro Carvalho Chehab5a037702007-08-02 23:31:54 -03001069 .mmap = vivi_mmap,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001070 .llseek = no_llseek,
1071};
1072
Hans Verkuila3998102008-07-21 02:57:38 -03001073static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001074 .vidioc_querycap = vidioc_querycap,
Hans Verkuil78b526a2008-05-28 12:16:41 -03001075 .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
1076 .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
1077 .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
1078 .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001079 .vidioc_reqbufs = vidioc_reqbufs,
1080 .vidioc_querybuf = vidioc_querybuf,
1081 .vidioc_qbuf = vidioc_qbuf,
1082 .vidioc_dqbuf = vidioc_dqbuf,
1083 .vidioc_s_std = vidioc_s_std,
1084 .vidioc_enum_input = vidioc_enum_input,
1085 .vidioc_g_input = vidioc_g_input,
1086 .vidioc_s_input = vidioc_s_input,
1087 .vidioc_queryctrl = vidioc_queryctrl,
1088 .vidioc_g_ctrl = vidioc_g_ctrl,
1089 .vidioc_s_ctrl = vidioc_s_ctrl,
1090 .vidioc_streamon = vidioc_streamon,
1091 .vidioc_streamoff = vidioc_streamoff,
Mauro Carvalho Chehab0dfa9ab2006-08-08 09:10:10 -03001092#ifdef CONFIG_VIDEO_V4L1_COMPAT
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001093 .vidiocgmbuf = vidiocgmbuf,
1094#endif
Hans Verkuila3998102008-07-21 02:57:38 -03001095};
1096
1097static struct video_device vivi_template = {
1098 .name = "vivi",
Hans Verkuila3998102008-07-21 02:57:38 -03001099 .fops = &vivi_fops,
1100 .ioctl_ops = &vivi_ioctl_ops,
1101 .minor = -1,
1102 .release = video_device_release,
1103
Mauro Carvalho Chehab784c6682007-12-13 06:35:26 -03001104 .tvnorms = V4L2_STD_525_60,
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -03001105 .current_norm = V4L2_STD_NTSC_M,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001106};
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001107/* -----------------------------------------------------------------
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001108 Initialization and module stuff
1109 ------------------------------------------------------------------*/
1110
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001111/* This routine allocates from 1 to n_devs virtual drivers.
1112
1113 The real maximum number of virtual drivers will depend on how many drivers
1114 will succeed. This is limited to the maximum number of devices that
1115 videodev supports. Since there are 64 minors for video grabbers, this is
1116 currently the theoretical maximum limit. However, a further limit does
1117 exist at videodev that forbids any driver to register more than 32 video
1118 grabbers.
1119 */
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001120static int __init vivi_init(void)
1121{
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001122 int ret = -ENOMEM, i;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001123 struct vivi_dev *dev;
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001124 struct video_device *vfd;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001125
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001126 if (n_devs <= 0)
1127 n_devs = 1;
1128
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001129 for (i = 0; i < n_devs; i++) {
1130 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001131 if (!dev)
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001132 break;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001133
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001134 /* init video dma queues */
1135 INIT_LIST_HEAD(&dev->vidq.active);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001136 init_waitqueue_head(&dev->vidq.wq);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001137
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001138 /* initialize locks */
Mauro Carvalho Chehab55862ac2007-12-13 16:13:37 -03001139 spin_lock_init(&dev->slock);
Brandon Philipsaa9dbac2008-04-02 18:10:59 -03001140 mutex_init(&dev->mutex);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001141
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001142 vfd = video_device_alloc();
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001143 if (!vfd) {
1144 kfree(dev);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001145 break;
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001146 }
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001147
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001148 *vfd = vivi_template;
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001149
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001150 ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001151 if (ret < 0) {
1152 video_device_release(vfd);
1153 kfree(dev);
1154
1155 /* If some registers succeeded, keep driver */
1156 if (i)
1157 ret = 0;
1158
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001159 break;
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001160 }
1161
1162 /* Now that everything is fine, let's add it to device list */
1163 list_add_tail(&dev->vivi_devlist, &vivi_devlist);
Mauro Carvalho Chehabf905c442007-12-10 04:07:03 -03001164
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001165 snprintf(vfd->name, sizeof(vfd->name), "%s (%i)",
1166 vivi_template.name, vfd->minor);
1167
1168 if (video_nr >= 0)
1169 video_nr++;
1170
1171 dev->vfd = vfd;
Carl Karsten745271a2008-06-10 00:02:32 -03001172 printk(KERN_INFO "%s: V4L2 device registered as /dev/video%d\n",
Mauro Carvalho Chehab584ce482008-06-10 15:21:49 -03001173 VIVI_MODULE_NAME, vfd->minor);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001174 }
1175
1176 if (ret < 0) {
1177 vivi_release();
1178 printk(KERN_INFO "Error %d while loading vivi driver\n", ret);
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001179 } else {
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001180 printk(KERN_INFO "Video Technology Magazine Virtual Video "
Carl Karsten745271a2008-06-10 00:02:32 -03001181 "Capture Board ver %u.%u.%u successfully loaded.\n",
1182 (VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF,
1183 VIVI_VERSION & 0xFF);
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001184
1185 /* n_devs will reflect the actual number of allocated devices */
1186 n_devs = i;
1187 }
1188
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001189 return ret;
1190}
1191
1192static void __exit vivi_exit(void)
1193{
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001194 vivi_release();
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001195}
1196
1197module_init(vivi_init);
1198module_exit(vivi_exit);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001199
1200MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
1201MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
1202MODULE_LICENSE("Dual BSD/GPL");
1203
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001204module_param(video_nr, uint, 0444);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001205MODULE_PARM_DESC(video_nr, "video iminor start number");
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001206
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001207module_param(n_devs, uint, 0444);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001208MODULE_PARM_DESC(n_devs, "number of video devices to create");
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001209
Mauro Carvalho Chehab8996b3f2007-12-13 06:36:22 -03001210module_param_named(debug, vivi_template.debug, int, 0444);
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001211MODULE_PARM_DESC(debug, "activates debug info");
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001212
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001213module_param(vid_limit, int, 0644);
1214MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");