| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 1 | /* | 
 | 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 Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 10 |  *      Conversion to videobuf2 by Pawel Osciak & Marek Szyprowski | 
 | 11 |  *      Copyright (c) 2010 Samsung Electronics | 
 | 12 |  * | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 13 |  * 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 Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 19 | #include <linux/errno.h> | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 20 | #include <linux/kernel.h> | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 21 | #include <linux/init.h> | 
 | 22 | #include <linux/sched.h> | 
| Randy Dunlap | 6b46c39 | 2010-05-07 15:22:26 -0300 | [diff] [blame] | 23 | #include <linux/slab.h> | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 24 | #include <linux/font.h> | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 25 | #include <linux/version.h> | 
| Matthias Kaehlcke | 51b5402 | 2007-07-02 10:19:38 -0300 | [diff] [blame] | 26 | #include <linux/mutex.h> | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 27 | #include <linux/videodev2.h> | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 28 | #include <linux/kthread.h> | 
| Nigel Cunningham | 7dfb710 | 2006-12-06 20:34:23 -0800 | [diff] [blame] | 29 | #include <linux/freezer.h> | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 30 | #include <media/videobuf2-vmalloc.h> | 
| Hans Verkuil | 5ab6c9a | 2009-02-14 13:23:12 -0300 | [diff] [blame] | 31 | #include <media/v4l2-device.h> | 
 | 32 | #include <media/v4l2-ioctl.h> | 
| Hans Verkuil | 7e996af | 2011-01-23 12:33:16 -0200 | [diff] [blame] | 33 | #include <media/v4l2-ctrls.h> | 
| Hans Verkuil | 2e4784d | 2011-03-11 20:01:54 -0300 | [diff] [blame] | 34 | #include <media/v4l2-fh.h> | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 35 | #include <media/v4l2-common.h> | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 36 |  | 
| Mauro Carvalho Chehab | 584ce48 | 2008-06-10 15:21:49 -0300 | [diff] [blame] | 37 | #define VIVI_MODULE_NAME "vivi" | 
| Carl Karsten | 745271a | 2008-06-10 00:02:32 -0300 | [diff] [blame] | 38 |  | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 39 | /* Wake up at about 30 fps */ | 
 | 40 | #define WAKE_NUMERATOR 30 | 
 | 41 | #define WAKE_DENOMINATOR 1001 | 
 | 42 | #define BUFFER_TIMEOUT     msecs_to_jiffies(500)  /* 0.5 seconds */ | 
 | 43 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 44 | #define MAX_WIDTH 1920 | 
 | 45 | #define MAX_HEIGHT 1200 | 
 | 46 |  | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 47 | #define VIVI_MAJOR_VERSION 0 | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 48 | #define VIVI_MINOR_VERSION 8 | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 49 | #define VIVI_RELEASE 0 | 
| Mauro Carvalho Chehab | 543323b | 2007-12-10 09:33:52 -0300 | [diff] [blame] | 50 | #define VIVI_VERSION \ | 
 | 51 | 	KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE) | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 52 |  | 
| Hans Verkuil | 5ab6c9a | 2009-02-14 13:23:12 -0300 | [diff] [blame] | 53 | MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board"); | 
 | 54 | MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol"); | 
 | 55 | MODULE_LICENSE("Dual BSD/GPL"); | 
 | 56 |  | 
 | 57 | static unsigned video_nr = -1; | 
 | 58 | module_param(video_nr, uint, 0644); | 
 | 59 | MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect"); | 
 | 60 |  | 
 | 61 | static unsigned n_devs = 1; | 
 | 62 | module_param(n_devs, uint, 0644); | 
 | 63 | MODULE_PARM_DESC(n_devs, "number of video devices to create"); | 
 | 64 |  | 
 | 65 | static unsigned debug; | 
 | 66 | module_param(debug, uint, 0644); | 
 | 67 | MODULE_PARM_DESC(debug, "activates debug info"); | 
 | 68 |  | 
 | 69 | static unsigned int vid_limit = 16; | 
 | 70 | module_param(vid_limit, uint, 0644); | 
 | 71 | MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); | 
 | 72 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 73 | /* Global font descriptor */ | 
 | 74 | static const u8 *font8x16; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 75 |  | 
| Hans Verkuil | 5ab6c9a | 2009-02-14 13:23:12 -0300 | [diff] [blame] | 76 | #define dprintk(dev, level, fmt, arg...) \ | 
 | 77 | 	v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg) | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 78 |  | 
 | 79 | /* ------------------------------------------------------------------ | 
 | 80 | 	Basic structures | 
 | 81 |    ------------------------------------------------------------------*/ | 
 | 82 |  | 
 | 83 | struct vivi_fmt { | 
 | 84 | 	char  *name; | 
 | 85 | 	u32   fourcc;          /* v4l2 format id */ | 
 | 86 | 	int   depth; | 
 | 87 | }; | 
 | 88 |  | 
| Magnus Damm | d891f47 | 2008-10-14 12:47:09 -0300 | [diff] [blame] | 89 | static struct vivi_fmt formats[] = { | 
 | 90 | 	{ | 
 | 91 | 		.name     = "4:2:2, packed, YUYV", | 
 | 92 | 		.fourcc   = V4L2_PIX_FMT_YUYV, | 
 | 93 | 		.depth    = 16, | 
 | 94 | 	}, | 
| Magnus Damm | fca36ba | 2008-10-14 12:47:25 -0300 | [diff] [blame] | 95 | 	{ | 
 | 96 | 		.name     = "4:2:2, packed, UYVY", | 
 | 97 | 		.fourcc   = V4L2_PIX_FMT_UYVY, | 
 | 98 | 		.depth    = 16, | 
 | 99 | 	}, | 
| Magnus Damm | aeadb5d | 2008-10-14 12:47:35 -0300 | [diff] [blame] | 100 | 	{ | 
 | 101 | 		.name     = "RGB565 (LE)", | 
 | 102 | 		.fourcc   = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ | 
 | 103 | 		.depth    = 16, | 
 | 104 | 	}, | 
 | 105 | 	{ | 
 | 106 | 		.name     = "RGB565 (BE)", | 
 | 107 | 		.fourcc   = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ | 
 | 108 | 		.depth    = 16, | 
 | 109 | 	}, | 
| Magnus Damm | def5239 | 2008-10-14 12:47:43 -0300 | [diff] [blame] | 110 | 	{ | 
 | 111 | 		.name     = "RGB555 (LE)", | 
 | 112 | 		.fourcc   = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */ | 
 | 113 | 		.depth    = 16, | 
 | 114 | 	}, | 
 | 115 | 	{ | 
 | 116 | 		.name     = "RGB555 (BE)", | 
 | 117 | 		.fourcc   = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */ | 
 | 118 | 		.depth    = 16, | 
 | 119 | 	}, | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 120 | }; | 
 | 121 |  | 
| Magnus Damm | d891f47 | 2008-10-14 12:47:09 -0300 | [diff] [blame] | 122 | static struct vivi_fmt *get_format(struct v4l2_format *f) | 
 | 123 | { | 
 | 124 | 	struct vivi_fmt *fmt; | 
 | 125 | 	unsigned int k; | 
 | 126 |  | 
 | 127 | 	for (k = 0; k < ARRAY_SIZE(formats); k++) { | 
 | 128 | 		fmt = &formats[k]; | 
 | 129 | 		if (fmt->fourcc == f->fmt.pix.pixelformat) | 
 | 130 | 			break; | 
 | 131 | 	} | 
 | 132 |  | 
 | 133 | 	if (k == ARRAY_SIZE(formats)) | 
 | 134 | 		return NULL; | 
 | 135 |  | 
 | 136 | 	return &formats[k]; | 
 | 137 | } | 
 | 138 |  | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 139 | /* buffer for one video frame */ | 
 | 140 | struct vivi_buffer { | 
 | 141 | 	/* common v4l buffer stuff -- must be first */ | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 142 | 	struct vb2_buffer	vb; | 
 | 143 | 	struct list_head	list; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 144 | 	struct vivi_fmt        *fmt; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 145 | }; | 
 | 146 |  | 
 | 147 | struct vivi_dmaqueue { | 
 | 148 | 	struct list_head       active; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 149 |  | 
 | 150 | 	/* thread for generating video stream*/ | 
 | 151 | 	struct task_struct         *kthread; | 
 | 152 | 	wait_queue_head_t          wq; | 
 | 153 | 	/* Counters to control fps rate */ | 
 | 154 | 	int                        frame; | 
 | 155 | 	int                        ini_jiffies; | 
 | 156 | }; | 
 | 157 |  | 
 | 158 | static LIST_HEAD(vivi_devlist); | 
 | 159 |  | 
 | 160 | struct vivi_dev { | 
 | 161 | 	struct list_head           vivi_devlist; | 
| Hans Verkuil | 5ab6c9a | 2009-02-14 13:23:12 -0300 | [diff] [blame] | 162 | 	struct v4l2_device 	   v4l2_dev; | 
| Hans Verkuil | 7e996af | 2011-01-23 12:33:16 -0200 | [diff] [blame] | 163 | 	struct v4l2_ctrl_handler   ctrl_handler; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 164 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 165 | 	/* controls */ | 
| Hans Verkuil | 7e996af | 2011-01-23 12:33:16 -0200 | [diff] [blame] | 166 | 	struct v4l2_ctrl	   *brightness; | 
 | 167 | 	struct v4l2_ctrl	   *contrast; | 
 | 168 | 	struct v4l2_ctrl	   *saturation; | 
 | 169 | 	struct v4l2_ctrl	   *hue; | 
 | 170 | 	struct v4l2_ctrl	   *volume; | 
 | 171 | 	struct v4l2_ctrl	   *button; | 
 | 172 | 	struct v4l2_ctrl	   *boolean; | 
 | 173 | 	struct v4l2_ctrl	   *int32; | 
 | 174 | 	struct v4l2_ctrl	   *int64; | 
 | 175 | 	struct v4l2_ctrl	   *menu; | 
 | 176 | 	struct v4l2_ctrl	   *string; | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 177 |  | 
| Mauro Carvalho Chehab | 55862ac | 2007-12-13 16:13:37 -0300 | [diff] [blame] | 178 | 	spinlock_t                 slock; | 
| Brandon Philips | aa9dbac | 2008-04-02 18:10:59 -0300 | [diff] [blame] | 179 | 	struct mutex		   mutex; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 180 |  | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 181 | 	/* various device info */ | 
| Mauro Carvalho Chehab | f905c44 | 2007-12-10 04:07:03 -0300 | [diff] [blame] | 182 | 	struct video_device        *vfd; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 183 |  | 
 | 184 | 	struct vivi_dmaqueue       vidq; | 
 | 185 |  | 
 | 186 | 	/* Several counters */ | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 187 | 	unsigned 		   ms; | 
| Mauro Carvalho Chehab | dfd8c04 | 2008-01-13 19:36:11 -0300 | [diff] [blame] | 188 | 	unsigned long              jiffies; | 
| Hans Verkuil | 7e996af | 2011-01-23 12:33:16 -0200 | [diff] [blame] | 189 | 	unsigned		   button_pressed; | 
| Mauro Carvalho Chehab | 025341d | 2007-12-10 04:43:38 -0300 | [diff] [blame] | 190 |  | 
 | 191 | 	int			   mv_count;	/* Controls bars movement */ | 
| Mauro Carvalho Chehab | e164b58 | 2009-01-11 10:29:43 -0300 | [diff] [blame] | 192 |  | 
 | 193 | 	/* Input Number */ | 
 | 194 | 	int			   input; | 
| Hans Verkuil | c41ee24 | 2009-02-14 13:43:44 -0300 | [diff] [blame] | 195 |  | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 196 | 	/* video capture */ | 
 | 197 | 	struct vivi_fmt            *fmt; | 
| Mauro Carvalho Chehab | 543323b | 2007-12-10 09:33:52 -0300 | [diff] [blame] | 198 | 	unsigned int               width, height; | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 199 | 	struct vb2_queue	   vb_vidq; | 
 | 200 | 	enum v4l2_field		   field; | 
 | 201 | 	unsigned int		   field_count; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 202 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 203 | 	u8 			   bars[9][3]; | 
 | 204 | 	u8 			   line[MAX_WIDTH * 4]; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 205 | }; | 
 | 206 |  | 
 | 207 | /* ------------------------------------------------------------------ | 
 | 208 | 	DMA and thread functions | 
 | 209 |    ------------------------------------------------------------------*/ | 
 | 210 |  | 
 | 211 | /* Bars and Colors should match positions */ | 
 | 212 |  | 
 | 213 | enum colors { | 
 | 214 | 	WHITE, | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 215 | 	AMBER, | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 216 | 	CYAN, | 
 | 217 | 	GREEN, | 
 | 218 | 	MAGENTA, | 
 | 219 | 	RED, | 
| Mauro Carvalho Chehab | 543323b | 2007-12-10 09:33:52 -0300 | [diff] [blame] | 220 | 	BLUE, | 
 | 221 | 	BLACK, | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 222 | 	TEXT_BLACK, | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 223 | }; | 
 | 224 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 225 | /* R   G   B */ | 
| Mauro Carvalho Chehab | e164b58 | 2009-01-11 10:29:43 -0300 | [diff] [blame] | 226 | #define COLOR_WHITE	{204, 204, 204} | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 227 | #define COLOR_AMBER	{208, 208,   0} | 
 | 228 | #define COLOR_CYAN	{  0, 206, 206} | 
| Mauro Carvalho Chehab | e164b58 | 2009-01-11 10:29:43 -0300 | [diff] [blame] | 229 | #define	COLOR_GREEN	{  0, 239,   0} | 
 | 230 | #define COLOR_MAGENTA	{239,   0, 239} | 
 | 231 | #define COLOR_RED	{205,   0,   0} | 
 | 232 | #define COLOR_BLUE	{  0,   0, 255} | 
 | 233 | #define COLOR_BLACK	{  0,   0,   0} | 
 | 234 |  | 
 | 235 | struct bar_std { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 236 | 	u8 bar[9][3]; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 237 | }; | 
 | 238 |  | 
| Mauro Carvalho Chehab | e164b58 | 2009-01-11 10:29:43 -0300 | [diff] [blame] | 239 | /* Maximum number of bars are 10 - otherwise, the input print code | 
 | 240 |    should be modified */ | 
 | 241 | static struct bar_std bars[] = { | 
 | 242 | 	{	/* Standard ITU-R color bar sequence */ | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 243 | 		{ COLOR_WHITE, COLOR_AMBER, COLOR_CYAN, COLOR_GREEN, | 
 | 244 | 		  COLOR_MAGENTA, COLOR_RED, COLOR_BLUE, COLOR_BLACK, COLOR_BLACK } | 
| Mauro Carvalho Chehab | e164b58 | 2009-01-11 10:29:43 -0300 | [diff] [blame] | 245 | 	}, { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 246 | 		{ COLOR_WHITE, COLOR_AMBER, COLOR_BLACK, COLOR_WHITE, | 
 | 247 | 		  COLOR_AMBER, COLOR_BLACK, COLOR_WHITE, COLOR_AMBER, COLOR_BLACK } | 
| Mauro Carvalho Chehab | e164b58 | 2009-01-11 10:29:43 -0300 | [diff] [blame] | 248 | 	}, { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 249 | 		{ COLOR_WHITE, COLOR_CYAN, COLOR_BLACK, COLOR_WHITE, | 
 | 250 | 		  COLOR_CYAN, COLOR_BLACK, COLOR_WHITE, COLOR_CYAN, COLOR_BLACK } | 
| Mauro Carvalho Chehab | e164b58 | 2009-01-11 10:29:43 -0300 | [diff] [blame] | 251 | 	}, { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 252 | 		{ COLOR_WHITE, COLOR_GREEN, COLOR_BLACK, COLOR_WHITE, | 
 | 253 | 		  COLOR_GREEN, COLOR_BLACK, COLOR_WHITE, COLOR_GREEN, COLOR_BLACK } | 
| Mauro Carvalho Chehab | e164b58 | 2009-01-11 10:29:43 -0300 | [diff] [blame] | 254 | 	}, | 
 | 255 | }; | 
 | 256 |  | 
 | 257 | #define NUM_INPUTS ARRAY_SIZE(bars) | 
 | 258 |  | 
| Mauro Carvalho Chehab | 543323b | 2007-12-10 09:33:52 -0300 | [diff] [blame] | 259 | #define TO_Y(r, g, b) \ | 
 | 260 | 	(((16829 * r + 33039 * g + 6416 * b  + 32768) >> 16) + 16) | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 261 | /* RGB to  V(Cr) Color transform */ | 
| Mauro Carvalho Chehab | 543323b | 2007-12-10 09:33:52 -0300 | [diff] [blame] | 262 | #define TO_V(r, g, b) \ | 
 | 263 | 	(((28784 * r - 24103 * g - 4681 * b  + 32768) >> 16) + 128) | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 264 | /* RGB to  U(Cb) Color transform */ | 
| Mauro Carvalho Chehab | 543323b | 2007-12-10 09:33:52 -0300 | [diff] [blame] | 265 | #define TO_U(r, g, b) \ | 
 | 266 | 	(((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128) | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 267 |  | 
| Mauro Carvalho Chehab | c285add | 2009-06-25 16:28:23 -0300 | [diff] [blame] | 268 | /* precalculate color bar values to speed up rendering */ | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 269 | static void precalculate_bars(struct vivi_dev *dev) | 
| Mauro Carvalho Chehab | c285add | 2009-06-25 16:28:23 -0300 | [diff] [blame] | 270 | { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 271 | 	u8 r, g, b; | 
| Mauro Carvalho Chehab | c285add | 2009-06-25 16:28:23 -0300 | [diff] [blame] | 272 | 	int k, is_yuv; | 
 | 273 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 274 | 	for (k = 0; k < 9; k++) { | 
 | 275 | 		r = bars[dev->input].bar[k][0]; | 
 | 276 | 		g = bars[dev->input].bar[k][1]; | 
 | 277 | 		b = bars[dev->input].bar[k][2]; | 
| Mauro Carvalho Chehab | c285add | 2009-06-25 16:28:23 -0300 | [diff] [blame] | 278 | 		is_yuv = 0; | 
 | 279 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 280 | 		switch (dev->fmt->fourcc) { | 
| Mauro Carvalho Chehab | c285add | 2009-06-25 16:28:23 -0300 | [diff] [blame] | 281 | 		case V4L2_PIX_FMT_YUYV: | 
 | 282 | 		case V4L2_PIX_FMT_UYVY: | 
 | 283 | 			is_yuv = 1; | 
 | 284 | 			break; | 
 | 285 | 		case V4L2_PIX_FMT_RGB565: | 
 | 286 | 		case V4L2_PIX_FMT_RGB565X: | 
 | 287 | 			r >>= 3; | 
 | 288 | 			g >>= 2; | 
 | 289 | 			b >>= 3; | 
 | 290 | 			break; | 
 | 291 | 		case V4L2_PIX_FMT_RGB555: | 
 | 292 | 		case V4L2_PIX_FMT_RGB555X: | 
 | 293 | 			r >>= 3; | 
 | 294 | 			g >>= 3; | 
 | 295 | 			b >>= 3; | 
 | 296 | 			break; | 
 | 297 | 		} | 
 | 298 |  | 
 | 299 | 		if (is_yuv) { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 300 | 			dev->bars[k][0] = TO_Y(r, g, b);	/* Luma */ | 
 | 301 | 			dev->bars[k][1] = TO_U(r, g, b);	/* Cb */ | 
 | 302 | 			dev->bars[k][2] = TO_V(r, g, b);	/* Cr */ | 
| Mauro Carvalho Chehab | c285add | 2009-06-25 16:28:23 -0300 | [diff] [blame] | 303 | 		} else { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 304 | 			dev->bars[k][0] = r; | 
 | 305 | 			dev->bars[k][1] = g; | 
 | 306 | 			dev->bars[k][2] = b; | 
| Mauro Carvalho Chehab | c285add | 2009-06-25 16:28:23 -0300 | [diff] [blame] | 307 | 		} | 
 | 308 | 	} | 
| Mauro Carvalho Chehab | c285add | 2009-06-25 16:28:23 -0300 | [diff] [blame] | 309 | } | 
 | 310 |  | 
| Mauro Carvalho Chehab | e164b58 | 2009-01-11 10:29:43 -0300 | [diff] [blame] | 311 | #define TSTAMP_MIN_Y	24 | 
 | 312 | #define TSTAMP_MAX_Y	(TSTAMP_MIN_Y + 15) | 
 | 313 | #define TSTAMP_INPUT_X	10 | 
 | 314 | #define TSTAMP_MIN_X	(54 + TSTAMP_INPUT_X) | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 315 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 316 | static void gen_twopix(struct vivi_dev *dev, u8 *buf, int colorpos) | 
| Magnus Damm | 74d7c5a | 2008-10-14 12:46:59 -0300 | [diff] [blame] | 317 | { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 318 | 	u8 r_y, g_u, b_v; | 
| Magnus Damm | 74d7c5a | 2008-10-14 12:46:59 -0300 | [diff] [blame] | 319 | 	int color; | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 320 | 	u8 *p; | 
| Magnus Damm | 74d7c5a | 2008-10-14 12:46:59 -0300 | [diff] [blame] | 321 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 322 | 	r_y = dev->bars[colorpos][0]; /* R or precalculated Y */ | 
 | 323 | 	g_u = dev->bars[colorpos][1]; /* G or precalculated U */ | 
 | 324 | 	b_v = dev->bars[colorpos][2]; /* B or precalculated V */ | 
| Magnus Damm | 74d7c5a | 2008-10-14 12:46:59 -0300 | [diff] [blame] | 325 |  | 
 | 326 | 	for (color = 0; color < 4; color++) { | 
 | 327 | 		p = buf + color; | 
 | 328 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 329 | 		switch (dev->fmt->fourcc) { | 
| Magnus Damm | d891f47 | 2008-10-14 12:47:09 -0300 | [diff] [blame] | 330 | 		case V4L2_PIX_FMT_YUYV: | 
 | 331 | 			switch (color) { | 
 | 332 | 			case 0: | 
 | 333 | 			case 2: | 
 | 334 | 				*p = r_y; | 
 | 335 | 				break; | 
 | 336 | 			case 1: | 
 | 337 | 				*p = g_u; | 
 | 338 | 				break; | 
 | 339 | 			case 3: | 
 | 340 | 				*p = b_v; | 
 | 341 | 				break; | 
 | 342 | 			} | 
| Magnus Damm | 74d7c5a | 2008-10-14 12:46:59 -0300 | [diff] [blame] | 343 | 			break; | 
| Magnus Damm | fca36ba | 2008-10-14 12:47:25 -0300 | [diff] [blame] | 344 | 		case V4L2_PIX_FMT_UYVY: | 
 | 345 | 			switch (color) { | 
 | 346 | 			case 1: | 
 | 347 | 			case 3: | 
 | 348 | 				*p = r_y; | 
 | 349 | 				break; | 
 | 350 | 			case 0: | 
 | 351 | 				*p = g_u; | 
 | 352 | 				break; | 
 | 353 | 			case 2: | 
 | 354 | 				*p = b_v; | 
 | 355 | 				break; | 
 | 356 | 			} | 
 | 357 | 			break; | 
| Magnus Damm | aeadb5d | 2008-10-14 12:47:35 -0300 | [diff] [blame] | 358 | 		case V4L2_PIX_FMT_RGB565: | 
 | 359 | 			switch (color) { | 
 | 360 | 			case 0: | 
 | 361 | 			case 2: | 
 | 362 | 				*p = (g_u << 5) | b_v; | 
 | 363 | 				break; | 
 | 364 | 			case 1: | 
 | 365 | 			case 3: | 
 | 366 | 				*p = (r_y << 3) | (g_u >> 3); | 
 | 367 | 				break; | 
 | 368 | 			} | 
 | 369 | 			break; | 
 | 370 | 		case V4L2_PIX_FMT_RGB565X: | 
 | 371 | 			switch (color) { | 
 | 372 | 			case 0: | 
 | 373 | 			case 2: | 
 | 374 | 				*p = (r_y << 3) | (g_u >> 3); | 
 | 375 | 				break; | 
 | 376 | 			case 1: | 
 | 377 | 			case 3: | 
 | 378 | 				*p = (g_u << 5) | b_v; | 
 | 379 | 				break; | 
 | 380 | 			} | 
 | 381 | 			break; | 
| Magnus Damm | def5239 | 2008-10-14 12:47:43 -0300 | [diff] [blame] | 382 | 		case V4L2_PIX_FMT_RGB555: | 
 | 383 | 			switch (color) { | 
 | 384 | 			case 0: | 
 | 385 | 			case 2: | 
 | 386 | 				*p = (g_u << 5) | b_v; | 
 | 387 | 				break; | 
 | 388 | 			case 1: | 
 | 389 | 			case 3: | 
 | 390 | 				*p = (r_y << 2) | (g_u >> 3); | 
 | 391 | 				break; | 
 | 392 | 			} | 
 | 393 | 			break; | 
 | 394 | 		case V4L2_PIX_FMT_RGB555X: | 
 | 395 | 			switch (color) { | 
 | 396 | 			case 0: | 
 | 397 | 			case 2: | 
 | 398 | 				*p = (r_y << 2) | (g_u >> 3); | 
 | 399 | 				break; | 
 | 400 | 			case 1: | 
 | 401 | 			case 3: | 
 | 402 | 				*p = (g_u << 5) | b_v; | 
 | 403 | 				break; | 
 | 404 | 			} | 
 | 405 | 			break; | 
| Magnus Damm | 74d7c5a | 2008-10-14 12:46:59 -0300 | [diff] [blame] | 406 | 		} | 
 | 407 | 	} | 
 | 408 | } | 
 | 409 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 410 | static void precalculate_line(struct vivi_dev *dev) | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 411 | { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 412 | 	int w; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 413 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 414 | 	for (w = 0; w < dev->width * 2; w += 2) { | 
 | 415 | 		int colorpos = (w / (dev->width / 8) % 8); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 416 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 417 | 		gen_twopix(dev, dev->line + w * 2, colorpos); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 418 | 	} | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 419 | } | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 420 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 421 | static void gen_text(struct vivi_dev *dev, char *basep, | 
 | 422 | 					int y, int x, char *text) | 
 | 423 | { | 
 | 424 | 	int line; | 
| Mauro Carvalho Chehab | e164b58 | 2009-01-11 10:29:43 -0300 | [diff] [blame] | 425 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 426 | 	/* Checks if it is possible to show string */ | 
 | 427 | 	if (y + 16 >= dev->height || x + strlen(text) * 8 >= dev->width) | 
 | 428 | 		return; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 429 |  | 
 | 430 | 	/* Print stream time */ | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 431 | 	for (line = y; line < y + 16; line++) { | 
 | 432 | 		int j = 0; | 
 | 433 | 		char *pos = basep + line * dev->width * 2 + x * 2; | 
 | 434 | 		char *s; | 
 | 435 |  | 
 | 436 | 		for (s = text; *s; s++) { | 
 | 437 | 			u8 chr = font8x16[*s * 16 + line - y]; | 
 | 438 | 			int i; | 
 | 439 |  | 
 | 440 | 			for (i = 0; i < 7; i++, j++) { | 
| Magnus Damm | 74d7c5a | 2008-10-14 12:46:59 -0300 | [diff] [blame] | 441 | 				/* Draw white font on black background */ | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 442 | 				if (chr & (1 << (7 - i))) | 
 | 443 | 					gen_twopix(dev, pos + j * 2, WHITE); | 
| Magnus Damm | 74d7c5a | 2008-10-14 12:46:59 -0300 | [diff] [blame] | 444 | 				else | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 445 | 					gen_twopix(dev, pos + j * 2, TEXT_BLACK); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 446 | 			} | 
 | 447 | 		} | 
 | 448 | 	} | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 449 | } | 
| Brandon Philips | 78718e5 | 2008-04-02 18:10:59 -0300 | [diff] [blame] | 450 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 451 | static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf) | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 452 | { | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 453 | 	int wmax = dev->width; | 
 | 454 | 	int hmax = dev->height; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 455 | 	struct timeval ts; | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 456 | 	void *vbuf = vb2_plane_vaddr(&buf->vb, 0); | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 457 | 	unsigned ms; | 
 | 458 | 	char str[100]; | 
 | 459 | 	int h, line = 1; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 460 |  | 
| Marcin Slusarz | 5c554e6 | 2008-06-22 09:11:40 -0300 | [diff] [blame] | 461 | 	if (!vbuf) | 
| Mauro Carvalho Chehab | 5a03770 | 2007-08-02 23:31:54 -0300 | [diff] [blame] | 462 | 		return; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 463 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 464 | 	for (h = 0; h < hmax; h++) | 
 | 465 | 		memcpy(vbuf + h * wmax * 2, dev->line + (dev->mv_count % wmax) * 2, wmax * 2); | 
| Mauro Carvalho Chehab | 5a03770 | 2007-08-02 23:31:54 -0300 | [diff] [blame] | 466 |  | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 467 | 	/* Updates stream time */ | 
 | 468 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 469 | 	dev->ms += jiffies_to_msecs(jiffies - dev->jiffies); | 
| Mauro Carvalho Chehab | 543323b | 2007-12-10 09:33:52 -0300 | [diff] [blame] | 470 | 	dev->jiffies = jiffies; | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 471 | 	ms = dev->ms; | 
 | 472 | 	snprintf(str, sizeof(str), " %02d:%02d:%02d:%03d ", | 
 | 473 | 			(ms / (60 * 60 * 1000)) % 24, | 
 | 474 | 			(ms / (60 * 1000)) % 60, | 
 | 475 | 			(ms / 1000) % 60, | 
 | 476 | 			ms % 1000); | 
 | 477 | 	gen_text(dev, vbuf, line++ * 16, 16, str); | 
 | 478 | 	snprintf(str, sizeof(str), " %dx%d, input %d ", | 
 | 479 | 			dev->width, dev->height, dev->input); | 
 | 480 | 	gen_text(dev, vbuf, line++ * 16, 16, str); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 481 |  | 
| Hans Verkuil | 7e996af | 2011-01-23 12:33:16 -0200 | [diff] [blame] | 482 | 	mutex_lock(&dev->ctrl_handler.lock); | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 483 | 	snprintf(str, sizeof(str), " brightness %3d, contrast %3d, saturation %3d, hue %d ", | 
| Hans Verkuil | 7e996af | 2011-01-23 12:33:16 -0200 | [diff] [blame] | 484 | 			dev->brightness->cur.val, | 
 | 485 | 			dev->contrast->cur.val, | 
 | 486 | 			dev->saturation->cur.val, | 
 | 487 | 			dev->hue->cur.val); | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 488 | 	gen_text(dev, vbuf, line++ * 16, 16, str); | 
| Hans Verkuil | 7e996af | 2011-01-23 12:33:16 -0200 | [diff] [blame] | 489 | 	snprintf(str, sizeof(str), " volume %3d ", dev->volume->cur.val); | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 490 | 	gen_text(dev, vbuf, line++ * 16, 16, str); | 
| Hans Verkuil | 7e996af | 2011-01-23 12:33:16 -0200 | [diff] [blame] | 491 | 	snprintf(str, sizeof(str), " int32 %d, int64 %lld ", | 
 | 492 | 			dev->int32->cur.val, | 
 | 493 | 			dev->int64->cur.val64); | 
 | 494 | 	gen_text(dev, vbuf, line++ * 16, 16, str); | 
 | 495 | 	snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ", | 
 | 496 | 			dev->boolean->cur.val, | 
 | 497 | 			dev->menu->qmenu[dev->menu->cur.val], | 
 | 498 | 			dev->string->cur.string); | 
 | 499 | 	mutex_unlock(&dev->ctrl_handler.lock); | 
 | 500 | 	gen_text(dev, vbuf, line++ * 16, 16, str); | 
 | 501 | 	if (dev->button_pressed) { | 
 | 502 | 		dev->button_pressed--; | 
 | 503 | 		snprintf(str, sizeof(str), " button pressed!"); | 
 | 504 | 		gen_text(dev, vbuf, line++ * 16, 16, str); | 
 | 505 | 	} | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 506 |  | 
 | 507 | 	dev->mv_count += 2; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 508 |  | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 509 | 	buf->vb.v4l2_buf.field = dev->field; | 
 | 510 | 	dev->field_count++; | 
 | 511 | 	buf->vb.v4l2_buf.sequence = dev->field_count >> 1; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 512 | 	do_gettimeofday(&ts); | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 513 | 	buf->vb.v4l2_buf.timestamp = ts; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 514 | } | 
 | 515 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 516 | static void vivi_thread_tick(struct vivi_dev *dev) | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 517 | { | 
| Brandon Philips | 78718e5 | 2008-04-02 18:10:59 -0300 | [diff] [blame] | 518 | 	struct vivi_dmaqueue *dma_q = &dev->vidq; | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 519 | 	struct vivi_buffer *buf; | 
| Brandon Philips | 78718e5 | 2008-04-02 18:10:59 -0300 | [diff] [blame] | 520 | 	unsigned long flags = 0; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 521 |  | 
| Brandon Philips | 78718e5 | 2008-04-02 18:10:59 -0300 | [diff] [blame] | 522 | 	dprintk(dev, 1, "Thread tick\n"); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 523 |  | 
| Brandon Philips | 78718e5 | 2008-04-02 18:10:59 -0300 | [diff] [blame] | 524 | 	spin_lock_irqsave(&dev->slock, flags); | 
 | 525 | 	if (list_empty(&dma_q->active)) { | 
 | 526 | 		dprintk(dev, 1, "No active queue to serve\n"); | 
 | 527 | 		goto unlock; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 528 | 	} | 
| Brandon Philips | 78718e5 | 2008-04-02 18:10:59 -0300 | [diff] [blame] | 529 |  | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 530 | 	buf = list_entry(dma_q->active.next, struct vivi_buffer, list); | 
 | 531 | 	list_del(&buf->list); | 
| Brandon Philips | 78718e5 | 2008-04-02 18:10:59 -0300 | [diff] [blame] | 532 |  | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 533 | 	do_gettimeofday(&buf->vb.v4l2_buf.timestamp); | 
| Brandon Philips | 78718e5 | 2008-04-02 18:10:59 -0300 | [diff] [blame] | 534 |  | 
 | 535 | 	/* Fill buffer */ | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 536 | 	vivi_fillbuff(dev, buf); | 
| Brandon Philips | 78718e5 | 2008-04-02 18:10:59 -0300 | [diff] [blame] | 537 | 	dprintk(dev, 1, "filled buffer %p\n", buf); | 
 | 538 |  | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 539 | 	vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); | 
 | 540 | 	dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index); | 
| Brandon Philips | 78718e5 | 2008-04-02 18:10:59 -0300 | [diff] [blame] | 541 | unlock: | 
 | 542 | 	spin_unlock_irqrestore(&dev->slock, flags); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 543 | } | 
 | 544 |  | 
| Mauro Carvalho Chehab | 6594ad8 | 2007-12-13 16:15:41 -0300 | [diff] [blame] | 545 | #define frames_to_ms(frames)					\ | 
 | 546 | 	((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR) | 
 | 547 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 548 | static void vivi_sleep(struct vivi_dev *dev) | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 549 | { | 
| Brandon Philips | 78718e5 | 2008-04-02 18:10:59 -0300 | [diff] [blame] | 550 | 	struct vivi_dmaqueue *dma_q = &dev->vidq; | 
 | 551 | 	int timeout; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 552 | 	DECLARE_WAITQUEUE(wait, current); | 
 | 553 |  | 
| Harvey Harrison | 7e28adb | 2008-04-08 23:20:00 -0300 | [diff] [blame] | 554 | 	dprintk(dev, 1, "%s dma_q=0x%08lx\n", __func__, | 
| Mauro Carvalho Chehab | 6c2f990 | 2007-12-13 13:30:14 -0300 | [diff] [blame] | 555 | 		(unsigned long)dma_q); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 556 |  | 
 | 557 | 	add_wait_queue(&dma_q->wq, &wait); | 
| Mauro Carvalho Chehab | 6594ad8 | 2007-12-13 16:15:41 -0300 | [diff] [blame] | 558 | 	if (kthread_should_stop()) | 
 | 559 | 		goto stop_task; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 560 |  | 
| Mauro Carvalho Chehab | 6594ad8 | 2007-12-13 16:15:41 -0300 | [diff] [blame] | 561 | 	/* Calculate time to wake up */ | 
| Brandon Philips | 78718e5 | 2008-04-02 18:10:59 -0300 | [diff] [blame] | 562 | 	timeout = msecs_to_jiffies(frames_to_ms(1)); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 563 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 564 | 	vivi_thread_tick(dev); | 
| Mauro Carvalho Chehab | 6594ad8 | 2007-12-13 16:15:41 -0300 | [diff] [blame] | 565 |  | 
 | 566 | 	schedule_timeout_interruptible(timeout); | 
 | 567 |  | 
 | 568 | stop_task: | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 569 | 	remove_wait_queue(&dma_q->wq, &wait); | 
 | 570 | 	try_to_freeze(); | 
 | 571 | } | 
 | 572 |  | 
| Adrian Bunk | 972c351 | 2006-04-27 21:06:50 -0300 | [diff] [blame] | 573 | static int vivi_thread(void *data) | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 574 | { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 575 | 	struct vivi_dev *dev = data; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 576 |  | 
| Mauro Carvalho Chehab | 6c2f990 | 2007-12-13 13:30:14 -0300 | [diff] [blame] | 577 | 	dprintk(dev, 1, "thread started\n"); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 578 |  | 
| Rafael J. Wysocki | 8314418 | 2007-07-17 04:03:35 -0700 | [diff] [blame] | 579 | 	set_freezable(); | 
| Mauro Carvalho Chehab | 0b60051 | 2007-01-14 08:33:24 -0300 | [diff] [blame] | 580 |  | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 581 | 	for (;;) { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 582 | 		vivi_sleep(dev); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 583 |  | 
 | 584 | 		if (kthread_should_stop()) | 
 | 585 | 			break; | 
 | 586 | 	} | 
| Mauro Carvalho Chehab | 6c2f990 | 2007-12-13 13:30:14 -0300 | [diff] [blame] | 587 | 	dprintk(dev, 1, "thread: exit\n"); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 588 | 	return 0; | 
 | 589 | } | 
 | 590 |  | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 591 | static int vivi_start_generating(struct vivi_dev *dev) | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 592 | { | 
| Brandon Philips | 78718e5 | 2008-04-02 18:10:59 -0300 | [diff] [blame] | 593 | 	struct vivi_dmaqueue *dma_q = &dev->vidq; | 
| Mauro Carvalho Chehab | 6c2f990 | 2007-12-13 13:30:14 -0300 | [diff] [blame] | 594 |  | 
| Harvey Harrison | 7e28adb | 2008-04-08 23:20:00 -0300 | [diff] [blame] | 595 | 	dprintk(dev, 1, "%s\n", __func__); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 596 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 597 | 	/* Resets frame counters */ | 
 | 598 | 	dev->ms = 0; | 
 | 599 | 	dev->mv_count = 0; | 
 | 600 | 	dev->jiffies = jiffies; | 
 | 601 |  | 
 | 602 | 	dma_q->frame = 0; | 
 | 603 | 	dma_q->ini_jiffies = jiffies; | 
 | 604 | 	dma_q->kthread = kthread_run(vivi_thread, dev, dev->v4l2_dev.name); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 605 |  | 
| Akinobu Mita | 054afee | 2006-12-20 10:04:00 -0300 | [diff] [blame] | 606 | 	if (IS_ERR(dma_q->kthread)) { | 
| Hans Verkuil | 5ab6c9a | 2009-02-14 13:23:12 -0300 | [diff] [blame] | 607 | 		v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n"); | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 608 | 		return PTR_ERR(dma_q->kthread); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 609 | 	} | 
| Mauro Carvalho Chehab | 0b60051 | 2007-01-14 08:33:24 -0300 | [diff] [blame] | 610 | 	/* Wakes thread */ | 
 | 611 | 	wake_up_interruptible(&dma_q->wq); | 
 | 612 |  | 
| Harvey Harrison | 7e28adb | 2008-04-08 23:20:00 -0300 | [diff] [blame] | 613 | 	dprintk(dev, 1, "returning from %s\n", __func__); | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 614 | 	return 0; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 615 | } | 
 | 616 |  | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 617 | static void vivi_stop_generating(struct vivi_dev *dev) | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 618 | { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 619 | 	struct vivi_dmaqueue *dma_q = &dev->vidq; | 
| Mauro Carvalho Chehab | 6c2f990 | 2007-12-13 13:30:14 -0300 | [diff] [blame] | 620 |  | 
| Harvey Harrison | 7e28adb | 2008-04-08 23:20:00 -0300 | [diff] [blame] | 621 | 	dprintk(dev, 1, "%s\n", __func__); | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 622 |  | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 623 | 	/* shutdown control thread */ | 
 | 624 | 	if (dma_q->kthread) { | 
 | 625 | 		kthread_stop(dma_q->kthread); | 
| Mauro Carvalho Chehab | 543323b | 2007-12-10 09:33:52 -0300 | [diff] [blame] | 626 | 		dma_q->kthread = NULL; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 627 | 	} | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 628 |  | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 629 | 	/* | 
 | 630 | 	 * Typical driver might need to wait here until dma engine stops. | 
 | 631 | 	 * In this case we can abort imiedetly, so it's just a noop. | 
 | 632 | 	 */ | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 633 |  | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 634 | 	/* Release all active buffers */ | 
 | 635 | 	while (!list_empty(&dma_q->active)) { | 
 | 636 | 		struct vivi_buffer *buf; | 
 | 637 | 		buf = list_entry(dma_q->active.next, struct vivi_buffer, list); | 
 | 638 | 		list_del(&buf->list); | 
 | 639 | 		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); | 
 | 640 | 		dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index); | 
 | 641 | 	} | 
 | 642 | } | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 643 | /* ------------------------------------------------------------------ | 
 | 644 | 	Videobuf operations | 
 | 645 |    ------------------------------------------------------------------*/ | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 646 | static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, | 
 | 647 | 				unsigned int *nplanes, unsigned long sizes[], | 
 | 648 | 				void *alloc_ctxs[]) | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 649 | { | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 650 | 	struct vivi_dev *dev = vb2_get_drv_priv(vq); | 
 | 651 | 	unsigned long size; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 652 |  | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 653 | 	size = dev->width * dev->height * 2; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 654 |  | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 655 | 	if (0 == *nbuffers) | 
 | 656 | 		*nbuffers = 32; | 
| Mauro Carvalho Chehab | 6bb2790 | 2007-08-23 16:41:14 -0300 | [diff] [blame] | 657 |  | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 658 | 	while (size * *nbuffers > vid_limit * 1024 * 1024) | 
 | 659 | 		(*nbuffers)--; | 
| Mauro Carvalho Chehab | 6bb2790 | 2007-08-23 16:41:14 -0300 | [diff] [blame] | 660 |  | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 661 | 	*nplanes = 1; | 
 | 662 |  | 
 | 663 | 	sizes[0] = size; | 
 | 664 |  | 
 | 665 | 	/* | 
 | 666 | 	 * videobuf2-vmalloc allocator is context-less so no need to set | 
 | 667 | 	 * alloc_ctxs array. | 
 | 668 | 	 */ | 
 | 669 |  | 
 | 670 | 	dprintk(dev, 1, "%s, count=%d, size=%ld\n", __func__, | 
 | 671 | 		*nbuffers, size); | 
| Mauro Carvalho Chehab | 6bb2790 | 2007-08-23 16:41:14 -0300 | [diff] [blame] | 672 |  | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 673 | 	return 0; | 
 | 674 | } | 
 | 675 |  | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 676 | static int buffer_init(struct vb2_buffer *vb) | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 677 | { | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 678 | 	struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 679 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 680 | 	BUG_ON(NULL == dev->fmt); | 
| Brandon Philips | 78718e5 | 2008-04-02 18:10:59 -0300 | [diff] [blame] | 681 |  | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 682 | 	/* | 
 | 683 | 	 * This callback is called once per buffer, after its allocation. | 
 | 684 | 	 * | 
 | 685 | 	 * Vivi does not allow changing format during streaming, but it is | 
 | 686 | 	 * possible to do so when streaming is paused (i.e. in streamoff state). | 
 | 687 | 	 * Buffers however are not freed when going into streamoff and so | 
 | 688 | 	 * buffer size verification has to be done in buffer_prepare, on each | 
 | 689 | 	 * qbuf. | 
 | 690 | 	 * It would be best to move verification code here to buf_init and | 
 | 691 | 	 * s_fmt though. | 
 | 692 | 	 */ | 
 | 693 |  | 
 | 694 | 	return 0; | 
 | 695 | } | 
 | 696 |  | 
 | 697 | static int buffer_prepare(struct vb2_buffer *vb) | 
 | 698 | { | 
 | 699 | 	struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue); | 
 | 700 | 	struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); | 
 | 701 | 	unsigned long size; | 
 | 702 |  | 
 | 703 | 	dprintk(dev, 1, "%s, field=%d\n", __func__, vb->v4l2_buf.field); | 
 | 704 |  | 
 | 705 | 	BUG_ON(NULL == dev->fmt); | 
 | 706 |  | 
 | 707 | 	/* | 
 | 708 | 	 * Theses properties only change when queue is idle, see s_fmt. | 
 | 709 | 	 * The below checks should not be performed here, on each | 
 | 710 | 	 * buffer_prepare (i.e. on each qbuf). Most of the code in this function | 
 | 711 | 	 * should thus be moved to buffer_init and s_fmt. | 
 | 712 | 	 */ | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 713 | 	if (dev->width  < 48 || dev->width  > MAX_WIDTH || | 
 | 714 | 	    dev->height < 32 || dev->height > MAX_HEIGHT) | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 715 | 		return -EINVAL; | 
| Brandon Philips | 78718e5 | 2008-04-02 18:10:59 -0300 | [diff] [blame] | 716 |  | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 717 | 	size = dev->width * dev->height * 2; | 
 | 718 | 	if (vb2_plane_size(vb, 0) < size) { | 
 | 719 | 		dprintk(dev, 1, "%s data will not fit into plane (%lu < %lu)\n", | 
 | 720 | 				__func__, vb2_plane_size(vb, 0), size); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 721 | 		return -EINVAL; | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 722 | 	} | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 723 |  | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 724 | 	vb2_set_plane_payload(&buf->vb, 0, size); | 
 | 725 |  | 
 | 726 | 	buf->fmt = dev->fmt; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 727 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 728 | 	precalculate_bars(dev); | 
 | 729 | 	precalculate_line(dev); | 
| Mauro Carvalho Chehab | c285add | 2009-06-25 16:28:23 -0300 | [diff] [blame] | 730 |  | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 731 | 	return 0; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 732 | } | 
 | 733 |  | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 734 | static int buffer_finish(struct vb2_buffer *vb) | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 735 | { | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 736 | 	struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue); | 
 | 737 | 	dprintk(dev, 1, "%s\n", __func__); | 
 | 738 | 	return 0; | 
 | 739 | } | 
 | 740 |  | 
 | 741 | static void buffer_cleanup(struct vb2_buffer *vb) | 
 | 742 | { | 
 | 743 | 	struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue); | 
 | 744 | 	dprintk(dev, 1, "%s\n", __func__); | 
 | 745 |  | 
 | 746 | } | 
 | 747 |  | 
 | 748 | static void buffer_queue(struct vb2_buffer *vb) | 
 | 749 | { | 
 | 750 | 	struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue); | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 751 | 	struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); | 
| Brandon Philips | 78718e5 | 2008-04-02 18:10:59 -0300 | [diff] [blame] | 752 | 	struct vivi_dmaqueue *vidq = &dev->vidq; | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 753 | 	unsigned long flags = 0; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 754 |  | 
| Harvey Harrison | 7e28adb | 2008-04-08 23:20:00 -0300 | [diff] [blame] | 755 | 	dprintk(dev, 1, "%s\n", __func__); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 756 |  | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 757 | 	spin_lock_irqsave(&dev->slock, flags); | 
 | 758 | 	list_add_tail(&buf->list, &vidq->active); | 
 | 759 | 	spin_unlock_irqrestore(&dev->slock, flags); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 760 | } | 
 | 761 |  | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 762 | static int start_streaming(struct vb2_queue *vq) | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 763 | { | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 764 | 	struct vivi_dev *dev = vb2_get_drv_priv(vq); | 
| Harvey Harrison | 7e28adb | 2008-04-08 23:20:00 -0300 | [diff] [blame] | 765 | 	dprintk(dev, 1, "%s\n", __func__); | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 766 | 	return vivi_start_generating(dev); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 767 | } | 
 | 768 |  | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 769 | /* abort streaming and wait for last buffer */ | 
 | 770 | static int stop_streaming(struct vb2_queue *vq) | 
 | 771 | { | 
 | 772 | 	struct vivi_dev *dev = vb2_get_drv_priv(vq); | 
 | 773 | 	dprintk(dev, 1, "%s\n", __func__); | 
 | 774 | 	vivi_stop_generating(dev); | 
 | 775 | 	return 0; | 
 | 776 | } | 
 | 777 |  | 
 | 778 | static void vivi_lock(struct vb2_queue *vq) | 
 | 779 | { | 
 | 780 | 	struct vivi_dev *dev = vb2_get_drv_priv(vq); | 
 | 781 | 	mutex_lock(&dev->mutex); | 
 | 782 | } | 
 | 783 |  | 
 | 784 | static void vivi_unlock(struct vb2_queue *vq) | 
 | 785 | { | 
 | 786 | 	struct vivi_dev *dev = vb2_get_drv_priv(vq); | 
 | 787 | 	mutex_unlock(&dev->mutex); | 
 | 788 | } | 
 | 789 |  | 
 | 790 |  | 
 | 791 | static struct vb2_ops vivi_video_qops = { | 
 | 792 | 	.queue_setup		= queue_setup, | 
 | 793 | 	.buf_init		= buffer_init, | 
 | 794 | 	.buf_prepare		= buffer_prepare, | 
 | 795 | 	.buf_finish		= buffer_finish, | 
 | 796 | 	.buf_cleanup		= buffer_cleanup, | 
 | 797 | 	.buf_queue		= buffer_queue, | 
 | 798 | 	.start_streaming	= start_streaming, | 
 | 799 | 	.stop_streaming		= stop_streaming, | 
 | 800 | 	.wait_prepare		= vivi_unlock, | 
 | 801 | 	.wait_finish		= vivi_lock, | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 802 | }; | 
 | 803 |  | 
 | 804 | /* ------------------------------------------------------------------ | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 805 | 	IOCTL vidioc handling | 
 | 806 |    ------------------------------------------------------------------*/ | 
| Mauro Carvalho Chehab | 543323b | 2007-12-10 09:33:52 -0300 | [diff] [blame] | 807 | static int vidioc_querycap(struct file *file, void  *priv, | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 808 | 					struct v4l2_capability *cap) | 
 | 809 | { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 810 | 	struct vivi_dev *dev = video_drvdata(file); | 
| Hans Verkuil | 5ab6c9a | 2009-02-14 13:23:12 -0300 | [diff] [blame] | 811 |  | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 812 | 	strcpy(cap->driver, "vivi"); | 
 | 813 | 	strcpy(cap->card, "vivi"); | 
| Hans Verkuil | 5ab6c9a | 2009-02-14 13:23:12 -0300 | [diff] [blame] | 814 | 	strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info)); | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 815 | 	cap->version = VIVI_VERSION; | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 816 | 	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | \ | 
 | 817 | 			    V4L2_CAP_READWRITE; | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 818 | 	return 0; | 
 | 819 | } | 
 | 820 |  | 
| Hans Verkuil | 78b526a | 2008-05-28 12:16:41 -0300 | [diff] [blame] | 821 | static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv, | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 822 | 					struct v4l2_fmtdesc *f) | 
 | 823 | { | 
| Magnus Damm | d891f47 | 2008-10-14 12:47:09 -0300 | [diff] [blame] | 824 | 	struct vivi_fmt *fmt; | 
 | 825 |  | 
 | 826 | 	if (f->index >= ARRAY_SIZE(formats)) | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 827 | 		return -EINVAL; | 
 | 828 |  | 
| Magnus Damm | d891f47 | 2008-10-14 12:47:09 -0300 | [diff] [blame] | 829 | 	fmt = &formats[f->index]; | 
 | 830 |  | 
 | 831 | 	strlcpy(f->description, fmt->name, sizeof(f->description)); | 
 | 832 | 	f->pixelformat = fmt->fourcc; | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 833 | 	return 0; | 
 | 834 | } | 
 | 835 |  | 
| Hans Verkuil | 78b526a | 2008-05-28 12:16:41 -0300 | [diff] [blame] | 836 | static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 837 | 					struct v4l2_format *f) | 
 | 838 | { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 839 | 	struct vivi_dev *dev = video_drvdata(file); | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 840 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 841 | 	f->fmt.pix.width        = dev->width; | 
 | 842 | 	f->fmt.pix.height       = dev->height; | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 843 | 	f->fmt.pix.field        = dev->field; | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 844 | 	f->fmt.pix.pixelformat  = dev->fmt->fourcc; | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 845 | 	f->fmt.pix.bytesperline = | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 846 | 		(f->fmt.pix.width * dev->fmt->depth) >> 3; | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 847 | 	f->fmt.pix.sizeimage = | 
 | 848 | 		f->fmt.pix.height * f->fmt.pix.bytesperline; | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 849 | 	return 0; | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 850 | } | 
 | 851 |  | 
| Hans Verkuil | 78b526a | 2008-05-28 12:16:41 -0300 | [diff] [blame] | 852 | static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 853 | 			struct v4l2_format *f) | 
 | 854 | { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 855 | 	struct vivi_dev *dev = video_drvdata(file); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 856 | 	struct vivi_fmt *fmt; | 
 | 857 | 	enum v4l2_field field; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 858 |  | 
| Magnus Damm | d891f47 | 2008-10-14 12:47:09 -0300 | [diff] [blame] | 859 | 	fmt = get_format(f); | 
 | 860 | 	if (!fmt) { | 
 | 861 | 		dprintk(dev, 1, "Fourcc format (0x%08x) invalid.\n", | 
 | 862 | 			f->fmt.pix.pixelformat); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 863 | 		return -EINVAL; | 
 | 864 | 	} | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 865 |  | 
 | 866 | 	field = f->fmt.pix.field; | 
 | 867 |  | 
 | 868 | 	if (field == V4L2_FIELD_ANY) { | 
| Mauro Carvalho Chehab | 543323b | 2007-12-10 09:33:52 -0300 | [diff] [blame] | 869 | 		field = V4L2_FIELD_INTERLACED; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 870 | 	} else if (V4L2_FIELD_INTERLACED != field) { | 
| Mauro Carvalho Chehab | 6c2f990 | 2007-12-13 13:30:14 -0300 | [diff] [blame] | 871 | 		dprintk(dev, 1, "Field type invalid.\n"); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 872 | 		return -EINVAL; | 
 | 873 | 	} | 
 | 874 |  | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 875 | 	f->fmt.pix.field = field; | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 876 | 	v4l_bound_align_image(&f->fmt.pix.width, 48, MAX_WIDTH, 2, | 
 | 877 | 			      &f->fmt.pix.height, 32, MAX_HEIGHT, 0, 0); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 878 | 	f->fmt.pix.bytesperline = | 
 | 879 | 		(f->fmt.pix.width * fmt->depth) >> 3; | 
 | 880 | 	f->fmt.pix.sizeimage = | 
 | 881 | 		f->fmt.pix.height * f->fmt.pix.bytesperline; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 882 | 	return 0; | 
 | 883 | } | 
 | 884 |  | 
| Mauro Carvalho Chehab | e164b58 | 2009-01-11 10:29:43 -0300 | [diff] [blame] | 885 | static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, | 
 | 886 | 					struct v4l2_format *f) | 
 | 887 | { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 888 | 	struct vivi_dev *dev = video_drvdata(file); | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 889 | 	struct vb2_queue *q = &dev->vb_vidq; | 
| Mauro Carvalho Chehab | e164b58 | 2009-01-11 10:29:43 -0300 | [diff] [blame] | 890 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 891 | 	int ret = vidioc_try_fmt_vid_cap(file, priv, f); | 
| Mauro Carvalho Chehab | e164b58 | 2009-01-11 10:29:43 -0300 | [diff] [blame] | 892 | 	if (ret < 0) | 
 | 893 | 		return ret; | 
 | 894 |  | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 895 | 	if (vb2_is_streaming(q)) { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 896 | 		dprintk(dev, 1, "%s device busy\n", __func__); | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 897 | 		return -EBUSY; | 
| Mauro Carvalho Chehab | e164b58 | 2009-01-11 10:29:43 -0300 | [diff] [blame] | 898 | 	} | 
 | 899 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 900 | 	dev->fmt = get_format(f); | 
 | 901 | 	dev->width = f->fmt.pix.width; | 
 | 902 | 	dev->height = f->fmt.pix.height; | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 903 | 	dev->field = f->fmt.pix.field; | 
 | 904 |  | 
 | 905 | 	return 0; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 906 | } | 
 | 907 |  | 
| Mauro Carvalho Chehab | 543323b | 2007-12-10 09:33:52 -0300 | [diff] [blame] | 908 | static int vidioc_reqbufs(struct file *file, void *priv, | 
 | 909 | 			  struct v4l2_requestbuffers *p) | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 910 | { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 911 | 	struct vivi_dev *dev = video_drvdata(file); | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 912 | 	return vb2_reqbufs(&dev->vb_vidq, p); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 913 | } | 
 | 914 |  | 
| Mauro Carvalho Chehab | 543323b | 2007-12-10 09:33:52 -0300 | [diff] [blame] | 915 | static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 916 | { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 917 | 	struct vivi_dev *dev = video_drvdata(file); | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 918 | 	return vb2_querybuf(&dev->vb_vidq, p); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 919 | } | 
 | 920 |  | 
| Mauro Carvalho Chehab | 543323b | 2007-12-10 09:33:52 -0300 | [diff] [blame] | 921 | static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 922 | { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 923 | 	struct vivi_dev *dev = video_drvdata(file); | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 924 | 	return vb2_qbuf(&dev->vb_vidq, p); | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 925 | } | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 926 |  | 
| Mauro Carvalho Chehab | 543323b | 2007-12-10 09:33:52 -0300 | [diff] [blame] | 927 | static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 928 | { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 929 | 	struct vivi_dev *dev = video_drvdata(file); | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 930 | 	return vb2_dqbuf(&dev->vb_vidq, p, file->f_flags & O_NONBLOCK); | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 931 | } | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 932 |  | 
| Adrian Bunk | dc46ace | 2006-06-23 06:42:44 -0300 | [diff] [blame] | 933 | static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 934 | { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 935 | 	struct vivi_dev *dev = video_drvdata(file); | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 936 | 	return vb2_streamon(&dev->vb_vidq, i); | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 937 | } | 
 | 938 |  | 
| Adrian Bunk | dc46ace | 2006-06-23 06:42:44 -0300 | [diff] [blame] | 939 | static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 940 | { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 941 | 	struct vivi_dev *dev = video_drvdata(file); | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 942 | 	return vb2_streamoff(&dev->vb_vidq, i); | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 943 | } | 
 | 944 |  | 
| Mauro Carvalho Chehab | 543323b | 2007-12-10 09:33:52 -0300 | [diff] [blame] | 945 | static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 946 | { | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 947 | 	return 0; | 
 | 948 | } | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 949 |  | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 950 | /* only one input in this sample driver */ | 
| Mauro Carvalho Chehab | 543323b | 2007-12-10 09:33:52 -0300 | [diff] [blame] | 951 | static int vidioc_enum_input(struct file *file, void *priv, | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 952 | 				struct v4l2_input *inp) | 
 | 953 | { | 
| Mauro Carvalho Chehab | e164b58 | 2009-01-11 10:29:43 -0300 | [diff] [blame] | 954 | 	if (inp->index >= NUM_INPUTS) | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 955 | 		return -EINVAL; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 956 |  | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 957 | 	inp->type = V4L2_INPUT_TYPE_CAMERA; | 
| Mauro Carvalho Chehab | 784c668 | 2007-12-13 06:35:26 -0300 | [diff] [blame] | 958 | 	inp->std = V4L2_STD_525_60; | 
| Mauro Carvalho Chehab | e164b58 | 2009-01-11 10:29:43 -0300 | [diff] [blame] | 959 | 	sprintf(inp->name, "Camera %u", inp->index); | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 960 | 	return 0; | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 961 | } | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 962 |  | 
| Mauro Carvalho Chehab | 543323b | 2007-12-10 09:33:52 -0300 | [diff] [blame] | 963 | static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 964 | { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 965 | 	struct vivi_dev *dev = video_drvdata(file); | 
| Mauro Carvalho Chehab | e164b58 | 2009-01-11 10:29:43 -0300 | [diff] [blame] | 966 |  | 
 | 967 | 	*i = dev->input; | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 968 | 	return 0; | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 969 | } | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 970 |  | 
| Mauro Carvalho Chehab | 543323b | 2007-12-10 09:33:52 -0300 | [diff] [blame] | 971 | static int vidioc_s_input(struct file *file, void *priv, unsigned int i) | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 972 | { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 973 | 	struct vivi_dev *dev = video_drvdata(file); | 
| Mauro Carvalho Chehab | e164b58 | 2009-01-11 10:29:43 -0300 | [diff] [blame] | 974 |  | 
 | 975 | 	if (i >= NUM_INPUTS) | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 976 | 		return -EINVAL; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 977 |  | 
| Mauro Carvalho Chehab | e164b58 | 2009-01-11 10:29:43 -0300 | [diff] [blame] | 978 | 	dev->input = i; | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 979 | 	precalculate_bars(dev); | 
 | 980 | 	precalculate_line(dev); | 
 | 981 | 	return 0; | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 982 | } | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 983 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 984 | /* --- controls ---------------------------------------------- */ | 
| Hans Verkuil | 7e996af | 2011-01-23 12:33:16 -0200 | [diff] [blame] | 985 |  | 
 | 986 | static int vivi_s_ctrl(struct v4l2_ctrl *ctrl) | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 987 | { | 
| Hans Verkuil | 7e996af | 2011-01-23 12:33:16 -0200 | [diff] [blame] | 988 | 	struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 989 |  | 
| Hans Verkuil | 7e996af | 2011-01-23 12:33:16 -0200 | [diff] [blame] | 990 | 	if (ctrl == dev->button) | 
 | 991 | 		dev->button_pressed = 30; | 
 | 992 | 	return 0; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 993 | } | 
 | 994 |  | 
 | 995 | /* ------------------------------------------------------------------ | 
 | 996 | 	File operations for the device | 
 | 997 |    ------------------------------------------------------------------*/ | 
 | 998 |  | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 999 | static ssize_t | 
 | 1000 | vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) | 
 | 1001 | { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 1002 | 	struct vivi_dev *dev = video_drvdata(file); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 1003 |  | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 1004 | 	dprintk(dev, 1, "read called\n"); | 
 | 1005 | 	return vb2_read(&dev->vb_vidq, data, count, ppos, | 
 | 1006 | 		       file->f_flags & O_NONBLOCK); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 1007 | } | 
 | 1008 |  | 
 | 1009 | static unsigned int | 
 | 1010 | vivi_poll(struct file *file, struct poll_table_struct *wait) | 
 | 1011 | { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 1012 | 	struct vivi_dev *dev = video_drvdata(file); | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 1013 | 	struct vb2_queue *q = &dev->vb_vidq; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 1014 |  | 
| Harvey Harrison | 7e28adb | 2008-04-08 23:20:00 -0300 | [diff] [blame] | 1015 | 	dprintk(dev, 1, "%s\n", __func__); | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 1016 | 	return vb2_poll(q, file, wait); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 1017 | } | 
 | 1018 |  | 
| Hans Verkuil | bec4366 | 2008-12-30 06:58:20 -0300 | [diff] [blame] | 1019 | static int vivi_close(struct file *file) | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 1020 | { | 
| Laurent Pinchart | 50462eb | 2009-12-10 11:47:13 -0200 | [diff] [blame] | 1021 | 	struct video_device  *vdev = video_devdata(file); | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 1022 | 	struct vivi_dev *dev = video_drvdata(file); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 1023 |  | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 1024 | 	dprintk(dev, 1, "close called (dev=%s), file %p\n", | 
 | 1025 | 		video_device_node_name(vdev), file); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 1026 |  | 
| Hans Verkuil | 2e4784d | 2011-03-11 20:01:54 -0300 | [diff] [blame] | 1027 | 	if (v4l2_fh_is_singular_file(file)) | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 1028 | 		vb2_queue_release(&dev->vb_vidq); | 
| Hans Verkuil | 2e4784d | 2011-03-11 20:01:54 -0300 | [diff] [blame] | 1029 | 	return v4l2_fh_release(file); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 1030 | } | 
 | 1031 |  | 
| Mauro Carvalho Chehab | 543323b | 2007-12-10 09:33:52 -0300 | [diff] [blame] | 1032 | static int vivi_mmap(struct file *file, struct vm_area_struct *vma) | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 1033 | { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 1034 | 	struct vivi_dev *dev = video_drvdata(file); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 1035 | 	int ret; | 
 | 1036 |  | 
| Mauro Carvalho Chehab | 6c2f990 | 2007-12-13 13:30:14 -0300 | [diff] [blame] | 1037 | 	dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 1038 |  | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 1039 | 	ret = vb2_mmap(&dev->vb_vidq, vma); | 
| Mauro Carvalho Chehab | 6c2f990 | 2007-12-13 13:30:14 -0300 | [diff] [blame] | 1040 | 	dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n", | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 1041 | 		(unsigned long)vma->vm_start, | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 1042 | 		(unsigned long)vma->vm_end - (unsigned long)vma->vm_start, | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 1043 | 		ret); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 1044 | 	return ret; | 
 | 1045 | } | 
 | 1046 |  | 
| Hans Verkuil | 7e996af | 2011-01-23 12:33:16 -0200 | [diff] [blame] | 1047 | static const struct v4l2_ctrl_ops vivi_ctrl_ops = { | 
 | 1048 | 	.s_ctrl = vivi_s_ctrl, | 
 | 1049 | }; | 
 | 1050 |  | 
 | 1051 | #define VIVI_CID_CUSTOM_BASE	(V4L2_CID_USER_BASE | 0xf000) | 
 | 1052 |  | 
 | 1053 | static const struct v4l2_ctrl_config vivi_ctrl_button = { | 
 | 1054 | 	.ops = &vivi_ctrl_ops, | 
 | 1055 | 	.id = VIVI_CID_CUSTOM_BASE + 0, | 
 | 1056 | 	.name = "Button", | 
 | 1057 | 	.type = V4L2_CTRL_TYPE_BUTTON, | 
 | 1058 | }; | 
 | 1059 |  | 
 | 1060 | static const struct v4l2_ctrl_config vivi_ctrl_boolean = { | 
 | 1061 | 	.ops = &vivi_ctrl_ops, | 
 | 1062 | 	.id = VIVI_CID_CUSTOM_BASE + 1, | 
 | 1063 | 	.name = "Boolean", | 
 | 1064 | 	.type = V4L2_CTRL_TYPE_BOOLEAN, | 
 | 1065 | 	.min = 0, | 
 | 1066 | 	.max = 1, | 
 | 1067 | 	.step = 1, | 
 | 1068 | 	.def = 1, | 
 | 1069 | }; | 
 | 1070 |  | 
 | 1071 | static const struct v4l2_ctrl_config vivi_ctrl_int32 = { | 
 | 1072 | 	.ops = &vivi_ctrl_ops, | 
 | 1073 | 	.id = VIVI_CID_CUSTOM_BASE + 2, | 
 | 1074 | 	.name = "Integer 32 Bits", | 
 | 1075 | 	.type = V4L2_CTRL_TYPE_INTEGER, | 
| Hans Verkuil | 5b28302 | 2011-01-11 17:32:28 -0300 | [diff] [blame] | 1076 | 	.min = 0x80000000, | 
 | 1077 | 	.max = 0x7fffffff, | 
| Hans Verkuil | 7e996af | 2011-01-23 12:33:16 -0200 | [diff] [blame] | 1078 | 	.step = 1, | 
 | 1079 | }; | 
 | 1080 |  | 
 | 1081 | static const struct v4l2_ctrl_config vivi_ctrl_int64 = { | 
 | 1082 | 	.ops = &vivi_ctrl_ops, | 
 | 1083 | 	.id = VIVI_CID_CUSTOM_BASE + 3, | 
 | 1084 | 	.name = "Integer 64 Bits", | 
 | 1085 | 	.type = V4L2_CTRL_TYPE_INTEGER64, | 
 | 1086 | }; | 
 | 1087 |  | 
 | 1088 | static const char * const vivi_ctrl_menu_strings[] = { | 
 | 1089 | 	"Menu Item 0 (Skipped)", | 
 | 1090 | 	"Menu Item 1", | 
 | 1091 | 	"Menu Item 2 (Skipped)", | 
 | 1092 | 	"Menu Item 3", | 
 | 1093 | 	"Menu Item 4", | 
 | 1094 | 	"Menu Item 5 (Skipped)", | 
 | 1095 | 	NULL, | 
 | 1096 | }; | 
 | 1097 |  | 
 | 1098 | static const struct v4l2_ctrl_config vivi_ctrl_menu = { | 
 | 1099 | 	.ops = &vivi_ctrl_ops, | 
 | 1100 | 	.id = VIVI_CID_CUSTOM_BASE + 4, | 
 | 1101 | 	.name = "Menu", | 
 | 1102 | 	.type = V4L2_CTRL_TYPE_MENU, | 
 | 1103 | 	.min = 1, | 
 | 1104 | 	.max = 4, | 
 | 1105 | 	.def = 3, | 
 | 1106 | 	.menu_skip_mask = 0x04, | 
 | 1107 | 	.qmenu = vivi_ctrl_menu_strings, | 
 | 1108 | }; | 
 | 1109 |  | 
 | 1110 | static const struct v4l2_ctrl_config vivi_ctrl_string = { | 
 | 1111 | 	.ops = &vivi_ctrl_ops, | 
 | 1112 | 	.id = VIVI_CID_CUSTOM_BASE + 5, | 
 | 1113 | 	.name = "String", | 
 | 1114 | 	.type = V4L2_CTRL_TYPE_STRING, | 
 | 1115 | 	.min = 2, | 
 | 1116 | 	.max = 4, | 
 | 1117 | 	.step = 1, | 
 | 1118 | }; | 
 | 1119 |  | 
| Hans Verkuil | bec4366 | 2008-12-30 06:58:20 -0300 | [diff] [blame] | 1120 | static const struct v4l2_file_operations vivi_fops = { | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 1121 | 	.owner		= THIS_MODULE, | 
| Hans Verkuil | 2e4784d | 2011-03-11 20:01:54 -0300 | [diff] [blame] | 1122 | 	.open		= v4l2_fh_open, | 
| Mauro Carvalho Chehab | f905c44 | 2007-12-10 04:07:03 -0300 | [diff] [blame] | 1123 | 	.release        = vivi_close, | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 1124 | 	.read           = vivi_read, | 
 | 1125 | 	.poll		= vivi_poll, | 
| Hans Verkuil | fedc6c8 | 2010-09-20 18:25:55 -0300 | [diff] [blame] | 1126 | 	.unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ | 
| Mauro Carvalho Chehab | 5a03770 | 2007-08-02 23:31:54 -0300 | [diff] [blame] | 1127 | 	.mmap           = vivi_mmap, | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 1128 | }; | 
 | 1129 |  | 
| Hans Verkuil | a399810 | 2008-07-21 02:57:38 -0300 | [diff] [blame] | 1130 | static const struct v4l2_ioctl_ops vivi_ioctl_ops = { | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 1131 | 	.vidioc_querycap      = vidioc_querycap, | 
| Hans Verkuil | 78b526a | 2008-05-28 12:16:41 -0300 | [diff] [blame] | 1132 | 	.vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap, | 
 | 1133 | 	.vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap, | 
 | 1134 | 	.vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap, | 
 | 1135 | 	.vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap, | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 1136 | 	.vidioc_reqbufs       = vidioc_reqbufs, | 
 | 1137 | 	.vidioc_querybuf      = vidioc_querybuf, | 
 | 1138 | 	.vidioc_qbuf          = vidioc_qbuf, | 
 | 1139 | 	.vidioc_dqbuf         = vidioc_dqbuf, | 
 | 1140 | 	.vidioc_s_std         = vidioc_s_std, | 
 | 1141 | 	.vidioc_enum_input    = vidioc_enum_input, | 
 | 1142 | 	.vidioc_g_input       = vidioc_g_input, | 
 | 1143 | 	.vidioc_s_input       = vidioc_s_input, | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 1144 | 	.vidioc_streamon      = vidioc_streamon, | 
 | 1145 | 	.vidioc_streamoff     = vidioc_streamoff, | 
| Hans Verkuil | a399810 | 2008-07-21 02:57:38 -0300 | [diff] [blame] | 1146 | }; | 
 | 1147 |  | 
 | 1148 | static struct video_device vivi_template = { | 
 | 1149 | 	.name		= "vivi", | 
| Hans Verkuil | a399810 | 2008-07-21 02:57:38 -0300 | [diff] [blame] | 1150 | 	.fops           = &vivi_fops, | 
 | 1151 | 	.ioctl_ops 	= &vivi_ioctl_ops, | 
| Hans Verkuil | a399810 | 2008-07-21 02:57:38 -0300 | [diff] [blame] | 1152 | 	.release	= video_device_release, | 
 | 1153 |  | 
| Mauro Carvalho Chehab | 784c668 | 2007-12-13 06:35:26 -0300 | [diff] [blame] | 1154 | 	.tvnorms              = V4L2_STD_525_60, | 
| Mauro Carvalho Chehab | e75f9ce | 2006-11-20 13:19:20 -0300 | [diff] [blame] | 1155 | 	.current_norm         = V4L2_STD_NTSC_M, | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 1156 | }; | 
| Hans Verkuil | 5ab6c9a | 2009-02-14 13:23:12 -0300 | [diff] [blame] | 1157 |  | 
| Mauro Carvalho Chehab | c820cc4 | 2006-06-04 10:34:12 -0300 | [diff] [blame] | 1158 | /* ----------------------------------------------------------------- | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 1159 | 	Initialization and module stuff | 
 | 1160 |    ------------------------------------------------------------------*/ | 
 | 1161 |  | 
| Hans Verkuil | 5ab6c9a | 2009-02-14 13:23:12 -0300 | [diff] [blame] | 1162 | static int vivi_release(void) | 
 | 1163 | { | 
 | 1164 | 	struct vivi_dev *dev; | 
 | 1165 | 	struct list_head *list; | 
 | 1166 |  | 
 | 1167 | 	while (!list_empty(&vivi_devlist)) { | 
 | 1168 | 		list = vivi_devlist.next; | 
 | 1169 | 		list_del(list); | 
 | 1170 | 		dev = list_entry(list, struct vivi_dev, vivi_devlist); | 
 | 1171 |  | 
| Laurent Pinchart | 38c7c03 | 2009-11-27 13:57:15 -0300 | [diff] [blame] | 1172 | 		v4l2_info(&dev->v4l2_dev, "unregistering %s\n", | 
 | 1173 | 			video_device_node_name(dev->vfd)); | 
| Hans Verkuil | 5ab6c9a | 2009-02-14 13:23:12 -0300 | [diff] [blame] | 1174 | 		video_unregister_device(dev->vfd); | 
 | 1175 | 		v4l2_device_unregister(&dev->v4l2_dev); | 
| Hans Verkuil | 7e996af | 2011-01-23 12:33:16 -0200 | [diff] [blame] | 1176 | 		v4l2_ctrl_handler_free(&dev->ctrl_handler); | 
| Hans Verkuil | 5ab6c9a | 2009-02-14 13:23:12 -0300 | [diff] [blame] | 1177 | 		kfree(dev); | 
 | 1178 | 	} | 
 | 1179 |  | 
 | 1180 | 	return 0; | 
 | 1181 | } | 
 | 1182 |  | 
| Hans Verkuil | c41ee24 | 2009-02-14 13:43:44 -0300 | [diff] [blame] | 1183 | static int __init vivi_create_instance(int inst) | 
| Hans Verkuil | 5ab6c9a | 2009-02-14 13:23:12 -0300 | [diff] [blame] | 1184 | { | 
 | 1185 | 	struct vivi_dev *dev; | 
 | 1186 | 	struct video_device *vfd; | 
| Hans Verkuil | 7e996af | 2011-01-23 12:33:16 -0200 | [diff] [blame] | 1187 | 	struct v4l2_ctrl_handler *hdl; | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 1188 | 	struct vb2_queue *q; | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 1189 | 	int ret; | 
| Hans Verkuil | 5ab6c9a | 2009-02-14 13:23:12 -0300 | [diff] [blame] | 1190 |  | 
 | 1191 | 	dev = kzalloc(sizeof(*dev), GFP_KERNEL); | 
 | 1192 | 	if (!dev) | 
 | 1193 | 		return -ENOMEM; | 
 | 1194 |  | 
 | 1195 | 	snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), | 
| Hans Verkuil | c41ee24 | 2009-02-14 13:43:44 -0300 | [diff] [blame] | 1196 | 			"%s-%03d", VIVI_MODULE_NAME, inst); | 
| Hans Verkuil | 5ab6c9a | 2009-02-14 13:23:12 -0300 | [diff] [blame] | 1197 | 	ret = v4l2_device_register(NULL, &dev->v4l2_dev); | 
 | 1198 | 	if (ret) | 
 | 1199 | 		goto free_dev; | 
 | 1200 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 1201 | 	dev->fmt = &formats[0]; | 
 | 1202 | 	dev->width = 640; | 
 | 1203 | 	dev->height = 480; | 
| Hans Verkuil | 7e996af | 2011-01-23 12:33:16 -0200 | [diff] [blame] | 1204 | 	hdl = &dev->ctrl_handler; | 
 | 1205 | 	v4l2_ctrl_handler_init(hdl, 11); | 
 | 1206 | 	dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, | 
 | 1207 | 			V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200); | 
 | 1208 | 	dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, | 
 | 1209 | 			V4L2_CID_BRIGHTNESS, 0, 255, 1, 127); | 
 | 1210 | 	dev->contrast = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, | 
 | 1211 | 			V4L2_CID_CONTRAST, 0, 255, 1, 16); | 
 | 1212 | 	dev->saturation = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, | 
 | 1213 | 			V4L2_CID_SATURATION, 0, 255, 1, 127); | 
 | 1214 | 	dev->hue = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, | 
 | 1215 | 			V4L2_CID_HUE, -128, 127, 1, 0); | 
 | 1216 | 	dev->button = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_button, NULL); | 
 | 1217 | 	dev->int32 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int32, NULL); | 
 | 1218 | 	dev->int64 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int64, NULL); | 
 | 1219 | 	dev->boolean = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_boolean, NULL); | 
 | 1220 | 	dev->menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_menu, NULL); | 
 | 1221 | 	dev->string = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_string, NULL); | 
 | 1222 | 	if (hdl->error) { | 
 | 1223 | 		ret = hdl->error; | 
 | 1224 | 		goto unreg_dev; | 
 | 1225 | 	} | 
 | 1226 | 	dev->v4l2_dev.ctrl_handler = hdl; | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 1227 |  | 
| Hans Verkuil | fedc6c8 | 2010-09-20 18:25:55 -0300 | [diff] [blame] | 1228 | 	/* initialize locks */ | 
 | 1229 | 	spin_lock_init(&dev->slock); | 
| Hans Verkuil | fedc6c8 | 2010-09-20 18:25:55 -0300 | [diff] [blame] | 1230 |  | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 1231 | 	/* initialize queue */ | 
 | 1232 | 	q = &dev->vb_vidq; | 
 | 1233 | 	memset(q, 0, sizeof(dev->vb_vidq)); | 
 | 1234 | 	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 
 | 1235 | 	q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; | 
 | 1236 | 	q->drv_priv = dev; | 
 | 1237 | 	q->buf_struct_size = sizeof(struct vivi_buffer); | 
 | 1238 | 	q->ops = &vivi_video_qops; | 
 | 1239 | 	q->mem_ops = &vb2_vmalloc_memops; | 
 | 1240 |  | 
 | 1241 | 	vb2_queue_init(q); | 
 | 1242 |  | 
 | 1243 | 	mutex_init(&dev->mutex); | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 1244 |  | 
| Hans Verkuil | 5ab6c9a | 2009-02-14 13:23:12 -0300 | [diff] [blame] | 1245 | 	/* init video dma queues */ | 
 | 1246 | 	INIT_LIST_HEAD(&dev->vidq.active); | 
 | 1247 | 	init_waitqueue_head(&dev->vidq.wq); | 
 | 1248 |  | 
| Hans Verkuil | 5ab6c9a | 2009-02-14 13:23:12 -0300 | [diff] [blame] | 1249 | 	ret = -ENOMEM; | 
 | 1250 | 	vfd = video_device_alloc(); | 
 | 1251 | 	if (!vfd) | 
 | 1252 | 		goto unreg_dev; | 
 | 1253 |  | 
 | 1254 | 	*vfd = vivi_template; | 
| Mauro Carvalho Chehab | c285add | 2009-06-25 16:28:23 -0300 | [diff] [blame] | 1255 | 	vfd->debug = debug; | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 1256 | 	vfd->v4l2_dev = &dev->v4l2_dev; | 
| Hans Verkuil | b1a873a | 2011-03-22 10:14:07 -0300 | [diff] [blame] | 1257 | 	set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); | 
| Pawel Osciak | e007a32 | 2011-01-19 13:02:29 -0200 | [diff] [blame] | 1258 |  | 
 | 1259 | 	/* | 
 | 1260 | 	 * Provide a mutex to v4l2 core. It will be used to protect | 
 | 1261 | 	 * all fops and v4l2 ioctls. | 
 | 1262 | 	 */ | 
| Hans Verkuil | fedc6c8 | 2010-09-20 18:25:55 -0300 | [diff] [blame] | 1263 | 	vfd->lock = &dev->mutex; | 
| Hans Verkuil | 5ab6c9a | 2009-02-14 13:23:12 -0300 | [diff] [blame] | 1264 |  | 
 | 1265 | 	ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); | 
 | 1266 | 	if (ret < 0) | 
 | 1267 | 		goto rel_vdev; | 
 | 1268 |  | 
 | 1269 | 	video_set_drvdata(vfd, dev); | 
 | 1270 |  | 
 | 1271 | 	/* Now that everything is fine, let's add it to device list */ | 
 | 1272 | 	list_add_tail(&dev->vivi_devlist, &vivi_devlist); | 
 | 1273 |  | 
| Roel Kluin | 7de0b87 | 2009-12-16 13:06:33 -0300 | [diff] [blame] | 1274 | 	if (video_nr != -1) | 
| Hans Verkuil | 5ab6c9a | 2009-02-14 13:23:12 -0300 | [diff] [blame] | 1275 | 		video_nr++; | 
 | 1276 |  | 
 | 1277 | 	dev->vfd = vfd; | 
| Laurent Pinchart | 38c7c03 | 2009-11-27 13:57:15 -0300 | [diff] [blame] | 1278 | 	v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n", | 
 | 1279 | 		  video_device_node_name(vfd)); | 
| Hans Verkuil | 5ab6c9a | 2009-02-14 13:23:12 -0300 | [diff] [blame] | 1280 | 	return 0; | 
 | 1281 |  | 
 | 1282 | rel_vdev: | 
 | 1283 | 	video_device_release(vfd); | 
 | 1284 | unreg_dev: | 
| Hans Verkuil | 7e996af | 2011-01-23 12:33:16 -0200 | [diff] [blame] | 1285 | 	v4l2_ctrl_handler_free(hdl); | 
| Hans Verkuil | 5ab6c9a | 2009-02-14 13:23:12 -0300 | [diff] [blame] | 1286 | 	v4l2_device_unregister(&dev->v4l2_dev); | 
 | 1287 | free_dev: | 
 | 1288 | 	kfree(dev); | 
 | 1289 | 	return ret; | 
 | 1290 | } | 
 | 1291 |  | 
| Mauro Carvalho Chehab | 980d4f1 | 2008-09-03 17:11:53 -0300 | [diff] [blame] | 1292 | /* This routine allocates from 1 to n_devs virtual drivers. | 
 | 1293 |  | 
 | 1294 |    The real maximum number of virtual drivers will depend on how many drivers | 
 | 1295 |    will succeed. This is limited to the maximum number of devices that | 
| Hans Verkuil | 62cfdac | 2009-02-14 11:37:17 -0300 | [diff] [blame] | 1296 |    videodev supports, which is equal to VIDEO_NUM_DEVICES. | 
| Mauro Carvalho Chehab | 980d4f1 | 2008-09-03 17:11:53 -0300 | [diff] [blame] | 1297 |  */ | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 1298 | static int __init vivi_init(void) | 
 | 1299 | { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 1300 | 	const struct font_desc *font = find_font("VGA8x16"); | 
| Hans Verkuil | 9185cbf | 2009-03-06 09:58:12 -0300 | [diff] [blame] | 1301 | 	int ret = 0, i; | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 1302 |  | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 1303 | 	if (font == NULL) { | 
 | 1304 | 		printk(KERN_ERR "vivi: could not find font\n"); | 
 | 1305 | 		return -ENODEV; | 
 | 1306 | 	} | 
 | 1307 | 	font8x16 = font->data; | 
 | 1308 |  | 
| Mauro Carvalho Chehab | 980d4f1 | 2008-09-03 17:11:53 -0300 | [diff] [blame] | 1309 | 	if (n_devs <= 0) | 
 | 1310 | 		n_devs = 1; | 
 | 1311 |  | 
| Mauro Carvalho Chehab | 55712ff | 2007-12-10 04:38:11 -0300 | [diff] [blame] | 1312 | 	for (i = 0; i < n_devs; i++) { | 
| Hans Verkuil | 5ab6c9a | 2009-02-14 13:23:12 -0300 | [diff] [blame] | 1313 | 		ret = vivi_create_instance(i); | 
 | 1314 | 		if (ret) { | 
 | 1315 | 			/* If some instantiations succeeded, keep driver */ | 
| Mauro Carvalho Chehab | 980d4f1 | 2008-09-03 17:11:53 -0300 | [diff] [blame] | 1316 | 			if (i) | 
 | 1317 | 				ret = 0; | 
| Mauro Carvalho Chehab | 55712ff | 2007-12-10 04:38:11 -0300 | [diff] [blame] | 1318 | 			break; | 
| Mauro Carvalho Chehab | 980d4f1 | 2008-09-03 17:11:53 -0300 | [diff] [blame] | 1319 | 		} | 
| Mauro Carvalho Chehab | 55712ff | 2007-12-10 04:38:11 -0300 | [diff] [blame] | 1320 | 	} | 
 | 1321 |  | 
 | 1322 | 	if (ret < 0) { | 
| Hans Verkuil | 730947b | 2010-04-10 04:13:53 -0300 | [diff] [blame] | 1323 | 		printk(KERN_ERR "vivi: error %d while loading driver\n", ret); | 
| Hans Verkuil | 5ab6c9a | 2009-02-14 13:23:12 -0300 | [diff] [blame] | 1324 | 		return ret; | 
 | 1325 | 	} | 
 | 1326 |  | 
 | 1327 | 	printk(KERN_INFO "Video Technology Magazine Virtual Video " | 
| Carl Karsten | 745271a | 2008-06-10 00:02:32 -0300 | [diff] [blame] | 1328 | 			"Capture Board ver %u.%u.%u successfully loaded.\n", | 
 | 1329 | 			(VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF, | 
 | 1330 | 			VIVI_VERSION & 0xFF); | 
| Mauro Carvalho Chehab | 980d4f1 | 2008-09-03 17:11:53 -0300 | [diff] [blame] | 1331 |  | 
| Hans Verkuil | 5ab6c9a | 2009-02-14 13:23:12 -0300 | [diff] [blame] | 1332 | 	/* n_devs will reflect the actual number of allocated devices */ | 
 | 1333 | 	n_devs = i; | 
| Mauro Carvalho Chehab | 980d4f1 | 2008-09-03 17:11:53 -0300 | [diff] [blame] | 1334 |  | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 1335 | 	return ret; | 
 | 1336 | } | 
 | 1337 |  | 
 | 1338 | static void __exit vivi_exit(void) | 
 | 1339 | { | 
| Mauro Carvalho Chehab | 55712ff | 2007-12-10 04:38:11 -0300 | [diff] [blame] | 1340 | 	vivi_release(); | 
| Mauro Carvalho Chehab | 1e6dd65 | 2006-03-10 12:40:10 -0300 | [diff] [blame] | 1341 | } | 
 | 1342 |  | 
 | 1343 | module_init(vivi_init); | 
 | 1344 | module_exit(vivi_exit); |