blob: 80333714ffa7498e3a63af827d3549468d0664de [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 *
Pawel Osciake007a322011-01-19 13:02:29 -020010 * Conversion to videobuf2 by Pawel Osciak & Marek Szyprowski
11 * Copyright (c) 2010 Samsung Electronics
12 *
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -030013 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the BSD Licence, GNU General Public License
15 * as published by the Free Software Foundation; either version 2 of the
16 * License, or (at your option) any later version
17 */
18#include <linux/module.h>
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -030019#include <linux/errno.h>
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -030020#include <linux/kernel.h>
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -030021#include <linux/init.h>
22#include <linux/sched.h>
Randy Dunlap6b46c392010-05-07 15:22:26 -030023#include <linux/slab.h>
Hans Verkuil730947b2010-04-10 04:13:53 -030024#include <linux/font.h>
Matthias Kaehlcke51b54022007-07-02 10:19:38 -030025#include <linux/mutex.h>
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -030026#include <linux/videodev2.h>
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -030027#include <linux/kthread.h>
Nigel Cunningham7dfb7102006-12-06 20:34:23 -080028#include <linux/freezer.h>
Pawel Osciake007a322011-01-19 13:02:29 -020029#include <media/videobuf2-vmalloc.h>
Hans Verkuil5ab6c9a2009-02-14 13:23:12 -030030#include <media/v4l2-device.h>
31#include <media/v4l2-ioctl.h>
Hans Verkuil7e996af2011-01-23 12:33:16 -020032#include <media/v4l2-ctrls.h>
Hans Verkuil2e4784d2011-03-11 20:01:54 -030033#include <media/v4l2-fh.h>
Hans Verkuilc7a52f82011-06-07 10:20:23 -030034#include <media/v4l2-event.h>
Hans Verkuil730947b2010-04-10 04:13:53 -030035#include <media/v4l2-common.h>
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -030036
Mauro Carvalho Chehab584ce482008-06-10 15:21:49 -030037#define VIVI_MODULE_NAME "vivi"
Carl Karsten745271a2008-06-10 00:02:32 -030038
Kirill Smelkovfe0e9902012-10-23 09:56:59 -030039/* Maximum allowed frame rate
40 *
41 * Vivi will allow setting timeperframe in [1/FPS_MAX - FPS_MAX/1] range.
42 *
43 * Ideally FPS_MAX should be infinity, i.e. practically UINT_MAX, but that
44 * might hit application errors when they manipulate these values.
45 *
46 * Besides, for tpf < 1ms image-generation logic should be changed, to avoid
47 * producing frames with equal content.
48 */
49#define FPS_MAX 1000
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -030050
Hans Verkuil730947b2010-04-10 04:13:53 -030051#define MAX_WIDTH 1920
52#define MAX_HEIGHT 1200
53
Mauro Carvalho Chehab1990d502011-06-24 14:45:49 -030054#define VIVI_VERSION "0.8.1"
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -030055
Hans Verkuil5ab6c9a2009-02-14 13:23:12 -030056MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
57MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
58MODULE_LICENSE("Dual BSD/GPL");
Mauro Carvalho Chehab1990d502011-06-24 14:45:49 -030059MODULE_VERSION(VIVI_VERSION);
Hans Verkuil5ab6c9a2009-02-14 13:23:12 -030060
61static unsigned video_nr = -1;
62module_param(video_nr, uint, 0644);
63MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect");
64
65static unsigned n_devs = 1;
66module_param(n_devs, uint, 0644);
67MODULE_PARM_DESC(n_devs, "number of video devices to create");
68
69static unsigned debug;
70module_param(debug, uint, 0644);
71MODULE_PARM_DESC(debug, "activates debug info");
72
Hans Verkuil730947b2010-04-10 04:13:53 -030073/* Global font descriptor */
74static const u8 *font8x16;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -030075
Kirill Smelkovfe0e9902012-10-23 09:56:59 -030076/* timeperframe: min/max and default */
77static const struct v4l2_fract
78 tpf_min = {.numerator = 1, .denominator = FPS_MAX},
79 tpf_max = {.numerator = FPS_MAX, .denominator = 1},
80 tpf_default = {.numerator = 1001, .denominator = 30000}; /* NTSC */
81
Hans Verkuil5ab6c9a2009-02-14 13:23:12 -030082#define dprintk(dev, level, fmt, arg...) \
83 v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -030084
85/* ------------------------------------------------------------------
86 Basic structures
87 ------------------------------------------------------------------*/
88
89struct vivi_fmt {
Kirill Smelkovc19bec52012-12-26 12:23:26 -030090 const char *name;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -030091 u32 fourcc; /* v4l2 format id */
Hans Verkuil0a3a8a32012-08-06 10:36:18 -030092 u8 depth;
93 bool is_yuv;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -030094};
95
Kirill Smelkovc19bec52012-12-26 12:23:26 -030096static const struct vivi_fmt formats[] = {
Magnus Dammd891f472008-10-14 12:47:09 -030097 {
98 .name = "4:2:2, packed, YUYV",
99 .fourcc = V4L2_PIX_FMT_YUYV,
100 .depth = 16,
Hans Verkuil0a3a8a32012-08-06 10:36:18 -0300101 .is_yuv = true,
Magnus Dammd891f472008-10-14 12:47:09 -0300102 },
Magnus Dammfca36ba2008-10-14 12:47:25 -0300103 {
104 .name = "4:2:2, packed, UYVY",
105 .fourcc = V4L2_PIX_FMT_UYVY,
106 .depth = 16,
Hans Verkuil0a3a8a32012-08-06 10:36:18 -0300107 .is_yuv = true,
Magnus Dammfca36ba2008-10-14 12:47:25 -0300108 },
Magnus Dammaeadb5d2008-10-14 12:47:35 -0300109 {
Hans Verkuil3d51dca2012-05-02 03:15:11 -0300110 .name = "4:2:2, packed, YVYU",
111 .fourcc = V4L2_PIX_FMT_YVYU,
112 .depth = 16,
Hans Verkuil0a3a8a32012-08-06 10:36:18 -0300113 .is_yuv = true,
Hans Verkuil3d51dca2012-05-02 03:15:11 -0300114 },
115 {
116 .name = "4:2:2, packed, VYUY",
117 .fourcc = V4L2_PIX_FMT_VYUY,
118 .depth = 16,
Hans Verkuil0a3a8a32012-08-06 10:36:18 -0300119 .is_yuv = true,
Hans Verkuil3d51dca2012-05-02 03:15:11 -0300120 },
121 {
Magnus Dammaeadb5d2008-10-14 12:47:35 -0300122 .name = "RGB565 (LE)",
123 .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
124 .depth = 16,
125 },
126 {
127 .name = "RGB565 (BE)",
128 .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
129 .depth = 16,
130 },
Magnus Dammdef52392008-10-14 12:47:43 -0300131 {
132 .name = "RGB555 (LE)",
133 .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
134 .depth = 16,
135 },
136 {
137 .name = "RGB555 (BE)",
138 .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
139 .depth = 16,
140 },
Hans Verkuil3d51dca2012-05-02 03:15:11 -0300141 {
142 .name = "RGB24 (LE)",
143 .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */
144 .depth = 24,
145 },
146 {
147 .name = "RGB24 (BE)",
148 .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */
149 .depth = 24,
150 },
151 {
152 .name = "RGB32 (LE)",
153 .fourcc = V4L2_PIX_FMT_RGB32, /* argb */
154 .depth = 32,
155 },
156 {
157 .name = "RGB32 (BE)",
158 .fourcc = V4L2_PIX_FMT_BGR32, /* bgra */
159 .depth = 32,
160 },
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300161};
162
Kirill Smelkovc19bec52012-12-26 12:23:26 -0300163static const struct vivi_fmt *__get_format(u32 pixelformat)
Magnus Dammd891f472008-10-14 12:47:09 -0300164{
Kirill Smelkovc19bec52012-12-26 12:23:26 -0300165 const struct vivi_fmt *fmt;
Magnus Dammd891f472008-10-14 12:47:09 -0300166 unsigned int k;
167
168 for (k = 0; k < ARRAY_SIZE(formats); k++) {
169 fmt = &formats[k];
Kirill Smelkovfe0e9902012-10-23 09:56:59 -0300170 if (fmt->fourcc == pixelformat)
Magnus Dammd891f472008-10-14 12:47:09 -0300171 break;
172 }
173
174 if (k == ARRAY_SIZE(formats))
175 return NULL;
176
177 return &formats[k];
178}
179
Kirill Smelkovc19bec52012-12-26 12:23:26 -0300180static const struct vivi_fmt *get_format(struct v4l2_format *f)
Kirill Smelkovfe0e9902012-10-23 09:56:59 -0300181{
182 return __get_format(f->fmt.pix.pixelformat);
183}
184
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300185/* buffer for one video frame */
186struct vivi_buffer {
187 /* common v4l buffer stuff -- must be first */
Pawel Osciake007a322011-01-19 13:02:29 -0200188 struct vb2_buffer vb;
189 struct list_head list;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300190};
191
192struct vivi_dmaqueue {
193 struct list_head active;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300194
195 /* thread for generating video stream*/
196 struct task_struct *kthread;
197 wait_queue_head_t wq;
198 /* Counters to control fps rate */
199 int frame;
200 int ini_jiffies;
201};
202
203static LIST_HEAD(vivi_devlist);
204
205struct vivi_dev {
206 struct list_head vivi_devlist;
Hans Verkuil5ab6c9a2009-02-14 13:23:12 -0300207 struct v4l2_device v4l2_dev;
Hans Verkuil7e996af2011-01-23 12:33:16 -0200208 struct v4l2_ctrl_handler ctrl_handler;
Hans Verkuil70bd97a2012-06-09 11:27:43 -0300209 struct video_device vdev;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300210
Hans Verkuil730947b2010-04-10 04:13:53 -0300211 /* controls */
Hans Verkuil7e996af2011-01-23 12:33:16 -0200212 struct v4l2_ctrl *brightness;
213 struct v4l2_ctrl *contrast;
214 struct v4l2_ctrl *saturation;
215 struct v4l2_ctrl *hue;
Hans Verkuila1c894f2011-06-07 06:34:41 -0300216 struct {
217 /* autogain/gain cluster */
218 struct v4l2_ctrl *autogain;
219 struct v4l2_ctrl *gain;
220 };
Hans Verkuil7e996af2011-01-23 12:33:16 -0200221 struct v4l2_ctrl *volume;
Hans Verkuil7088f4d2012-05-02 03:33:52 -0300222 struct v4l2_ctrl *alpha;
Hans Verkuil7e996af2011-01-23 12:33:16 -0200223 struct v4l2_ctrl *button;
224 struct v4l2_ctrl *boolean;
225 struct v4l2_ctrl *int32;
226 struct v4l2_ctrl *int64;
227 struct v4l2_ctrl *menu;
228 struct v4l2_ctrl *string;
Hans Verkuilb6d17a52011-03-29 16:33:11 -0300229 struct v4l2_ctrl *bitmask;
Sakari Ailusc5203312011-08-05 06:38:05 -0300230 struct v4l2_ctrl *int_menu;
Hans Verkuil730947b2010-04-10 04:13:53 -0300231
Mauro Carvalho Chehab55862ac2007-12-13 16:13:37 -0300232 spinlock_t slock;
Brandon Philipsaa9dbac2008-04-02 18:10:59 -0300233 struct mutex mutex;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300234
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300235 struct vivi_dmaqueue vidq;
236
237 /* Several counters */
Hans Verkuil730947b2010-04-10 04:13:53 -0300238 unsigned ms;
Mauro Carvalho Chehabdfd8c042008-01-13 19:36:11 -0300239 unsigned long jiffies;
Hans Verkuil7e996af2011-01-23 12:33:16 -0200240 unsigned button_pressed;
Mauro Carvalho Chehab025341d2007-12-10 04:43:38 -0300241
242 int mv_count; /* Controls bars movement */
Mauro Carvalho Chehabe164b582009-01-11 10:29:43 -0300243
244 /* Input Number */
245 int input;
Hans Verkuilc41ee242009-02-14 13:43:44 -0300246
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300247 /* video capture */
Kirill Smelkovc19bec52012-12-26 12:23:26 -0300248 const struct vivi_fmt *fmt;
Kirill Smelkovfe0e9902012-10-23 09:56:59 -0300249 struct v4l2_fract timeperframe;
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300250 unsigned int width, height;
Pawel Osciake007a322011-01-19 13:02:29 -0200251 struct vb2_queue vb_vidq;
Hans Verkuilf0af5e82014-02-10 08:08:45 -0300252 unsigned int seq_count;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300253
Hans Verkuil3d51dca2012-05-02 03:15:11 -0300254 u8 bars[9][3];
Kirill Smelkov10ce8442012-11-02 09:10:31 -0300255 u8 line[MAX_WIDTH * 8] __attribute__((__aligned__(4)));
Hans Verkuil3d51dca2012-05-02 03:15:11 -0300256 unsigned int pixelsize;
Hans Verkuil7088f4d2012-05-02 03:33:52 -0300257 u8 alpha_component;
Kirill Smelkove3a8b4d2012-11-02 09:10:30 -0300258 u32 textfg, textbg;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300259};
260
261/* ------------------------------------------------------------------
262 DMA and thread functions
263 ------------------------------------------------------------------*/
264
265/* Bars and Colors should match positions */
266
267enum colors {
268 WHITE,
Hans Verkuil730947b2010-04-10 04:13:53 -0300269 AMBER,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300270 CYAN,
271 GREEN,
272 MAGENTA,
273 RED,
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300274 BLUE,
275 BLACK,
Hans Verkuil730947b2010-04-10 04:13:53 -0300276 TEXT_BLACK,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300277};
278
Hans Verkuil730947b2010-04-10 04:13:53 -0300279/* R G B */
Mauro Carvalho Chehabe164b582009-01-11 10:29:43 -0300280#define COLOR_WHITE {204, 204, 204}
Hans Verkuil730947b2010-04-10 04:13:53 -0300281#define COLOR_AMBER {208, 208, 0}
282#define COLOR_CYAN { 0, 206, 206}
Mauro Carvalho Chehabe164b582009-01-11 10:29:43 -0300283#define COLOR_GREEN { 0, 239, 0}
284#define COLOR_MAGENTA {239, 0, 239}
285#define COLOR_RED {205, 0, 0}
286#define COLOR_BLUE { 0, 0, 255}
287#define COLOR_BLACK { 0, 0, 0}
288
289struct bar_std {
Hans Verkuil730947b2010-04-10 04:13:53 -0300290 u8 bar[9][3];
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300291};
292
Mauro Carvalho Chehabe164b582009-01-11 10:29:43 -0300293/* Maximum number of bars are 10 - otherwise, the input print code
294 should be modified */
Kirill Smelkovc19bec52012-12-26 12:23:26 -0300295static const struct bar_std bars[] = {
Mauro Carvalho Chehabe164b582009-01-11 10:29:43 -0300296 { /* Standard ITU-R color bar sequence */
Hans Verkuil730947b2010-04-10 04:13:53 -0300297 { COLOR_WHITE, COLOR_AMBER, COLOR_CYAN, COLOR_GREEN,
298 COLOR_MAGENTA, COLOR_RED, COLOR_BLUE, COLOR_BLACK, COLOR_BLACK }
Mauro Carvalho Chehabe164b582009-01-11 10:29:43 -0300299 }, {
Hans Verkuil730947b2010-04-10 04:13:53 -0300300 { COLOR_WHITE, COLOR_AMBER, COLOR_BLACK, COLOR_WHITE,
301 COLOR_AMBER, COLOR_BLACK, COLOR_WHITE, COLOR_AMBER, COLOR_BLACK }
Mauro Carvalho Chehabe164b582009-01-11 10:29:43 -0300302 }, {
Hans Verkuil730947b2010-04-10 04:13:53 -0300303 { COLOR_WHITE, COLOR_CYAN, COLOR_BLACK, COLOR_WHITE,
304 COLOR_CYAN, COLOR_BLACK, COLOR_WHITE, COLOR_CYAN, COLOR_BLACK }
Mauro Carvalho Chehabe164b582009-01-11 10:29:43 -0300305 }, {
Hans Verkuil730947b2010-04-10 04:13:53 -0300306 { COLOR_WHITE, COLOR_GREEN, COLOR_BLACK, COLOR_WHITE,
307 COLOR_GREEN, COLOR_BLACK, COLOR_WHITE, COLOR_GREEN, COLOR_BLACK }
Mauro Carvalho Chehabe164b582009-01-11 10:29:43 -0300308 },
309};
310
311#define NUM_INPUTS ARRAY_SIZE(bars)
312
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300313#define TO_Y(r, g, b) \
314 (((16829 * r + 33039 * g + 6416 * b + 32768) >> 16) + 16)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300315/* RGB to V(Cr) Color transform */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300316#define TO_V(r, g, b) \
317 (((28784 * r - 24103 * g - 4681 * b + 32768) >> 16) + 128)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300318/* RGB to U(Cb) Color transform */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300319#define TO_U(r, g, b) \
320 (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300321
Mauro Carvalho Chehabc285add2009-06-25 16:28:23 -0300322/* precalculate color bar values to speed up rendering */
Hans Verkuil730947b2010-04-10 04:13:53 -0300323static void precalculate_bars(struct vivi_dev *dev)
Mauro Carvalho Chehabc285add2009-06-25 16:28:23 -0300324{
Hans Verkuil730947b2010-04-10 04:13:53 -0300325 u8 r, g, b;
Mauro Carvalho Chehabc285add2009-06-25 16:28:23 -0300326 int k, is_yuv;
327
Hans Verkuil730947b2010-04-10 04:13:53 -0300328 for (k = 0; k < 9; k++) {
329 r = bars[dev->input].bar[k][0];
330 g = bars[dev->input].bar[k][1];
331 b = bars[dev->input].bar[k][2];
Hans Verkuil0a3a8a32012-08-06 10:36:18 -0300332 is_yuv = dev->fmt->is_yuv;
Mauro Carvalho Chehabc285add2009-06-25 16:28:23 -0300333
Hans Verkuil730947b2010-04-10 04:13:53 -0300334 switch (dev->fmt->fourcc) {
Mauro Carvalho Chehabc285add2009-06-25 16:28:23 -0300335 case V4L2_PIX_FMT_RGB565:
336 case V4L2_PIX_FMT_RGB565X:
337 r >>= 3;
338 g >>= 2;
339 b >>= 3;
340 break;
341 case V4L2_PIX_FMT_RGB555:
342 case V4L2_PIX_FMT_RGB555X:
343 r >>= 3;
344 g >>= 3;
345 b >>= 3;
346 break;
Hans Verkuil0a3a8a32012-08-06 10:36:18 -0300347 case V4L2_PIX_FMT_YUYV:
348 case V4L2_PIX_FMT_UYVY:
349 case V4L2_PIX_FMT_YVYU:
350 case V4L2_PIX_FMT_VYUY:
Hans Verkuil3d51dca2012-05-02 03:15:11 -0300351 case V4L2_PIX_FMT_RGB24:
352 case V4L2_PIX_FMT_BGR24:
353 case V4L2_PIX_FMT_RGB32:
354 case V4L2_PIX_FMT_BGR32:
355 break;
Mauro Carvalho Chehabc285add2009-06-25 16:28:23 -0300356 }
357
358 if (is_yuv) {
Hans Verkuil730947b2010-04-10 04:13:53 -0300359 dev->bars[k][0] = TO_Y(r, g, b); /* Luma */
360 dev->bars[k][1] = TO_U(r, g, b); /* Cb */
361 dev->bars[k][2] = TO_V(r, g, b); /* Cr */
Mauro Carvalho Chehabc285add2009-06-25 16:28:23 -0300362 } else {
Hans Verkuil730947b2010-04-10 04:13:53 -0300363 dev->bars[k][0] = r;
364 dev->bars[k][1] = g;
365 dev->bars[k][2] = b;
Mauro Carvalho Chehabc285add2009-06-25 16:28:23 -0300366 }
367 }
Mauro Carvalho Chehabc285add2009-06-25 16:28:23 -0300368}
369
Hans Verkuil3d51dca2012-05-02 03:15:11 -0300370/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
371static void gen_twopix(struct vivi_dev *dev, u8 *buf, int colorpos, bool odd)
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300372{
Hans Verkuil730947b2010-04-10 04:13:53 -0300373 u8 r_y, g_u, b_v;
Hans Verkuil7088f4d2012-05-02 03:33:52 -0300374 u8 alpha = dev->alpha_component;
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300375 int color;
Hans Verkuil730947b2010-04-10 04:13:53 -0300376 u8 *p;
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300377
Hans Verkuil730947b2010-04-10 04:13:53 -0300378 r_y = dev->bars[colorpos][0]; /* R or precalculated Y */
379 g_u = dev->bars[colorpos][1]; /* G or precalculated U */
380 b_v = dev->bars[colorpos][2]; /* B or precalculated V */
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300381
Hans Verkuil3d51dca2012-05-02 03:15:11 -0300382 for (color = 0; color < dev->pixelsize; color++) {
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300383 p = buf + color;
384
Hans Verkuil730947b2010-04-10 04:13:53 -0300385 switch (dev->fmt->fourcc) {
Magnus Dammd891f472008-10-14 12:47:09 -0300386 case V4L2_PIX_FMT_YUYV:
387 switch (color) {
388 case 0:
Magnus Dammd891f472008-10-14 12:47:09 -0300389 *p = r_y;
390 break;
391 case 1:
Hans Verkuil3d51dca2012-05-02 03:15:11 -0300392 *p = odd ? b_v : g_u;
Magnus Dammd891f472008-10-14 12:47:09 -0300393 break;
394 }
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300395 break;
Magnus Dammfca36ba2008-10-14 12:47:25 -0300396 case V4L2_PIX_FMT_UYVY:
397 switch (color) {
Hans Verkuil3d51dca2012-05-02 03:15:11 -0300398 case 0:
399 *p = odd ? b_v : g_u;
400 break;
Magnus Dammfca36ba2008-10-14 12:47:25 -0300401 case 1:
Magnus Dammfca36ba2008-10-14 12:47:25 -0300402 *p = r_y;
403 break;
Hans Verkuil3d51dca2012-05-02 03:15:11 -0300404 }
405 break;
406 case V4L2_PIX_FMT_YVYU:
407 switch (color) {
Magnus Dammfca36ba2008-10-14 12:47:25 -0300408 case 0:
Hans Verkuil3d51dca2012-05-02 03:15:11 -0300409 *p = r_y;
Magnus Dammfca36ba2008-10-14 12:47:25 -0300410 break;
Hans Verkuil3d51dca2012-05-02 03:15:11 -0300411 case 1:
412 *p = odd ? g_u : b_v;
413 break;
414 }
415 break;
416 case V4L2_PIX_FMT_VYUY:
417 switch (color) {
418 case 0:
419 *p = odd ? g_u : b_v;
420 break;
421 case 1:
422 *p = r_y;
Magnus Dammfca36ba2008-10-14 12:47:25 -0300423 break;
424 }
425 break;
Magnus Dammaeadb5d2008-10-14 12:47:35 -0300426 case V4L2_PIX_FMT_RGB565:
427 switch (color) {
428 case 0:
Magnus Dammaeadb5d2008-10-14 12:47:35 -0300429 *p = (g_u << 5) | b_v;
430 break;
431 case 1:
Magnus Dammaeadb5d2008-10-14 12:47:35 -0300432 *p = (r_y << 3) | (g_u >> 3);
433 break;
434 }
435 break;
436 case V4L2_PIX_FMT_RGB565X:
437 switch (color) {
438 case 0:
Magnus Dammaeadb5d2008-10-14 12:47:35 -0300439 *p = (r_y << 3) | (g_u >> 3);
440 break;
441 case 1:
Magnus Dammaeadb5d2008-10-14 12:47:35 -0300442 *p = (g_u << 5) | b_v;
443 break;
444 }
445 break;
Magnus Dammdef52392008-10-14 12:47:43 -0300446 case V4L2_PIX_FMT_RGB555:
447 switch (color) {
448 case 0:
Magnus Dammdef52392008-10-14 12:47:43 -0300449 *p = (g_u << 5) | b_v;
450 break;
451 case 1:
Hans Verkuil7088f4d2012-05-02 03:33:52 -0300452 *p = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
Magnus Dammdef52392008-10-14 12:47:43 -0300453 break;
454 }
455 break;
456 case V4L2_PIX_FMT_RGB555X:
457 switch (color) {
458 case 0:
Hans Verkuil7088f4d2012-05-02 03:33:52 -0300459 *p = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
Magnus Dammdef52392008-10-14 12:47:43 -0300460 break;
461 case 1:
Magnus Dammdef52392008-10-14 12:47:43 -0300462 *p = (g_u << 5) | b_v;
463 break;
464 }
465 break;
Hans Verkuil3d51dca2012-05-02 03:15:11 -0300466 case V4L2_PIX_FMT_RGB24:
467 switch (color) {
468 case 0:
469 *p = r_y;
470 break;
471 case 1:
472 *p = g_u;
473 break;
474 case 2:
475 *p = b_v;
476 break;
477 }
478 break;
479 case V4L2_PIX_FMT_BGR24:
480 switch (color) {
481 case 0:
482 *p = b_v;
483 break;
484 case 1:
485 *p = g_u;
486 break;
487 case 2:
488 *p = r_y;
489 break;
490 }
491 break;
492 case V4L2_PIX_FMT_RGB32:
493 switch (color) {
494 case 0:
Hans Verkuil7088f4d2012-05-02 03:33:52 -0300495 *p = alpha;
Hans Verkuil3d51dca2012-05-02 03:15:11 -0300496 break;
497 case 1:
498 *p = r_y;
499 break;
500 case 2:
501 *p = g_u;
502 break;
503 case 3:
504 *p = b_v;
505 break;
506 }
507 break;
508 case V4L2_PIX_FMT_BGR32:
509 switch (color) {
510 case 0:
511 *p = b_v;
512 break;
513 case 1:
514 *p = g_u;
515 break;
516 case 2:
517 *p = r_y;
518 break;
519 case 3:
Hans Verkuil7088f4d2012-05-02 03:33:52 -0300520 *p = alpha;
Hans Verkuil3d51dca2012-05-02 03:15:11 -0300521 break;
522 }
523 break;
Magnus Damm74d7c5a2008-10-14 12:46:59 -0300524 }
525 }
526}
527
Hans Verkuil730947b2010-04-10 04:13:53 -0300528static void precalculate_line(struct vivi_dev *dev)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300529{
Kirill Smelkovd40fbf82012-11-02 09:10:33 -0300530 unsigned pixsize = dev->pixelsize;
531 unsigned pixsize2 = 2*pixsize;
532 int colorpos;
533 u8 *pos;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300534
Kirill Smelkovd40fbf82012-11-02 09:10:33 -0300535 for (colorpos = 0; colorpos < 16; ++colorpos) {
536 u8 pix[8];
537 int wstart = colorpos * dev->width / 8;
538 int wend = (colorpos+1) * dev->width / 8;
539 int w;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300540
Kirill Smelkovd40fbf82012-11-02 09:10:33 -0300541 gen_twopix(dev, &pix[0], colorpos % 8, 0);
542 gen_twopix(dev, &pix[pixsize], colorpos % 8, 1);
543
544 for (w = wstart/2*2, pos = dev->line + w*pixsize; w < wend; w += 2, pos += pixsize2)
545 memcpy(pos, pix, pixsize2);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300546 }
Hans Verkuil730947b2010-04-10 04:13:53 -0300547}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300548
Kirill Smelkove3a8b4d2012-11-02 09:10:30 -0300549/* need this to do rgb24 rendering */
550typedef struct { u16 __; u8 _; } __attribute__((packed)) x24;
551
Hans Verkuil730947b2010-04-10 04:13:53 -0300552static void gen_text(struct vivi_dev *dev, char *basep,
553 int y, int x, char *text)
554{
555 int line;
Kirill Smelkove3a8b4d2012-11-02 09:10:30 -0300556 unsigned int width = dev->width;
Mauro Carvalho Chehabe164b582009-01-11 10:29:43 -0300557
Hans Verkuil730947b2010-04-10 04:13:53 -0300558 /* Checks if it is possible to show string */
Kirill Smelkove3a8b4d2012-11-02 09:10:30 -0300559 if (y + 16 >= dev->height || x + strlen(text) * 8 >= width)
Hans Verkuil730947b2010-04-10 04:13:53 -0300560 return;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300561
562 /* Print stream time */
Kirill Smelkove3a8b4d2012-11-02 09:10:30 -0300563#define PRINTSTR(PIXTYPE) do { \
564 PIXTYPE fg; \
565 PIXTYPE bg; \
566 memcpy(&fg, &dev->textfg, sizeof(PIXTYPE)); \
567 memcpy(&bg, &dev->textbg, sizeof(PIXTYPE)); \
568 \
569 for (line = 0; line < 16; line++) { \
570 PIXTYPE *pos = (PIXTYPE *)( basep + ((y + line) * width + x) * sizeof(PIXTYPE) ); \
571 u8 *s; \
572 \
573 for (s = text; *s; s++) { \
574 u8 chr = font8x16[*s * 16 + line]; \
575 \
576 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
577 pos[1] = (chr & (0x01 << 6) ? fg : bg); \
578 pos[2] = (chr & (0x01 << 5) ? fg : bg); \
579 pos[3] = (chr & (0x01 << 4) ? fg : bg); \
580 pos[4] = (chr & (0x01 << 3) ? fg : bg); \
581 pos[5] = (chr & (0x01 << 2) ? fg : bg); \
582 pos[6] = (chr & (0x01 << 1) ? fg : bg); \
583 pos[7] = (chr & (0x01 << 0) ? fg : bg); \
584 \
585 pos += 8; \
586 } \
587 } \
588} while (0)
Hans Verkuil730947b2010-04-10 04:13:53 -0300589
Kirill Smelkove3a8b4d2012-11-02 09:10:30 -0300590 switch (dev->pixelsize) {
591 case 2:
592 PRINTSTR(u16); break;
593 case 4:
594 PRINTSTR(u32); break;
595 case 3:
596 PRINTSTR(x24); break;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300597 }
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300598}
Brandon Philips78718e52008-04-02 18:10:59 -0300599
Hans Verkuil730947b2010-04-10 04:13:53 -0300600static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300601{
Kirill Smelkov13908f32012-11-02 09:10:32 -0300602 int stride = dev->width * dev->pixelsize;
Pawel Osciake007a322011-01-19 13:02:29 -0200603 int hmax = dev->height;
Pawel Osciake007a322011-01-19 13:02:29 -0200604 void *vbuf = vb2_plane_vaddr(&buf->vb, 0);
Hans Verkuil730947b2010-04-10 04:13:53 -0300605 unsigned ms;
606 char str[100];
607 int h, line = 1;
Kirill Smelkov13908f32012-11-02 09:10:32 -0300608 u8 *linestart;
Hans Verkuila1c894f2011-06-07 06:34:41 -0300609 s32 gain;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300610
Marcin Slusarz5c554e62008-06-22 09:11:40 -0300611 if (!vbuf)
Mauro Carvalho Chehab5a037702007-08-02 23:31:54 -0300612 return;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300613
Kirill Smelkov13908f32012-11-02 09:10:32 -0300614 linestart = dev->line + (dev->mv_count % dev->width) * dev->pixelsize;
615
Hans Verkuil730947b2010-04-10 04:13:53 -0300616 for (h = 0; h < hmax; h++)
Kirill Smelkov13908f32012-11-02 09:10:32 -0300617 memcpy(vbuf + h * stride, linestart, stride);
Mauro Carvalho Chehab5a037702007-08-02 23:31:54 -0300618
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300619 /* Updates stream time */
620
Kirill Smelkove3a8b4d2012-11-02 09:10:30 -0300621 gen_twopix(dev, (u8 *)&dev->textbg, TEXT_BLACK, /*odd=*/ 0);
622 gen_twopix(dev, (u8 *)&dev->textfg, WHITE, /*odd=*/ 0);
623
Hans Verkuil730947b2010-04-10 04:13:53 -0300624 dev->ms += jiffies_to_msecs(jiffies - dev->jiffies);
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300625 dev->jiffies = jiffies;
Hans Verkuil730947b2010-04-10 04:13:53 -0300626 ms = dev->ms;
627 snprintf(str, sizeof(str), " %02d:%02d:%02d:%03d ",
628 (ms / (60 * 60 * 1000)) % 24,
629 (ms / (60 * 1000)) % 60,
630 (ms / 1000) % 60,
631 ms % 1000);
632 gen_text(dev, vbuf, line++ * 16, 16, str);
633 snprintf(str, sizeof(str), " %dx%d, input %d ",
634 dev->width, dev->height, dev->input);
635 gen_text(dev, vbuf, line++ * 16, 16, str);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300636
Hans Verkuila1c894f2011-06-07 06:34:41 -0300637 gain = v4l2_ctrl_g_ctrl(dev->gain);
Sakari Ailus77e7c4e2012-01-24 21:05:34 -0300638 mutex_lock(dev->ctrl_handler.lock);
Hans Verkuil730947b2010-04-10 04:13:53 -0300639 snprintf(str, sizeof(str), " brightness %3d, contrast %3d, saturation %3d, hue %d ",
Hans Verkuil7e996af2011-01-23 12:33:16 -0200640 dev->brightness->cur.val,
641 dev->contrast->cur.val,
642 dev->saturation->cur.val,
643 dev->hue->cur.val);
Hans Verkuil730947b2010-04-10 04:13:53 -0300644 gen_text(dev, vbuf, line++ * 16, 16, str);
Hans Verkuil7088f4d2012-05-02 03:33:52 -0300645 snprintf(str, sizeof(str), " autogain %d, gain %3d, volume %3d, alpha 0x%02x ",
646 dev->autogain->cur.val, gain, dev->volume->cur.val,
647 dev->alpha->cur.val);
Hans Verkuil730947b2010-04-10 04:13:53 -0300648 gen_text(dev, vbuf, line++ * 16, 16, str);
Hans Verkuilb6d17a52011-03-29 16:33:11 -0300649 snprintf(str, sizeof(str), " int32 %d, int64 %lld, bitmask %08x ",
Hans Verkuil7e996af2011-01-23 12:33:16 -0200650 dev->int32->cur.val,
Hans Verkuil2a9ec372014-04-27 03:38:13 -0300651 *dev->int64->p_cur.p_s64,
Hans Verkuilb6d17a52011-03-29 16:33:11 -0300652 dev->bitmask->cur.val);
Hans Verkuil7e996af2011-01-23 12:33:16 -0200653 gen_text(dev, vbuf, line++ * 16, 16, str);
654 snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ",
655 dev->boolean->cur.val,
656 dev->menu->qmenu[dev->menu->cur.val],
Hans Verkuil2a9ec372014-04-27 03:38:13 -0300657 dev->string->p_cur.p_char);
Hans Verkuilf70cfc72012-04-19 11:44:18 -0300658 gen_text(dev, vbuf, line++ * 16, 16, str);
Sakari Ailusc5203312011-08-05 06:38:05 -0300659 snprintf(str, sizeof(str), " integer_menu %lld, value %d ",
660 dev->int_menu->qmenu_int[dev->int_menu->cur.val],
661 dev->int_menu->cur.val);
662 gen_text(dev, vbuf, line++ * 16, 16, str);
Sakari Ailus77e7c4e2012-01-24 21:05:34 -0300663 mutex_unlock(dev->ctrl_handler.lock);
Hans Verkuil7e996af2011-01-23 12:33:16 -0200664 if (dev->button_pressed) {
665 dev->button_pressed--;
666 snprintf(str, sizeof(str), " button pressed!");
667 gen_text(dev, vbuf, line++ * 16, 16, str);
668 }
Hans Verkuil730947b2010-04-10 04:13:53 -0300669
670 dev->mv_count += 2;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300671
Hans Verkuilcd779252012-07-25 11:48:53 -0300672 buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
Hans Verkuilf0af5e82014-02-10 08:08:45 -0300673 buf->vb.v4l2_buf.sequence = dev->seq_count++;
Sakari Ailus8e6057b2012-09-15 15:14:42 -0300674 v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300675}
676
Hans Verkuil730947b2010-04-10 04:13:53 -0300677static void vivi_thread_tick(struct vivi_dev *dev)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300678{
Brandon Philips78718e52008-04-02 18:10:59 -0300679 struct vivi_dmaqueue *dma_q = &dev->vidq;
Hans Verkuil730947b2010-04-10 04:13:53 -0300680 struct vivi_buffer *buf;
Brandon Philips78718e52008-04-02 18:10:59 -0300681 unsigned long flags = 0;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300682
Brandon Philips78718e52008-04-02 18:10:59 -0300683 dprintk(dev, 1, "Thread tick\n");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300684
Brandon Philips78718e52008-04-02 18:10:59 -0300685 spin_lock_irqsave(&dev->slock, flags);
686 if (list_empty(&dma_q->active)) {
687 dprintk(dev, 1, "No active queue to serve\n");
Hans Verkuil1de5be52011-07-05 07:19:23 -0300688 spin_unlock_irqrestore(&dev->slock, flags);
689 return;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300690 }
Brandon Philips78718e52008-04-02 18:10:59 -0300691
Pawel Osciake007a322011-01-19 13:02:29 -0200692 buf = list_entry(dma_q->active.next, struct vivi_buffer, list);
693 list_del(&buf->list);
Hans Verkuil1de5be52011-07-05 07:19:23 -0300694 spin_unlock_irqrestore(&dev->slock, flags);
Brandon Philips78718e52008-04-02 18:10:59 -0300695
Sakari Ailus8e6057b2012-09-15 15:14:42 -0300696 v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
Brandon Philips78718e52008-04-02 18:10:59 -0300697
698 /* Fill buffer */
Hans Verkuil730947b2010-04-10 04:13:53 -0300699 vivi_fillbuff(dev, buf);
Brandon Philips78718e52008-04-02 18:10:59 -0300700 dprintk(dev, 1, "filled buffer %p\n", buf);
701
Pawel Osciake007a322011-01-19 13:02:29 -0200702 vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
703 dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300704}
705
Kirill Smelkovfe0e9902012-10-23 09:56:59 -0300706#define frames_to_ms(dev, frames) \
707 ((frames * dev->timeperframe.numerator * 1000) / dev->timeperframe.denominator)
Mauro Carvalho Chehab6594ad82007-12-13 16:15:41 -0300708
Hans Verkuil730947b2010-04-10 04:13:53 -0300709static void vivi_sleep(struct vivi_dev *dev)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300710{
Brandon Philips78718e52008-04-02 18:10:59 -0300711 struct vivi_dmaqueue *dma_q = &dev->vidq;
712 int timeout;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300713 DECLARE_WAITQUEUE(wait, current);
714
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300715 dprintk(dev, 1, "%s dma_q=0x%08lx\n", __func__,
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300716 (unsigned long)dma_q);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300717
718 add_wait_queue(&dma_q->wq, &wait);
Mauro Carvalho Chehab6594ad82007-12-13 16:15:41 -0300719 if (kthread_should_stop())
720 goto stop_task;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300721
Mauro Carvalho Chehab6594ad82007-12-13 16:15:41 -0300722 /* Calculate time to wake up */
Kirill Smelkovfe0e9902012-10-23 09:56:59 -0300723 timeout = msecs_to_jiffies(frames_to_ms(dev, 1));
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300724
Hans Verkuil730947b2010-04-10 04:13:53 -0300725 vivi_thread_tick(dev);
Mauro Carvalho Chehab6594ad82007-12-13 16:15:41 -0300726
727 schedule_timeout_interruptible(timeout);
728
729stop_task:
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300730 remove_wait_queue(&dma_q->wq, &wait);
731 try_to_freeze();
732}
733
Adrian Bunk972c3512006-04-27 21:06:50 -0300734static int vivi_thread(void *data)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300735{
Hans Verkuil730947b2010-04-10 04:13:53 -0300736 struct vivi_dev *dev = data;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300737
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300738 dprintk(dev, 1, "thread started\n");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300739
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700740 set_freezable();
Mauro Carvalho Chehab0b600512007-01-14 08:33:24 -0300741
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300742 for (;;) {
Hans Verkuil730947b2010-04-10 04:13:53 -0300743 vivi_sleep(dev);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300744
745 if (kthread_should_stop())
746 break;
747 }
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300748 dprintk(dev, 1, "thread: exit\n");
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300749 return 0;
750}
751
Pawel Osciake007a322011-01-19 13:02:29 -0200752static int vivi_start_generating(struct vivi_dev *dev)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300753{
Brandon Philips78718e52008-04-02 18:10:59 -0300754 struct vivi_dmaqueue *dma_q = &dev->vidq;
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300755
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300756 dprintk(dev, 1, "%s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300757
Hans Verkuil730947b2010-04-10 04:13:53 -0300758 /* Resets frame counters */
759 dev->ms = 0;
760 dev->mv_count = 0;
761 dev->jiffies = jiffies;
762
763 dma_q->frame = 0;
764 dma_q->ini_jiffies = jiffies;
Kees Cookf1701682013-07-03 15:04:58 -0700765 dma_q->kthread = kthread_run(vivi_thread, dev, "%s",
766 dev->v4l2_dev.name);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300767
Akinobu Mita054afee2006-12-20 10:04:00 -0300768 if (IS_ERR(dma_q->kthread)) {
Hans Verkuil5ab6c9a2009-02-14 13:23:12 -0300769 v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
Pawel Osciake007a322011-01-19 13:02:29 -0200770 return PTR_ERR(dma_q->kthread);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300771 }
Mauro Carvalho Chehab0b600512007-01-14 08:33:24 -0300772 /* Wakes thread */
773 wake_up_interruptible(&dma_q->wq);
774
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300775 dprintk(dev, 1, "returning from %s\n", __func__);
Pawel Osciake007a322011-01-19 13:02:29 -0200776 return 0;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300777}
778
Pawel Osciake007a322011-01-19 13:02:29 -0200779static void vivi_stop_generating(struct vivi_dev *dev)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300780{
Hans Verkuil730947b2010-04-10 04:13:53 -0300781 struct vivi_dmaqueue *dma_q = &dev->vidq;
Mauro Carvalho Chehab6c2f9902007-12-13 13:30:14 -0300782
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300783 dprintk(dev, 1, "%s\n", __func__);
Hans Verkuil730947b2010-04-10 04:13:53 -0300784
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300785 /* shutdown control thread */
786 if (dma_q->kthread) {
787 kthread_stop(dma_q->kthread);
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300788 dma_q->kthread = NULL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300789 }
Hans Verkuil730947b2010-04-10 04:13:53 -0300790
Pawel Osciake007a322011-01-19 13:02:29 -0200791 /*
792 * Typical driver might need to wait here until dma engine stops.
793 * In this case we can abort imiedetly, so it's just a noop.
794 */
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300795
Pawel Osciake007a322011-01-19 13:02:29 -0200796 /* Release all active buffers */
797 while (!list_empty(&dma_q->active)) {
798 struct vivi_buffer *buf;
799 buf = list_entry(dma_q->active.next, struct vivi_buffer, list);
800 list_del(&buf->list);
801 vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
802 dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);
803 }
804}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300805/* ------------------------------------------------------------------
806 Videobuf operations
807 ------------------------------------------------------------------*/
Guennadi Liakhovetskifc714e702011-08-24 10:30:21 -0300808static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
809 unsigned int *nbuffers, unsigned int *nplanes,
810 unsigned int sizes[], void *alloc_ctxs[])
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300811{
Pawel Osciake007a322011-01-19 13:02:29 -0200812 struct vivi_dev *dev = vb2_get_drv_priv(vq);
813 unsigned long size;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300814
Hans Verkuilefab6b62014-02-10 08:08:47 -0300815 size = dev->width * dev->height * dev->pixelsize;
816 if (fmt) {
817 if (fmt->fmt.pix.sizeimage < size)
818 return -EINVAL;
Hans Verkuil2e90c6c2012-06-22 05:53:31 -0300819 size = fmt->fmt.pix.sizeimage;
Hans Verkuilefab6b62014-02-10 08:08:47 -0300820 /* check against insane over 8K resolution buffers */
821 if (size > 7680 * 4320 * dev->pixelsize)
822 return -EINVAL;
823 }
Mauro Carvalho Chehab6bb27902007-08-23 16:41:14 -0300824
Pawel Osciake007a322011-01-19 13:02:29 -0200825 *nplanes = 1;
826
827 sizes[0] = size;
828
829 /*
830 * videobuf2-vmalloc allocator is context-less so no need to set
831 * alloc_ctxs array.
832 */
833
834 dprintk(dev, 1, "%s, count=%d, size=%ld\n", __func__,
835 *nbuffers, size);
Mauro Carvalho Chehab6bb27902007-08-23 16:41:14 -0300836
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300837 return 0;
838}
839
Pawel Osciake007a322011-01-19 13:02:29 -0200840static int buffer_prepare(struct vb2_buffer *vb)
841{
842 struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
843 struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
844 unsigned long size;
845
846 dprintk(dev, 1, "%s, field=%d\n", __func__, vb->v4l2_buf.field);
847
848 BUG_ON(NULL == dev->fmt);
849
850 /*
851 * Theses properties only change when queue is idle, see s_fmt.
852 * The below checks should not be performed here, on each
853 * buffer_prepare (i.e. on each qbuf). Most of the code in this function
854 * should thus be moved to buffer_init and s_fmt.
855 */
Hans Verkuil730947b2010-04-10 04:13:53 -0300856 if (dev->width < 48 || dev->width > MAX_WIDTH ||
857 dev->height < 32 || dev->height > MAX_HEIGHT)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300858 return -EINVAL;
Brandon Philips78718e52008-04-02 18:10:59 -0300859
Hans Verkuil3d51dca2012-05-02 03:15:11 -0300860 size = dev->width * dev->height * dev->pixelsize;
Pawel Osciake007a322011-01-19 13:02:29 -0200861 if (vb2_plane_size(vb, 0) < size) {
862 dprintk(dev, 1, "%s data will not fit into plane (%lu < %lu)\n",
863 __func__, vb2_plane_size(vb, 0), size);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300864 return -EINVAL;
Pawel Osciake007a322011-01-19 13:02:29 -0200865 }
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300866
Pawel Osciake007a322011-01-19 13:02:29 -0200867 vb2_set_plane_payload(&buf->vb, 0, size);
868
Hans Verkuil730947b2010-04-10 04:13:53 -0300869 precalculate_bars(dev);
870 precalculate_line(dev);
Mauro Carvalho Chehabc285add2009-06-25 16:28:23 -0300871
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300872 return 0;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300873}
874
Pawel Osciake007a322011-01-19 13:02:29 -0200875static void buffer_queue(struct vb2_buffer *vb)
876{
877 struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
Hans Verkuil730947b2010-04-10 04:13:53 -0300878 struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
Brandon Philips78718e52008-04-02 18:10:59 -0300879 struct vivi_dmaqueue *vidq = &dev->vidq;
Pawel Osciake007a322011-01-19 13:02:29 -0200880 unsigned long flags = 0;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300881
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300882 dprintk(dev, 1, "%s\n", __func__);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300883
Pawel Osciake007a322011-01-19 13:02:29 -0200884 spin_lock_irqsave(&dev->slock, flags);
885 list_add_tail(&buf->list, &vidq->active);
886 spin_unlock_irqrestore(&dev->slock, flags);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300887}
888
Marek Szyprowskibd323e22011-08-29 08:51:49 -0300889static int start_streaming(struct vb2_queue *vq, unsigned int count)
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300890{
Pawel Osciake007a322011-01-19 13:02:29 -0200891 struct vivi_dev *dev = vb2_get_drv_priv(vq);
Hans Verkuil48d829d2014-02-21 05:34:49 -0300892 int err;
Hans Verkuilf0af5e82014-02-10 08:08:45 -0300893
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300894 dprintk(dev, 1, "%s\n", __func__);
Hans Verkuilf0af5e82014-02-10 08:08:45 -0300895 dev->seq_count = 0;
Hans Verkuil48d829d2014-02-21 05:34:49 -0300896 err = vivi_start_generating(dev);
897 if (err) {
898 struct vivi_buffer *buf, *tmp;
899
900 list_for_each_entry_safe(buf, tmp, &dev->vidq.active, list) {
901 list_del(&buf->list);
902 vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
903 }
904 }
905 return err;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300906}
907
Pawel Osciake007a322011-01-19 13:02:29 -0200908/* abort streaming and wait for last buffer */
Hans Verkuile37559b2014-04-17 02:47:21 -0300909static void stop_streaming(struct vb2_queue *vq)
Pawel Osciake007a322011-01-19 13:02:29 -0200910{
911 struct vivi_dev *dev = vb2_get_drv_priv(vq);
912 dprintk(dev, 1, "%s\n", __func__);
913 vivi_stop_generating(dev);
Pawel Osciake007a322011-01-19 13:02:29 -0200914}
915
916static void vivi_lock(struct vb2_queue *vq)
917{
918 struct vivi_dev *dev = vb2_get_drv_priv(vq);
919 mutex_lock(&dev->mutex);
920}
921
922static void vivi_unlock(struct vb2_queue *vq)
923{
924 struct vivi_dev *dev = vb2_get_drv_priv(vq);
925 mutex_unlock(&dev->mutex);
926}
927
928
Kirill Smelkovc19bec52012-12-26 12:23:26 -0300929static const struct vb2_ops vivi_video_qops = {
Pawel Osciake007a322011-01-19 13:02:29 -0200930 .queue_setup = queue_setup,
Pawel Osciake007a322011-01-19 13:02:29 -0200931 .buf_prepare = buffer_prepare,
Pawel Osciake007a322011-01-19 13:02:29 -0200932 .buf_queue = buffer_queue,
933 .start_streaming = start_streaming,
934 .stop_streaming = stop_streaming,
935 .wait_prepare = vivi_unlock,
936 .wait_finish = vivi_lock,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300937};
938
939/* ------------------------------------------------------------------
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300940 IOCTL vidioc handling
941 ------------------------------------------------------------------*/
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -0300942static int vidioc_querycap(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300943 struct v4l2_capability *cap)
944{
Hans Verkuil730947b2010-04-10 04:13:53 -0300945 struct vivi_dev *dev = video_drvdata(file);
Hans Verkuil5ab6c9a2009-02-14 13:23:12 -0300946
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300947 strcpy(cap->driver, "vivi");
948 strcpy(cap->card, "vivi");
Hans Verkuil72c2af62012-09-14 06:23:12 -0300949 snprintf(cap->bus_info, sizeof(cap->bus_info),
950 "platform:%s", dev->v4l2_dev.name);
Hans Verkuil23268ae2012-01-24 05:24:36 -0300951 cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
952 V4L2_CAP_READWRITE;
953 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300954 return 0;
955}
956
Hans Verkuil78b526a2008-05-28 12:16:41 -0300957static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300958 struct v4l2_fmtdesc *f)
959{
Kirill Smelkovc19bec52012-12-26 12:23:26 -0300960 const struct vivi_fmt *fmt;
Magnus Dammd891f472008-10-14 12:47:09 -0300961
962 if (f->index >= ARRAY_SIZE(formats))
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300963 return -EINVAL;
964
Magnus Dammd891f472008-10-14 12:47:09 -0300965 fmt = &formats[f->index];
966
967 strlcpy(f->description, fmt->name, sizeof(f->description));
968 f->pixelformat = fmt->fourcc;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300969 return 0;
970}
971
Hans Verkuil78b526a2008-05-28 12:16:41 -0300972static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300973 struct v4l2_format *f)
974{
Hans Verkuil730947b2010-04-10 04:13:53 -0300975 struct vivi_dev *dev = video_drvdata(file);
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300976
Hans Verkuil730947b2010-04-10 04:13:53 -0300977 f->fmt.pix.width = dev->width;
978 f->fmt.pix.height = dev->height;
Hans Verkuilcd779252012-07-25 11:48:53 -0300979 f->fmt.pix.field = V4L2_FIELD_INTERLACED;
Hans Verkuil730947b2010-04-10 04:13:53 -0300980 f->fmt.pix.pixelformat = dev->fmt->fourcc;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300981 f->fmt.pix.bytesperline =
Hans Verkuil730947b2010-04-10 04:13:53 -0300982 (f->fmt.pix.width * dev->fmt->depth) >> 3;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300983 f->fmt.pix.sizeimage =
984 f->fmt.pix.height * f->fmt.pix.bytesperline;
Hans Verkuil0a3a8a32012-08-06 10:36:18 -0300985 if (dev->fmt->is_yuv)
Hans Verkuil8c79eec2011-07-29 07:19:46 -0300986 f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
987 else
988 f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
Hans Verkuil730947b2010-04-10 04:13:53 -0300989 return 0;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -0300990}
991
Hans Verkuil78b526a2008-05-28 12:16:41 -0300992static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300993 struct v4l2_format *f)
994{
Hans Verkuil730947b2010-04-10 04:13:53 -0300995 struct vivi_dev *dev = video_drvdata(file);
Kirill Smelkovc19bec52012-12-26 12:23:26 -0300996 const struct vivi_fmt *fmt;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -0300997
Magnus Dammd891f472008-10-14 12:47:09 -0300998 fmt = get_format(f);
999 if (!fmt) {
Hans Verkuilcd779252012-07-25 11:48:53 -03001000 dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n",
Magnus Dammd891f472008-10-14 12:47:09 -03001001 f->fmt.pix.pixelformat);
Hans Verkuilcd779252012-07-25 11:48:53 -03001002 f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
1003 fmt = get_format(f);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001004 }
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001005
Hans Verkuilcd779252012-07-25 11:48:53 -03001006 f->fmt.pix.field = V4L2_FIELD_INTERLACED;
Hans Verkuil730947b2010-04-10 04:13:53 -03001007 v4l_bound_align_image(&f->fmt.pix.width, 48, MAX_WIDTH, 2,
1008 &f->fmt.pix.height, 32, MAX_HEIGHT, 0, 0);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001009 f->fmt.pix.bytesperline =
1010 (f->fmt.pix.width * fmt->depth) >> 3;
1011 f->fmt.pix.sizeimage =
1012 f->fmt.pix.height * f->fmt.pix.bytesperline;
Hans Verkuil0a3a8a32012-08-06 10:36:18 -03001013 if (fmt->is_yuv)
Hans Verkuil8c79eec2011-07-29 07:19:46 -03001014 f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
1015 else
1016 f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001017 return 0;
1018}
1019
Mauro Carvalho Chehabe164b582009-01-11 10:29:43 -03001020static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
1021 struct v4l2_format *f)
1022{
Hans Verkuil730947b2010-04-10 04:13:53 -03001023 struct vivi_dev *dev = video_drvdata(file);
Pawel Osciake007a322011-01-19 13:02:29 -02001024 struct vb2_queue *q = &dev->vb_vidq;
Mauro Carvalho Chehabe164b582009-01-11 10:29:43 -03001025
Hans Verkuil730947b2010-04-10 04:13:53 -03001026 int ret = vidioc_try_fmt_vid_cap(file, priv, f);
Mauro Carvalho Chehabe164b582009-01-11 10:29:43 -03001027 if (ret < 0)
1028 return ret;
1029
Hans Verkuilf2ba5a02012-06-22 05:53:02 -03001030 if (vb2_is_busy(q)) {
Hans Verkuil730947b2010-04-10 04:13:53 -03001031 dprintk(dev, 1, "%s device busy\n", __func__);
Pawel Osciake007a322011-01-19 13:02:29 -02001032 return -EBUSY;
Mauro Carvalho Chehabe164b582009-01-11 10:29:43 -03001033 }
1034
Hans Verkuil730947b2010-04-10 04:13:53 -03001035 dev->fmt = get_format(f);
Hans Verkuil3d51dca2012-05-02 03:15:11 -03001036 dev->pixelsize = dev->fmt->depth / 8;
Hans Verkuil730947b2010-04-10 04:13:53 -03001037 dev->width = f->fmt.pix.width;
1038 dev->height = f->fmt.pix.height;
Pawel Osciake007a322011-01-19 13:02:29 -02001039
1040 return 0;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001041}
1042
Hans Verkuil77747f72012-08-06 10:37:18 -03001043static int vidioc_enum_framesizes(struct file *file, void *fh,
1044 struct v4l2_frmsizeenum *fsize)
1045{
1046 static const struct v4l2_frmsize_stepwise sizes = {
1047 48, MAX_WIDTH, 4,
1048 32, MAX_HEIGHT, 1
1049 };
1050 int i;
1051
1052 if (fsize->index)
1053 return -EINVAL;
1054 for (i = 0; i < ARRAY_SIZE(formats); i++)
1055 if (formats[i].fourcc == fsize->pixel_format)
1056 break;
1057 if (i == ARRAY_SIZE(formats))
1058 return -EINVAL;
1059 fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
1060 fsize->stepwise = sizes;
1061 return 0;
1062}
1063
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001064/* only one input in this sample driver */
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001065static int vidioc_enum_input(struct file *file, void *priv,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001066 struct v4l2_input *inp)
1067{
Mauro Carvalho Chehabe164b582009-01-11 10:29:43 -03001068 if (inp->index >= NUM_INPUTS)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001069 return -EINVAL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001070
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001071 inp->type = V4L2_INPUT_TYPE_CAMERA;
Mauro Carvalho Chehabe164b582009-01-11 10:29:43 -03001072 sprintf(inp->name, "Camera %u", inp->index);
Hans Verkuil730947b2010-04-10 04:13:53 -03001073 return 0;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001074}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001075
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001076static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001077{
Hans Verkuil730947b2010-04-10 04:13:53 -03001078 struct vivi_dev *dev = video_drvdata(file);
Mauro Carvalho Chehabe164b582009-01-11 10:29:43 -03001079
1080 *i = dev->input;
Hans Verkuil730947b2010-04-10 04:13:53 -03001081 return 0;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001082}
Hans Verkuil730947b2010-04-10 04:13:53 -03001083
Mauro Carvalho Chehab543323b2007-12-10 09:33:52 -03001084static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001085{
Hans Verkuil730947b2010-04-10 04:13:53 -03001086 struct vivi_dev *dev = video_drvdata(file);
Mauro Carvalho Chehabe164b582009-01-11 10:29:43 -03001087
1088 if (i >= NUM_INPUTS)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001089 return -EINVAL;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001090
Hans Verkuilc7a52f82011-06-07 10:20:23 -03001091 if (i == dev->input)
1092 return 0;
1093
Mauro Carvalho Chehabe164b582009-01-11 10:29:43 -03001094 dev->input = i;
Hans Verkuilaf2d68d2013-03-12 03:56:55 -03001095 /*
1096 * Modify the brightness range depending on the input.
1097 * This makes it easy to use vivi to test if applications can
1098 * handle control range modifications and is also how this is
1099 * typically used in practice as different inputs may be hooked
1100 * up to different receivers with different control ranges.
1101 */
1102 v4l2_ctrl_modify_range(dev->brightness,
1103 128 * i, 255 + 128 * i, 1, 127 + 128 * i);
Hans Verkuil730947b2010-04-10 04:13:53 -03001104 precalculate_bars(dev);
1105 precalculate_line(dev);
1106 return 0;
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001107}
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001108
Jonathan McCrohan39c1cb22013-10-20 21:34:01 -03001109/* timeperframe is arbitrary and continuous */
Kirill Smelkovfe0e9902012-10-23 09:56:59 -03001110static int vidioc_enum_frameintervals(struct file *file, void *priv,
1111 struct v4l2_frmivalenum *fival)
1112{
Kirill Smelkovc19bec52012-12-26 12:23:26 -03001113 const struct vivi_fmt *fmt;
Kirill Smelkovfe0e9902012-10-23 09:56:59 -03001114
1115 if (fival->index)
1116 return -EINVAL;
1117
1118 fmt = __get_format(fival->pixel_format);
1119 if (!fmt)
1120 return -EINVAL;
1121
Hans Verkuilba38acb2014-02-25 07:15:54 -03001122 /* check for valid width/height */
1123 if (fival->width < 48 || fival->width > MAX_WIDTH || (fival->width & 3))
1124 return -EINVAL;
1125 if (fival->height < 32 || fival->height > MAX_HEIGHT)
1126 return -EINVAL;
Kirill Smelkovfe0e9902012-10-23 09:56:59 -03001127
1128 fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS;
1129
Jonathan McCrohan39c1cb22013-10-20 21:34:01 -03001130 /* fill in stepwise (step=1.0 is required by V4L2 spec) */
Kirill Smelkovfe0e9902012-10-23 09:56:59 -03001131 fival->stepwise.min = tpf_min;
1132 fival->stepwise.max = tpf_max;
1133 fival->stepwise.step = (struct v4l2_fract) {1, 1};
1134
1135 return 0;
1136}
1137
1138static int vidioc_g_parm(struct file *file, void *priv,
1139 struct v4l2_streamparm *parm)
1140{
1141 struct vivi_dev *dev = video_drvdata(file);
1142
1143 if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1144 return -EINVAL;
1145
1146 parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
1147 parm->parm.capture.timeperframe = dev->timeperframe;
1148 parm->parm.capture.readbuffers = 1;
1149 return 0;
1150}
1151
1152#define FRACT_CMP(a, OP, b) \
1153 ((u64)(a).numerator * (b).denominator OP (u64)(b).numerator * (a).denominator)
1154
1155static int vidioc_s_parm(struct file *file, void *priv,
1156 struct v4l2_streamparm *parm)
1157{
1158 struct vivi_dev *dev = video_drvdata(file);
1159 struct v4l2_fract tpf;
1160
1161 if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1162 return -EINVAL;
1163
1164 tpf = parm->parm.capture.timeperframe;
1165
1166 /* tpf: {*, 0} resets timing; clip to [min, max]*/
1167 tpf = tpf.denominator ? tpf : tpf_default;
1168 tpf = FRACT_CMP(tpf, <, tpf_min) ? tpf_min : tpf;
1169 tpf = FRACT_CMP(tpf, >, tpf_max) ? tpf_max : tpf;
1170
1171 dev->timeperframe = tpf;
1172 parm->parm.capture.timeperframe = tpf;
1173 parm->parm.capture.readbuffers = 1;
1174 return 0;
1175}
1176
Hans Verkuil730947b2010-04-10 04:13:53 -03001177/* --- controls ---------------------------------------------- */
Hans Verkuil7e996af2011-01-23 12:33:16 -02001178
Hans Verkuila1c894f2011-06-07 06:34:41 -03001179static int vivi_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
1180{
1181 struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler);
1182
1183 if (ctrl == dev->autogain)
1184 dev->gain->val = jiffies & 0xff;
1185 return 0;
1186}
1187
Hans Verkuil7e996af2011-01-23 12:33:16 -02001188static int vivi_s_ctrl(struct v4l2_ctrl *ctrl)
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001189{
Hans Verkuil7e996af2011-01-23 12:33:16 -02001190 struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler);
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001191
Hans Verkuil7088f4d2012-05-02 03:33:52 -03001192 switch (ctrl->id) {
1193 case V4L2_CID_ALPHA_COMPONENT:
1194 dev->alpha_component = ctrl->val;
1195 break;
1196 default:
1197 if (ctrl == dev->button)
1198 dev->button_pressed = 30;
1199 break;
1200 }
Hans Verkuil7e996af2011-01-23 12:33:16 -02001201 return 0;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001202}
1203
1204/* ------------------------------------------------------------------
1205 File operations for the device
1206 ------------------------------------------------------------------*/
1207
Hans Verkuil7e996af2011-01-23 12:33:16 -02001208static const struct v4l2_ctrl_ops vivi_ctrl_ops = {
Hans Verkuila1c894f2011-06-07 06:34:41 -03001209 .g_volatile_ctrl = vivi_g_volatile_ctrl,
Hans Verkuil7e996af2011-01-23 12:33:16 -02001210 .s_ctrl = vivi_s_ctrl,
1211};
1212
1213#define VIVI_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000)
1214
1215static const struct v4l2_ctrl_config vivi_ctrl_button = {
1216 .ops = &vivi_ctrl_ops,
1217 .id = VIVI_CID_CUSTOM_BASE + 0,
1218 .name = "Button",
1219 .type = V4L2_CTRL_TYPE_BUTTON,
1220};
1221
1222static const struct v4l2_ctrl_config vivi_ctrl_boolean = {
1223 .ops = &vivi_ctrl_ops,
1224 .id = VIVI_CID_CUSTOM_BASE + 1,
1225 .name = "Boolean",
1226 .type = V4L2_CTRL_TYPE_BOOLEAN,
1227 .min = 0,
1228 .max = 1,
1229 .step = 1,
1230 .def = 1,
1231};
1232
1233static const struct v4l2_ctrl_config vivi_ctrl_int32 = {
1234 .ops = &vivi_ctrl_ops,
1235 .id = VIVI_CID_CUSTOM_BASE + 2,
1236 .name = "Integer 32 Bits",
1237 .type = V4L2_CTRL_TYPE_INTEGER,
Hans Verkuil0ba2aeb2014-04-16 09:41:25 -03001238 .min = -0x80000000LL,
Hans Verkuil5b283022011-01-11 17:32:28 -03001239 .max = 0x7fffffff,
Hans Verkuil7e996af2011-01-23 12:33:16 -02001240 .step = 1,
1241};
1242
1243static const struct v4l2_ctrl_config vivi_ctrl_int64 = {
1244 .ops = &vivi_ctrl_ops,
1245 .id = VIVI_CID_CUSTOM_BASE + 3,
1246 .name = "Integer 64 Bits",
1247 .type = V4L2_CTRL_TYPE_INTEGER64,
Hans Verkuil0ba2aeb2014-04-16 09:41:25 -03001248 .min = LLONG_MIN,
1249 .max = LLONG_MAX,
1250 .step = 1,
Hans Verkuil7e996af2011-01-23 12:33:16 -02001251};
1252
1253static const char * const vivi_ctrl_menu_strings[] = {
1254 "Menu Item 0 (Skipped)",
1255 "Menu Item 1",
1256 "Menu Item 2 (Skipped)",
1257 "Menu Item 3",
1258 "Menu Item 4",
1259 "Menu Item 5 (Skipped)",
1260 NULL,
1261};
1262
1263static const struct v4l2_ctrl_config vivi_ctrl_menu = {
1264 .ops = &vivi_ctrl_ops,
1265 .id = VIVI_CID_CUSTOM_BASE + 4,
1266 .name = "Menu",
1267 .type = V4L2_CTRL_TYPE_MENU,
1268 .min = 1,
1269 .max = 4,
1270 .def = 3,
1271 .menu_skip_mask = 0x04,
1272 .qmenu = vivi_ctrl_menu_strings,
1273};
1274
1275static const struct v4l2_ctrl_config vivi_ctrl_string = {
1276 .ops = &vivi_ctrl_ops,
1277 .id = VIVI_CID_CUSTOM_BASE + 5,
1278 .name = "String",
1279 .type = V4L2_CTRL_TYPE_STRING,
1280 .min = 2,
1281 .max = 4,
1282 .step = 1,
1283};
1284
Hans Verkuilb6d17a52011-03-29 16:33:11 -03001285static const struct v4l2_ctrl_config vivi_ctrl_bitmask = {
1286 .ops = &vivi_ctrl_ops,
1287 .id = VIVI_CID_CUSTOM_BASE + 6,
1288 .name = "Bitmask",
1289 .type = V4L2_CTRL_TYPE_BITMASK,
1290 .def = 0x80002000,
1291 .min = 0,
1292 .max = 0x80402010,
1293 .step = 0,
1294};
1295
Sakari Ailusc5203312011-08-05 06:38:05 -03001296static const s64 vivi_ctrl_int_menu_values[] = {
1297 1, 1, 2, 3, 5, 8, 13, 21, 42,
1298};
1299
1300static const struct v4l2_ctrl_config vivi_ctrl_int_menu = {
1301 .ops = &vivi_ctrl_ops,
1302 .id = VIVI_CID_CUSTOM_BASE + 7,
1303 .name = "Integer menu",
1304 .type = V4L2_CTRL_TYPE_INTEGER_MENU,
1305 .min = 1,
1306 .max = 8,
1307 .def = 4,
1308 .menu_skip_mask = 0x02,
1309 .qmenu_int = vivi_ctrl_int_menu_values,
1310};
1311
Hans Verkuilbec43662008-12-30 06:58:20 -03001312static const struct v4l2_file_operations vivi_fops = {
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001313 .owner = THIS_MODULE,
Hans Verkuilc7a52f82011-06-07 10:20:23 -03001314 .open = v4l2_fh_open,
Hans Verkuilf2ba5a02012-06-22 05:53:02 -03001315 .release = vb2_fop_release,
1316 .read = vb2_fop_read,
1317 .poll = vb2_fop_poll,
Hans Verkuilfedc6c82010-09-20 18:25:55 -03001318 .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
Hans Verkuilf2ba5a02012-06-22 05:53:02 -03001319 .mmap = vb2_fop_mmap,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001320};
1321
Hans Verkuila3998102008-07-21 02:57:38 -03001322static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001323 .vidioc_querycap = vidioc_querycap,
Hans Verkuil78b526a2008-05-28 12:16:41 -03001324 .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
1325 .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
1326 .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
1327 .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
Hans Verkuil77747f72012-08-06 10:37:18 -03001328 .vidioc_enum_framesizes = vidioc_enum_framesizes,
Hans Verkuilf2ba5a02012-06-22 05:53:02 -03001329 .vidioc_reqbufs = vb2_ioctl_reqbufs,
Hans Verkuil2e90c6c2012-06-22 05:53:31 -03001330 .vidioc_create_bufs = vb2_ioctl_create_bufs,
1331 .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
Hans Verkuilf2ba5a02012-06-22 05:53:02 -03001332 .vidioc_querybuf = vb2_ioctl_querybuf,
1333 .vidioc_qbuf = vb2_ioctl_qbuf,
1334 .vidioc_dqbuf = vb2_ioctl_dqbuf,
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001335 .vidioc_enum_input = vidioc_enum_input,
1336 .vidioc_g_input = vidioc_g_input,
1337 .vidioc_s_input = vidioc_s_input,
Kirill Smelkovfe0e9902012-10-23 09:56:59 -03001338 .vidioc_enum_frameintervals = vidioc_enum_frameintervals,
1339 .vidioc_g_parm = vidioc_g_parm,
1340 .vidioc_s_parm = vidioc_s_parm,
Hans Verkuilf2ba5a02012-06-22 05:53:02 -03001341 .vidioc_streamon = vb2_ioctl_streamon,
1342 .vidioc_streamoff = vb2_ioctl_streamoff,
Hans Verkuile2ecb252012-02-02 08:20:53 -03001343 .vidioc_log_status = v4l2_ctrl_log_status,
Hans Verkuil6d6604f2012-01-27 16:21:10 -03001344 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
Hans Verkuilc7a52f82011-06-07 10:20:23 -03001345 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
Hans Verkuila3998102008-07-21 02:57:38 -03001346};
1347
Kirill Smelkovc19bec52012-12-26 12:23:26 -03001348static const struct video_device vivi_template = {
Hans Verkuila3998102008-07-21 02:57:38 -03001349 .name = "vivi",
Hans Verkuila3998102008-07-21 02:57:38 -03001350 .fops = &vivi_fops,
1351 .ioctl_ops = &vivi_ioctl_ops,
Hans Verkuil70bd97a2012-06-09 11:27:43 -03001352 .release = video_device_release_empty,
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001353};
Hans Verkuil5ab6c9a2009-02-14 13:23:12 -03001354
Mauro Carvalho Chehabc820cc42006-06-04 10:34:12 -03001355/* -----------------------------------------------------------------
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001356 Initialization and module stuff
1357 ------------------------------------------------------------------*/
1358
Hans Verkuil5ab6c9a2009-02-14 13:23:12 -03001359static int vivi_release(void)
1360{
1361 struct vivi_dev *dev;
1362 struct list_head *list;
1363
1364 while (!list_empty(&vivi_devlist)) {
1365 list = vivi_devlist.next;
1366 list_del(list);
1367 dev = list_entry(list, struct vivi_dev, vivi_devlist);
1368
Laurent Pinchart38c7c032009-11-27 13:57:15 -03001369 v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
Hans Verkuil70bd97a2012-06-09 11:27:43 -03001370 video_device_node_name(&dev->vdev));
1371 video_unregister_device(&dev->vdev);
Hans Verkuil5ab6c9a2009-02-14 13:23:12 -03001372 v4l2_device_unregister(&dev->v4l2_dev);
Hans Verkuil7e996af2011-01-23 12:33:16 -02001373 v4l2_ctrl_handler_free(&dev->ctrl_handler);
Hans Verkuil5ab6c9a2009-02-14 13:23:12 -03001374 kfree(dev);
1375 }
1376
1377 return 0;
1378}
1379
Hans Verkuilc41ee242009-02-14 13:43:44 -03001380static int __init vivi_create_instance(int inst)
Hans Verkuil5ab6c9a2009-02-14 13:23:12 -03001381{
1382 struct vivi_dev *dev;
1383 struct video_device *vfd;
Hans Verkuil7e996af2011-01-23 12:33:16 -02001384 struct v4l2_ctrl_handler *hdl;
Pawel Osciake007a322011-01-19 13:02:29 -02001385 struct vb2_queue *q;
Hans Verkuil730947b2010-04-10 04:13:53 -03001386 int ret;
Hans Verkuil5ab6c9a2009-02-14 13:23:12 -03001387
1388 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1389 if (!dev)
1390 return -ENOMEM;
1391
1392 snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
Hans Verkuilc41ee242009-02-14 13:43:44 -03001393 "%s-%03d", VIVI_MODULE_NAME, inst);
Hans Verkuil5ab6c9a2009-02-14 13:23:12 -03001394 ret = v4l2_device_register(NULL, &dev->v4l2_dev);
1395 if (ret)
1396 goto free_dev;
1397
Hans Verkuil730947b2010-04-10 04:13:53 -03001398 dev->fmt = &formats[0];
Kirill Smelkovfe0e9902012-10-23 09:56:59 -03001399 dev->timeperframe = tpf_default;
Hans Verkuil730947b2010-04-10 04:13:53 -03001400 dev->width = 640;
1401 dev->height = 480;
Hans Verkuil3d51dca2012-05-02 03:15:11 -03001402 dev->pixelsize = dev->fmt->depth / 8;
Hans Verkuil7e996af2011-01-23 12:33:16 -02001403 hdl = &dev->ctrl_handler;
1404 v4l2_ctrl_handler_init(hdl, 11);
1405 dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
1406 V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);
1407 dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
1408 V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
1409 dev->contrast = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
1410 V4L2_CID_CONTRAST, 0, 255, 1, 16);
1411 dev->saturation = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
1412 V4L2_CID_SATURATION, 0, 255, 1, 127);
1413 dev->hue = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
1414 V4L2_CID_HUE, -128, 127, 1, 0);
Hans Verkuila1c894f2011-06-07 06:34:41 -03001415 dev->autogain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
1416 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
1417 dev->gain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
1418 V4L2_CID_GAIN, 0, 255, 1, 100);
Hans Verkuil7088f4d2012-05-02 03:33:52 -03001419 dev->alpha = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
1420 V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 0);
Hans Verkuil7e996af2011-01-23 12:33:16 -02001421 dev->button = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_button, NULL);
1422 dev->int32 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int32, NULL);
1423 dev->int64 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int64, NULL);
1424 dev->boolean = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_boolean, NULL);
1425 dev->menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_menu, NULL);
1426 dev->string = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_string, NULL);
Hans Verkuilb6d17a52011-03-29 16:33:11 -03001427 dev->bitmask = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_bitmask, NULL);
Sakari Ailusc5203312011-08-05 06:38:05 -03001428 dev->int_menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int_menu, NULL);
Hans Verkuil7e996af2011-01-23 12:33:16 -02001429 if (hdl->error) {
1430 ret = hdl->error;
1431 goto unreg_dev;
1432 }
Hans Verkuila1c894f2011-06-07 06:34:41 -03001433 v4l2_ctrl_auto_cluster(2, &dev->autogain, 0, true);
Hans Verkuil7e996af2011-01-23 12:33:16 -02001434 dev->v4l2_dev.ctrl_handler = hdl;
Hans Verkuil730947b2010-04-10 04:13:53 -03001435
Hans Verkuilfedc6c82010-09-20 18:25:55 -03001436 /* initialize locks */
1437 spin_lock_init(&dev->slock);
Hans Verkuilfedc6c82010-09-20 18:25:55 -03001438
Pawel Osciake007a322011-01-19 13:02:29 -02001439 /* initialize queue */
1440 q = &dev->vb_vidq;
Pawel Osciake007a322011-01-19 13:02:29 -02001441 q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
Tomasz Stanislawskia626f0a2012-06-14 10:37:47 -03001442 q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
Pawel Osciake007a322011-01-19 13:02:29 -02001443 q->drv_priv = dev;
1444 q->buf_struct_size = sizeof(struct vivi_buffer);
1445 q->ops = &vivi_video_qops;
1446 q->mem_ops = &vb2_vmalloc_memops;
Sakari Ailusade48682014-02-25 19:12:19 -03001447 q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
Pawel Osciake007a322011-01-19 13:02:29 -02001448
Ezequiel Garcia4195ec72012-09-17 09:49:38 -03001449 ret = vb2_queue_init(q);
1450 if (ret)
1451 goto unreg_dev;
Pawel Osciake007a322011-01-19 13:02:29 -02001452
1453 mutex_init(&dev->mutex);
Hans Verkuil730947b2010-04-10 04:13:53 -03001454
Hans Verkuil5ab6c9a2009-02-14 13:23:12 -03001455 /* init video dma queues */
1456 INIT_LIST_HEAD(&dev->vidq.active);
1457 init_waitqueue_head(&dev->vidq.wq);
1458
Hans Verkuil70bd97a2012-06-09 11:27:43 -03001459 vfd = &dev->vdev;
Hans Verkuil5ab6c9a2009-02-14 13:23:12 -03001460 *vfd = vivi_template;
Mauro Carvalho Chehabc285add2009-06-25 16:28:23 -03001461 vfd->debug = debug;
Hans Verkuil730947b2010-04-10 04:13:53 -03001462 vfd->v4l2_dev = &dev->v4l2_dev;
Hans Verkuilf2ba5a02012-06-22 05:53:02 -03001463 vfd->queue = q;
Pawel Osciake007a322011-01-19 13:02:29 -02001464
1465 /*
1466 * Provide a mutex to v4l2 core. It will be used to protect
1467 * all fops and v4l2 ioctls.
1468 */
Hans Verkuilfedc6c82010-09-20 18:25:55 -03001469 vfd->lock = &dev->mutex;
Hans Verkuil70bd97a2012-06-09 11:27:43 -03001470 video_set_drvdata(vfd, dev);
Hans Verkuil5ab6c9a2009-02-14 13:23:12 -03001471
1472 ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
1473 if (ret < 0)
Hans Verkuil70bd97a2012-06-09 11:27:43 -03001474 goto unreg_dev;
Hans Verkuil5ab6c9a2009-02-14 13:23:12 -03001475
1476 /* Now that everything is fine, let's add it to device list */
1477 list_add_tail(&dev->vivi_devlist, &vivi_devlist);
1478
Laurent Pinchart38c7c032009-11-27 13:57:15 -03001479 v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n",
1480 video_device_node_name(vfd));
Hans Verkuil5ab6c9a2009-02-14 13:23:12 -03001481 return 0;
1482
Hans Verkuil5ab6c9a2009-02-14 13:23:12 -03001483unreg_dev:
Hans Verkuil7e996af2011-01-23 12:33:16 -02001484 v4l2_ctrl_handler_free(hdl);
Hans Verkuil5ab6c9a2009-02-14 13:23:12 -03001485 v4l2_device_unregister(&dev->v4l2_dev);
1486free_dev:
1487 kfree(dev);
1488 return ret;
1489}
1490
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001491/* This routine allocates from 1 to n_devs virtual drivers.
1492
1493 The real maximum number of virtual drivers will depend on how many drivers
1494 will succeed. This is limited to the maximum number of devices that
Hans Verkuil62cfdac2009-02-14 11:37:17 -03001495 videodev supports, which is equal to VIDEO_NUM_DEVICES.
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001496 */
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001497static int __init vivi_init(void)
1498{
Hans Verkuil730947b2010-04-10 04:13:53 -03001499 const struct font_desc *font = find_font("VGA8x16");
Hans Verkuil9185cbf2009-03-06 09:58:12 -03001500 int ret = 0, i;
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001501
Hans Verkuil730947b2010-04-10 04:13:53 -03001502 if (font == NULL) {
1503 printk(KERN_ERR "vivi: could not find font\n");
1504 return -ENODEV;
1505 }
1506 font8x16 = font->data;
1507
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001508 if (n_devs <= 0)
1509 n_devs = 1;
1510
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001511 for (i = 0; i < n_devs; i++) {
Hans Verkuil5ab6c9a2009-02-14 13:23:12 -03001512 ret = vivi_create_instance(i);
1513 if (ret) {
1514 /* If some instantiations succeeded, keep driver */
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001515 if (i)
1516 ret = 0;
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001517 break;
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001518 }
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001519 }
1520
1521 if (ret < 0) {
Hans Verkuil730947b2010-04-10 04:13:53 -03001522 printk(KERN_ERR "vivi: error %d while loading driver\n", ret);
Hans Verkuil5ab6c9a2009-02-14 13:23:12 -03001523 return ret;
1524 }
1525
1526 printk(KERN_INFO "Video Technology Magazine Virtual Video "
Mauro Carvalho Chehab1990d502011-06-24 14:45:49 -03001527 "Capture Board ver %s successfully loaded.\n",
1528 VIVI_VERSION);
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001529
Hans Verkuil5ab6c9a2009-02-14 13:23:12 -03001530 /* n_devs will reflect the actual number of allocated devices */
1531 n_devs = i;
Mauro Carvalho Chehab980d4f12008-09-03 17:11:53 -03001532
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001533 return ret;
1534}
1535
1536static void __exit vivi_exit(void)
1537{
Mauro Carvalho Chehab55712ff2007-12-10 04:38:11 -03001538 vivi_release();
Mauro Carvalho Chehab1e6dd652006-03-10 12:40:10 -03001539}
1540
1541module_init(vivi_init);
1542module_exit(vivi_exit);