blob: cea232a3302d57e0c0a789754819c0b715432bef [file] [log] [blame]
Mike Iselyd8554972006-06-26 20:58:46 -03001/*
2 *
Mike Iselyd8554972006-06-26 20:58:46 -03003 *
4 * Copyright (C) 2005 Mike Isely <isely@pobox.com>
5 * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
Mike Iselyd8554972006-06-26 20:58:46 -030016 */
17
18#include <linux/kernel.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090019#include <linux/slab.h>
Mike Iselyd8554972006-06-26 20:58:46 -030020#include "pvrusb2-context.h"
21#include "pvrusb2-hdw.h"
22#include "pvrusb2.h"
23#include "pvrusb2-debug.h"
24#include "pvrusb2-v4l2.h"
25#include "pvrusb2-ioread.h"
26#include <linux/videodev2.h>
Paul Gortmaker7a707b82011-07-03 14:03:12 -040027#include <linux/module.h>
Mike Isely43e06022006-09-23 23:47:50 -030028#include <media/v4l2-dev.h>
Hans Verkuila28fbd02013-06-10 09:16:25 -030029#include <media/v4l2-device.h>
Hans Verkuilcee05cb2015-02-03 10:46:55 -030030#include <media/v4l2-fh.h>
Mike Iselyd8554972006-06-26 20:58:46 -030031#include <media/v4l2-common.h>
Hans Verkuil35ea11f2008-07-20 08:12:02 -030032#include <media/v4l2-ioctl.h>
Mike Iselyd8554972006-06-26 20:58:46 -030033
34struct pvr2_v4l2_dev;
35struct pvr2_v4l2_fh;
36struct pvr2_v4l2;
37
Mike Iselyd8554972006-06-26 20:58:46 -030038struct pvr2_v4l2_dev {
Mike Isely75910052006-09-23 22:30:50 -030039 struct video_device devbase; /* MUST be first! */
Mike Iselyd8554972006-06-26 20:58:46 -030040 struct pvr2_v4l2 *v4lp;
Mike Iselyd8554972006-06-26 20:58:46 -030041 struct pvr2_context_stream *stream;
Mike Isely16eb40d2006-12-30 18:27:32 -030042 /* Information about this device: */
43 enum pvr2_config config; /* Expected stream format */
44 int v4l_type; /* V4L defined type for this device node */
45 enum pvr2_v4l_type minor_type; /* pvr2-understood minor device type */
Mike Iselyd8554972006-06-26 20:58:46 -030046};
47
48struct pvr2_v4l2_fh {
Hans Verkuilcee05cb2015-02-03 10:46:55 -030049 struct v4l2_fh fh;
Mike Iselyd8554972006-06-26 20:58:46 -030050 struct pvr2_channel channel;
Joe Perches108bdd72010-04-05 16:05:39 -030051 struct pvr2_v4l2_dev *pdi;
Mike Iselyd8554972006-06-26 20:58:46 -030052 struct pvr2_ioread *rhp;
53 struct file *file;
Mike Iselyd8554972006-06-26 20:58:46 -030054 wait_queue_head_t wait_data;
55 int fw_mode_flag;
Mike Iselye57b1c82008-04-21 03:52:34 -030056 /* Map contiguous ordinal value to input id */
57 unsigned char *input_map;
58 unsigned int input_cnt;
Mike Iselyd8554972006-06-26 20:58:46 -030059};
60
61struct pvr2_v4l2 {
62 struct pvr2_channel channel;
Mike Iselyd8554972006-06-26 20:58:46 -030063
Mike Isely0f0f257b2006-12-27 23:19:42 -030064 /* streams - Note that these must be separately, individually,
65 * allocated pointers. This is because the v4l core is going to
66 * manage their deletion - separately, individually... */
67 struct pvr2_v4l2_dev *dev_video;
68 struct pvr2_v4l2_dev *dev_radio;
Mike Iselyd8554972006-06-26 20:58:46 -030069};
70
71static int video_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
72module_param_array(video_nr, int, NULL, 0444);
Mike Isely5e6862c2006-12-27 23:17:26 -030073MODULE_PARM_DESC(video_nr, "Offset for device's video dev minor");
74static int radio_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
75module_param_array(radio_nr, int, NULL, 0444);
76MODULE_PARM_DESC(radio_nr, "Offset for device's radio dev minor");
77static int vbi_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
78module_param_array(vbi_nr, int, NULL, 0444);
79MODULE_PARM_DESC(vbi_nr, "Offset for device's vbi dev minor");
Mike Iselyd8554972006-06-26 20:58:46 -030080
Mike Iselyd8554972006-06-26 20:58:46 -030081#define PVR_FORMAT_PIX 0
82#define PVR_FORMAT_VBI 1
83
Adrian Bunk07e337e2006-06-30 11:30:20 -030084static struct v4l2_format pvr_format [] = {
Mike Iselyd8554972006-06-26 20:58:46 -030085 [PVR_FORMAT_PIX] = {
86 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
87 .fmt = {
88 .pix = {
89 .width = 720,
Hans Verkuilc4b72ee2017-12-13 18:44:42 -050090 .height = 576,
91 .pixelformat = V4L2_PIX_FMT_MPEG,
Mike Iselyd8554972006-06-26 20:58:46 -030092 .field = V4L2_FIELD_INTERLACED,
Hans Verkuilc4b72ee2017-12-13 18:44:42 -050093 /* FIXME : Don't know what to put here... */
94 .sizeimage = 32 * 1024,
Mike Iselyd8554972006-06-26 20:58:46 -030095 }
96 }
97 },
98 [PVR_FORMAT_VBI] = {
99 .type = V4L2_BUF_TYPE_VBI_CAPTURE,
100 .fmt = {
101 .vbi = {
102 .sampling_rate = 27000000,
103 .offset = 248,
104 .samples_per_line = 1443,
105 .sample_format = V4L2_PIX_FMT_GREY,
106 .start = { 0, 0 },
107 .count = { 0, 0 },
108 .flags = 0,
Mike Iselyd8554972006-06-26 20:58:46 -0300109 }
110 }
111 }
112};
113
Mike Isely16eb40d2006-12-30 18:27:32 -0300114
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300115
Mike Iselyd8554972006-06-26 20:58:46 -0300116/*
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300117 * This is part of Video 4 Linux API. These procedures handle ioctl() calls.
Mike Iselyd8554972006-06-26 20:58:46 -0300118 */
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300119static int pvr2_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
120{
121 struct pvr2_v4l2_fh *fh = file->private_data;
122 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
123
Mauro Carvalho Chehabc0decac2018-09-10 08:19:14 -0400124 strscpy(cap->driver, "pvrusb2", sizeof(cap->driver));
125 strscpy(cap->bus_info, pvr2_hdw_get_bus_info(hdw),
126 sizeof(cap->bus_info));
127 strscpy(cap->card, pvr2_hdw_get_desc(hdw), sizeof(cap->card));
Hans Verkuil42639f62015-01-19 06:23:26 -0300128 cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER |
129 V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
130 V4L2_CAP_READWRITE | V4L2_CAP_DEVICE_CAPS;
131 switch (fh->pdi->devbase.vfl_type) {
132 case VFL_TYPE_GRABBER:
133 cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO;
134 break;
135 case VFL_TYPE_RADIO:
136 cap->device_caps = V4L2_CAP_RADIO;
137 break;
Mauro Carvalho Chehab4839c582017-09-28 18:39:32 -0400138 default:
139 return -EINVAL;
Hans Verkuil42639f62015-01-19 06:23:26 -0300140 }
141 cap->device_caps |= V4L2_CAP_TUNER | V4L2_CAP_READWRITE;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300142 return 0;
143}
144
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300145static int pvr2_g_std(struct file *file, void *priv, v4l2_std_id *std)
146{
147 struct pvr2_v4l2_fh *fh = file->private_data;
Mike Iselyd8554972006-06-26 20:58:46 -0300148 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300149 int val = 0;
150 int ret;
Mike Iselyd8554972006-06-26 20:58:46 -0300151
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300152 ret = pvr2_ctrl_get_value(
153 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_STDCUR), &val);
154 *std = val;
155 return ret;
156}
Mike Iselyd8554972006-06-26 20:58:46 -0300157
Hans Verkuil314527a2013-03-15 06:10:40 -0300158static int pvr2_s_std(struct file *file, void *priv, v4l2_std_id std)
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300159{
160 struct pvr2_v4l2_fh *fh = file->private_data;
161 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
Hans Verkuileba09b52018-05-24 16:35:01 -0400162 int ret;
Mike Iselyd8554972006-06-26 20:58:46 -0300163
Hans Verkuileba09b52018-05-24 16:35:01 -0400164 ret = pvr2_ctrl_set_value(
Hans Verkuil314527a2013-03-15 06:10:40 -0300165 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_STDCUR), std);
Hans Verkuileba09b52018-05-24 16:35:01 -0400166 pvr2_hdw_commit_ctl(hdw);
167 return ret;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300168}
Mike Iselyd8554972006-06-26 20:58:46 -0300169
Mike Isely0927ee62012-02-20 02:26:06 -0300170static int pvr2_querystd(struct file *file, void *priv, v4l2_std_id *std)
171{
172 struct pvr2_v4l2_fh *fh = file->private_data;
173 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
Mike Iselyac04d002012-02-20 02:28:56 -0300174 int val = 0;
175 int ret;
Mike Isely0927ee62012-02-20 02:26:06 -0300176
Mike Iselyac04d002012-02-20 02:28:56 -0300177 ret = pvr2_ctrl_get_value(
178 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_STDDETECT), &val);
179 *std = val;
180 return ret;
Mike Isely0927ee62012-02-20 02:26:06 -0300181}
182
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300183static int pvr2_enum_input(struct file *file, void *priv, struct v4l2_input *vi)
184{
185 struct pvr2_v4l2_fh *fh = file->private_data;
186 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
187 struct pvr2_ctrl *cptr;
188 struct v4l2_input tmp;
189 unsigned int cnt;
190 int val;
Mike Iselyd8554972006-06-26 20:58:46 -0300191
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300192 cptr = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_INPUT);
Mike Iselyd8554972006-06-26 20:58:46 -0300193
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300194 memset(&tmp, 0, sizeof(tmp));
195 tmp.index = vi->index;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300196 if (vi->index >= fh->input_cnt)
197 return -EINVAL;
198 val = fh->input_map[vi->index];
199 switch (val) {
200 case PVR2_CVAL_INPUT_TV:
201 case PVR2_CVAL_INPUT_DTV:
202 case PVR2_CVAL_INPUT_RADIO:
203 tmp.type = V4L2_INPUT_TYPE_TUNER;
Mike Iselyd8554972006-06-26 20:58:46 -0300204 break;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300205 case PVR2_CVAL_INPUT_SVIDEO:
206 case PVR2_CVAL_INPUT_COMPOSITE:
207 tmp.type = V4L2_INPUT_TYPE_CAMERA;
Mike Iselyd8554972006-06-26 20:58:46 -0300208 break;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300209 default:
210 return -EINVAL;
Mike Iselyd8554972006-06-26 20:58:46 -0300211 }
212
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300213 cnt = 0;
214 pvr2_ctrl_get_valname(cptr, val,
215 tmp.name, sizeof(tmp.name) - 1, &cnt);
216 tmp.name[cnt] = 0;
Mike Iselyd8554972006-06-26 20:58:46 -0300217
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300218 /* Don't bother with audioset, since this driver currently
219 always switches the audio whenever the video is
220 switched. */
Mike Iselyd8554972006-06-26 20:58:46 -0300221
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300222 /* Handling std is a tougher problem. It doesn't make
223 sense in cases where a device might be multi-standard.
224 We could just copy out the current value for the
225 standard, but it can change over time. For now just
226 leave it zero. */
227 *vi = tmp;
228 return 0;
229}
Mike Iselyd8554972006-06-26 20:58:46 -0300230
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300231static int pvr2_g_input(struct file *file, void *priv, unsigned int *i)
232{
233 struct pvr2_v4l2_fh *fh = file->private_data;
234 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
235 unsigned int idx;
236 struct pvr2_ctrl *cptr;
237 int val;
238 int ret;
Mauro Carvalho Chehab7383a472011-10-03 12:22:28 -0300239
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300240 cptr = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_INPUT);
241 val = 0;
242 ret = pvr2_ctrl_get_value(cptr, &val);
243 *i = 0;
244 for (idx = 0; idx < fh->input_cnt; idx++) {
245 if (fh->input_map[idx] == val) {
246 *i = idx;
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300247 break;
248 }
Mike Iselyd8554972006-06-26 20:58:46 -0300249 }
250 return ret;
251}
252
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300253static int pvr2_s_input(struct file *file, void *priv, unsigned int inp)
254{
255 struct pvr2_v4l2_fh *fh = file->private_data;
256 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
Hans Verkuileba09b52018-05-24 16:35:01 -0400257 int ret;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300258
259 if (inp >= fh->input_cnt)
260 return -EINVAL;
Hans Verkuileba09b52018-05-24 16:35:01 -0400261 ret = pvr2_ctrl_set_value(
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300262 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_INPUT),
263 fh->input_map[inp]);
Hans Verkuileba09b52018-05-24 16:35:01 -0400264 pvr2_hdw_commit_ctl(hdw);
265 return ret;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300266}
267
268static int pvr2_enumaudio(struct file *file, void *priv, struct v4l2_audio *vin)
269{
270 /* pkt: FIXME: We are returning one "fake" input here
271 which could very well be called "whatever_we_like".
272 This is for apps that want to see an audio input
273 just to feel comfortable, as well as to test if
274 it can do stereo or sth. There is actually no guarantee
275 that the actual audio input cannot change behind the app's
276 back, but most applications should not mind that either.
277
278 Hopefully, mplayer people will work with us on this (this
279 whole mess is to support mplayer pvr://), or Hans will come
280 up with a more standard way to say "we have inputs but we
281 don 't want you to change them independent of video" which
282 will sort this mess.
283 */
284
285 if (vin->index > 0)
286 return -EINVAL;
287 strncpy(vin->name, "PVRUSB2 Audio", 14);
288 vin->capability = V4L2_AUDCAP_STEREO;
289 return 0;
290}
291
292static int pvr2_g_audio(struct file *file, void *priv, struct v4l2_audio *vin)
293{
294 /* pkt: FIXME: see above comment (VIDIOC_ENUMAUDIO) */
295 vin->index = 0;
296 strncpy(vin->name, "PVRUSB2 Audio", 14);
297 vin->capability = V4L2_AUDCAP_STEREO;
298 return 0;
299}
300
Hans Verkuil0e8025b92012-09-04 11:59:31 -0300301static int pvr2_s_audio(struct file *file, void *priv, const struct v4l2_audio *vout)
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300302{
303 if (vout->index)
304 return -EINVAL;
305 return 0;
306}
307
308static int pvr2_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt)
309{
310 struct pvr2_v4l2_fh *fh = file->private_data;
311 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
312
313 if (vt->index != 0)
314 return -EINVAL; /* Only answer for the 1st tuner */
315
316 pvr2_hdw_execute_tuner_poll(hdw);
317 return pvr2_hdw_get_tuner_status(hdw, vt);
318}
319
Hans Verkuil2f73c7c2013-03-15 06:10:06 -0300320static int pvr2_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *vt)
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300321{
322 struct pvr2_v4l2_fh *fh = file->private_data;
323 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
Hans Verkuileba09b52018-05-24 16:35:01 -0400324 int ret;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300325
326 if (vt->index != 0)
327 return -EINVAL;
328
Hans Verkuileba09b52018-05-24 16:35:01 -0400329 ret = pvr2_ctrl_set_value(
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300330 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_AUDIOMODE),
331 vt->audmode);
Hans Verkuileba09b52018-05-24 16:35:01 -0400332 pvr2_hdw_commit_ctl(hdw);
333 return ret;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300334}
335
Hans Verkuilb530a442013-03-19 04:09:26 -0300336static int pvr2_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *vf)
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300337{
338 struct pvr2_v4l2_fh *fh = file->private_data;
339 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
340 unsigned long fv;
341 struct v4l2_tuner vt;
342 int cur_input;
343 struct pvr2_ctrl *ctrlp;
344 int ret;
345
346 ret = pvr2_hdw_get_tuner_status(hdw, &vt);
347 if (ret != 0)
348 return ret;
349 ctrlp = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_INPUT);
350 ret = pvr2_ctrl_get_value(ctrlp, &cur_input);
351 if (ret != 0)
352 return ret;
353 if (vf->type == V4L2_TUNER_RADIO) {
354 if (cur_input != PVR2_CVAL_INPUT_RADIO)
355 pvr2_ctrl_set_value(ctrlp, PVR2_CVAL_INPUT_RADIO);
356 } else {
357 if (cur_input == PVR2_CVAL_INPUT_RADIO)
358 pvr2_ctrl_set_value(ctrlp, PVR2_CVAL_INPUT_TV);
359 }
360 fv = vf->frequency;
361 if (vt.capability & V4L2_TUNER_CAP_LOW)
362 fv = (fv * 125) / 2;
363 else
364 fv = fv * 62500;
Hans Verkuileba09b52018-05-24 16:35:01 -0400365 ret = pvr2_ctrl_set_value(
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300366 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),fv);
Hans Verkuileba09b52018-05-24 16:35:01 -0400367 pvr2_hdw_commit_ctl(hdw);
368 return ret;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300369}
370
371static int pvr2_g_frequency(struct file *file, void *priv, struct v4l2_frequency *vf)
372{
373 struct pvr2_v4l2_fh *fh = file->private_data;
374 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
375 int val = 0;
376 int cur_input;
377 struct v4l2_tuner vt;
378 int ret;
379
380 ret = pvr2_hdw_get_tuner_status(hdw, &vt);
381 if (ret != 0)
382 return ret;
383 ret = pvr2_ctrl_get_value(
384 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_FREQUENCY),
385 &val);
386 if (ret != 0)
387 return ret;
388 pvr2_ctrl_get_value(
389 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_INPUT),
390 &cur_input);
391 if (cur_input == PVR2_CVAL_INPUT_RADIO)
392 vf->type = V4L2_TUNER_RADIO;
393 else
394 vf->type = V4L2_TUNER_ANALOG_TV;
395 if (vt.capability & V4L2_TUNER_CAP_LOW)
396 val = (val * 2) / 125;
397 else
398 val /= 62500;
399 vf->frequency = val;
400 return 0;
401}
402
403static int pvr2_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *fd)
404{
Hans Verkuilc4b72ee2017-12-13 18:44:42 -0500405 /* Only one format is supported: MPEG. */
406 if (fd->index)
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300407 return -EINVAL;
408
Hans Verkuilc4b72ee2017-12-13 18:44:42 -0500409 fd->pixelformat = V4L2_PIX_FMT_MPEG;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300410 return 0;
411}
412
413static int pvr2_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf)
414{
415 struct pvr2_v4l2_fh *fh = file->private_data;
416 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
417 int val;
418
419 memcpy(vf, &pvr_format[PVR_FORMAT_PIX], sizeof(struct v4l2_format));
420 val = 0;
421 pvr2_ctrl_get_value(
422 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_HRES),
423 &val);
424 vf->fmt.pix.width = val;
425 val = 0;
426 pvr2_ctrl_get_value(
427 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_VRES),
428 &val);
429 vf->fmt.pix.height = val;
430 return 0;
431}
432
433static int pvr2_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf)
434{
435 struct pvr2_v4l2_fh *fh = file->private_data;
436 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
437 int lmin, lmax, ldef;
438 struct pvr2_ctrl *hcp, *vcp;
439 int h = vf->fmt.pix.height;
440 int w = vf->fmt.pix.width;
441
442 hcp = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_HRES);
443 vcp = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_VRES);
444
445 lmin = pvr2_ctrl_get_min(hcp);
446 lmax = pvr2_ctrl_get_max(hcp);
447 pvr2_ctrl_get_def(hcp, &ldef);
448 if (w == -1)
449 w = ldef;
450 else if (w < lmin)
451 w = lmin;
452 else if (w > lmax)
453 w = lmax;
454 lmin = pvr2_ctrl_get_min(vcp);
455 lmax = pvr2_ctrl_get_max(vcp);
456 pvr2_ctrl_get_def(vcp, &ldef);
457 if (h == -1)
458 h = ldef;
459 else if (h < lmin)
460 h = lmin;
461 else if (h > lmax)
462 h = lmax;
463
464 memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
465 sizeof(struct v4l2_format));
466 vf->fmt.pix.width = w;
467 vf->fmt.pix.height = h;
468 return 0;
469}
470
471static int pvr2_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf)
472{
473 struct pvr2_v4l2_fh *fh = file->private_data;
474 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
475 struct pvr2_ctrl *hcp, *vcp;
476 int ret = pvr2_try_fmt_vid_cap(file, fh, vf);
477
478 if (ret)
479 return ret;
480 hcp = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_HRES);
481 vcp = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_VRES);
482 pvr2_ctrl_set_value(hcp, vf->fmt.pix.width);
483 pvr2_ctrl_set_value(vcp, vf->fmt.pix.height);
Hans Verkuileba09b52018-05-24 16:35:01 -0400484 pvr2_hdw_commit_ctl(hdw);
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300485 return 0;
486}
487
488static int pvr2_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
489{
490 struct pvr2_v4l2_fh *fh = file->private_data;
491 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
492 struct pvr2_v4l2_dev *pdi = fh->pdi;
493 int ret;
494
495 if (!fh->pdi->stream) {
496 /* No stream defined for this node. This means
497 that we're not currently allowed to stream from
498 this node. */
499 return -EPERM;
500 }
501 ret = pvr2_hdw_set_stream_type(hdw, pdi->config);
502 if (ret < 0)
503 return ret;
504 return pvr2_hdw_set_streaming(hdw, !0);
505}
506
507static int pvr2_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
508{
509 struct pvr2_v4l2_fh *fh = file->private_data;
510 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
511
512 if (!fh->pdi->stream) {
513 /* No stream defined for this node. This means
514 that we're not currently allowed to stream from
515 this node. */
516 return -EPERM;
517 }
518 return pvr2_hdw_set_streaming(hdw, 0);
519}
520
521static int pvr2_queryctrl(struct file *file, void *priv,
522 struct v4l2_queryctrl *vc)
523{
524 struct pvr2_v4l2_fh *fh = file->private_data;
525 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
526 struct pvr2_ctrl *cptr;
527 int val;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300528
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300529 if (vc->id & V4L2_CTRL_FLAG_NEXT_CTRL) {
530 cptr = pvr2_hdw_get_ctrl_nextv4l(
531 hdw, (vc->id & ~V4L2_CTRL_FLAG_NEXT_CTRL));
532 if (cptr)
533 vc->id = pvr2_ctrl_get_v4lid(cptr);
534 } else {
535 cptr = pvr2_hdw_get_ctrl_v4l(hdw, vc->id);
536 }
537 if (!cptr) {
538 pvr2_trace(PVR2_TRACE_V4LIOCTL,
539 "QUERYCTRL id=0x%x not implemented here",
540 vc->id);
541 return -EINVAL;
542 }
543
544 pvr2_trace(PVR2_TRACE_V4LIOCTL,
545 "QUERYCTRL id=0x%x mapping name=%s (%s)",
546 vc->id, pvr2_ctrl_get_name(cptr),
547 pvr2_ctrl_get_desc(cptr));
Mauro Carvalho Chehabc0decac2018-09-10 08:19:14 -0400548 strscpy(vc->name, pvr2_ctrl_get_desc(cptr), sizeof(vc->name));
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300549 vc->flags = pvr2_ctrl_get_v4lflags(cptr);
550 pvr2_ctrl_get_def(cptr, &val);
551 vc->default_value = val;
552 switch (pvr2_ctrl_get_type(cptr)) {
553 case pvr2_ctl_enum:
554 vc->type = V4L2_CTRL_TYPE_MENU;
555 vc->minimum = 0;
556 vc->maximum = pvr2_ctrl_get_cnt(cptr) - 1;
557 vc->step = 1;
558 break;
559 case pvr2_ctl_bool:
560 vc->type = V4L2_CTRL_TYPE_BOOLEAN;
561 vc->minimum = 0;
562 vc->maximum = 1;
563 vc->step = 1;
564 break;
565 case pvr2_ctl_int:
566 vc->type = V4L2_CTRL_TYPE_INTEGER;
567 vc->minimum = pvr2_ctrl_get_min(cptr);
568 vc->maximum = pvr2_ctrl_get_max(cptr);
569 vc->step = 1;
570 break;
571 default:
572 pvr2_trace(PVR2_TRACE_V4LIOCTL,
573 "QUERYCTRL id=0x%x name=%s not mappable",
574 vc->id, pvr2_ctrl_get_name(cptr));
575 return -EINVAL;
576 }
577 return 0;
578}
579
580static int pvr2_querymenu(struct file *file, void *priv, struct v4l2_querymenu *vm)
581{
582 struct pvr2_v4l2_fh *fh = file->private_data;
583 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
584 unsigned int cnt = 0;
585 int ret;
586
587 ret = pvr2_ctrl_get_valname(pvr2_hdw_get_ctrl_v4l(hdw, vm->id),
588 vm->index,
589 vm->name, sizeof(vm->name) - 1,
590 &cnt);
591 vm->name[cnt] = 0;
592 return ret;
593}
594
595static int pvr2_g_ctrl(struct file *file, void *priv, struct v4l2_control *vc)
596{
597 struct pvr2_v4l2_fh *fh = file->private_data;
598 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
599 int val = 0;
600 int ret;
601
602 ret = pvr2_ctrl_get_value(pvr2_hdw_get_ctrl_v4l(hdw, vc->id),
603 &val);
604 vc->value = val;
605 return ret;
606}
607
608static int pvr2_s_ctrl(struct file *file, void *priv, struct v4l2_control *vc)
609{
610 struct pvr2_v4l2_fh *fh = file->private_data;
611 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
Hans Verkuileba09b52018-05-24 16:35:01 -0400612 int ret;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300613
Hans Verkuileba09b52018-05-24 16:35:01 -0400614 ret = pvr2_ctrl_set_value(pvr2_hdw_get_ctrl_v4l(hdw, vc->id),
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300615 vc->value);
Hans Verkuileba09b52018-05-24 16:35:01 -0400616 pvr2_hdw_commit_ctl(hdw);
617 return ret;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300618}
619
620static int pvr2_g_ext_ctrls(struct file *file, void *priv,
621 struct v4l2_ext_controls *ctls)
622{
623 struct pvr2_v4l2_fh *fh = file->private_data;
624 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
625 struct v4l2_ext_control *ctrl;
Ricardo Ribalda082afb72015-10-29 08:10:31 -0200626 struct pvr2_ctrl *cptr;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300627 unsigned int idx;
628 int val;
629 int ret;
630
631 ret = 0;
632 for (idx = 0; idx < ctls->count; idx++) {
633 ctrl = ctls->controls + idx;
Ricardo Ribalda082afb72015-10-29 08:10:31 -0200634 cptr = pvr2_hdw_get_ctrl_v4l(hdw, ctrl->id);
635 if (cptr) {
636 if (ctls->which == V4L2_CTRL_WHICH_DEF_VAL)
637 pvr2_ctrl_get_def(cptr, &val);
638 else
639 ret = pvr2_ctrl_get_value(cptr, &val);
640 } else
641 ret = -EINVAL;
642
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300643 if (ret) {
644 ctls->error_idx = idx;
645 return ret;
646 }
647 /* Ensure that if read as a 64 bit value, the user
648 will still get a hopefully sane value */
649 ctrl->value64 = 0;
650 ctrl->value = val;
651 }
652 return 0;
653}
654
655static int pvr2_s_ext_ctrls(struct file *file, void *priv,
656 struct v4l2_ext_controls *ctls)
657{
658 struct pvr2_v4l2_fh *fh = file->private_data;
659 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
660 struct v4l2_ext_control *ctrl;
661 unsigned int idx;
662 int ret;
663
Ricardo Ribalda082afb72015-10-29 08:10:31 -0200664 /* Default value cannot be changed */
665 if (ctls->which == V4L2_CTRL_WHICH_DEF_VAL)
666 return -EINVAL;
667
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300668 ret = 0;
669 for (idx = 0; idx < ctls->count; idx++) {
670 ctrl = ctls->controls + idx;
671 ret = pvr2_ctrl_set_value(
672 pvr2_hdw_get_ctrl_v4l(hdw, ctrl->id),
673 ctrl->value);
674 if (ret) {
675 ctls->error_idx = idx;
Hans Verkuileba09b52018-05-24 16:35:01 -0400676 goto commit;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300677 }
678 }
Hans Verkuileba09b52018-05-24 16:35:01 -0400679commit:
680 pvr2_hdw_commit_ctl(hdw);
681 return ret;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300682}
683
684static int pvr2_try_ext_ctrls(struct file *file, void *priv,
685 struct v4l2_ext_controls *ctls)
686{
687 struct pvr2_v4l2_fh *fh = file->private_data;
688 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
689 struct v4l2_ext_control *ctrl;
690 struct pvr2_ctrl *pctl;
691 unsigned int idx;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300692
693 /* For the moment just validate that the requested control
694 actually exists. */
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300695 for (idx = 0; idx < ctls->count; idx++) {
696 ctrl = ctls->controls + idx;
697 pctl = pvr2_hdw_get_ctrl_v4l(hdw, ctrl->id);
698 if (!pctl) {
699 ctls->error_idx = idx;
700 return -EINVAL;
701 }
702 }
703 return 0;
704}
705
706static int pvr2_cropcap(struct file *file, void *priv, struct v4l2_cropcap *cap)
707{
708 struct pvr2_v4l2_fh *fh = file->private_data;
709 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
710 int ret;
711
712 if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
713 return -EINVAL;
714 ret = pvr2_hdw_get_cropcap(hdw, cap);
715 cap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* paranoia */
716 return ret;
717}
718
Hans Verkuil1f981a42016-07-03 08:14:17 -0300719static int pvr2_g_selection(struct file *file, void *priv,
720 struct v4l2_selection *sel)
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300721{
722 struct pvr2_v4l2_fh *fh = file->private_data;
723 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
Hans Verkuil1f981a42016-07-03 08:14:17 -0300724 struct v4l2_cropcap cap;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300725 int val = 0;
726 int ret;
727
Hans Verkuil1f981a42016-07-03 08:14:17 -0300728 if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300729 return -EINVAL;
Hans Verkuil1f981a42016-07-03 08:14:17 -0300730
731 cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
732
733 switch (sel->target) {
734 case V4L2_SEL_TGT_CROP:
735 ret = pvr2_ctrl_get_value(
736 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL), &val);
737 if (ret != 0)
738 return -EINVAL;
739 sel->r.left = val;
740 ret = pvr2_ctrl_get_value(
741 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT), &val);
742 if (ret != 0)
743 return -EINVAL;
744 sel->r.top = val;
745 ret = pvr2_ctrl_get_value(
746 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW), &val);
747 if (ret != 0)
748 return -EINVAL;
749 sel->r.width = val;
750 ret = pvr2_ctrl_get_value(
751 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH), &val);
752 if (ret != 0)
753 return -EINVAL;
754 sel->r.height = val;
755 break;
756 case V4L2_SEL_TGT_CROP_DEFAULT:
757 ret = pvr2_hdw_get_cropcap(hdw, &cap);
758 sel->r = cap.defrect;
759 break;
760 case V4L2_SEL_TGT_CROP_BOUNDS:
761 ret = pvr2_hdw_get_cropcap(hdw, &cap);
762 sel->r = cap.bounds;
763 break;
764 default:
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300765 return -EINVAL;
Hans Verkuil1f981a42016-07-03 08:14:17 -0300766 }
767 return ret;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300768}
769
Hans Verkuil1f981a42016-07-03 08:14:17 -0300770static int pvr2_s_selection(struct file *file, void *priv,
771 struct v4l2_selection *sel)
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300772{
773 struct pvr2_v4l2_fh *fh = file->private_data;
774 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300775 int ret;
776
Hans Verkuil1f981a42016-07-03 08:14:17 -0300777 if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
778 sel->target != V4L2_SEL_TGT_CROP)
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300779 return -EINVAL;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300780 ret = pvr2_ctrl_set_value(
781 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL),
Hans Verkuil1f981a42016-07-03 08:14:17 -0300782 sel->r.left);
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300783 if (ret != 0)
Hans Verkuileba09b52018-05-24 16:35:01 -0400784 goto commit;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300785 ret = pvr2_ctrl_set_value(
786 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT),
Hans Verkuil1f981a42016-07-03 08:14:17 -0300787 sel->r.top);
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300788 if (ret != 0)
Hans Verkuileba09b52018-05-24 16:35:01 -0400789 goto commit;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300790 ret = pvr2_ctrl_set_value(
791 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW),
Hans Verkuil1f981a42016-07-03 08:14:17 -0300792 sel->r.width);
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300793 if (ret != 0)
Hans Verkuileba09b52018-05-24 16:35:01 -0400794 goto commit;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300795 ret = pvr2_ctrl_set_value(
796 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH),
Hans Verkuil1f981a42016-07-03 08:14:17 -0300797 sel->r.height);
Hans Verkuileba09b52018-05-24 16:35:01 -0400798commit:
799 pvr2_hdw_commit_ctl(hdw);
800 return ret;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300801}
802
803static int pvr2_log_status(struct file *file, void *priv)
804{
805 struct pvr2_v4l2_fh *fh = file->private_data;
806 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
807
808 pvr2_hdw_trigger_module_log(hdw);
809 return 0;
810}
811
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300812static const struct v4l2_ioctl_ops pvr2_ioctl_ops = {
813 .vidioc_querycap = pvr2_querycap,
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300814 .vidioc_s_audio = pvr2_s_audio,
815 .vidioc_g_audio = pvr2_g_audio,
816 .vidioc_enumaudio = pvr2_enumaudio,
817 .vidioc_enum_input = pvr2_enum_input,
818 .vidioc_cropcap = pvr2_cropcap,
Hans Verkuil1f981a42016-07-03 08:14:17 -0300819 .vidioc_s_selection = pvr2_s_selection,
820 .vidioc_g_selection = pvr2_g_selection,
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300821 .vidioc_g_input = pvr2_g_input,
822 .vidioc_s_input = pvr2_s_input,
823 .vidioc_g_frequency = pvr2_g_frequency,
824 .vidioc_s_frequency = pvr2_s_frequency,
825 .vidioc_s_tuner = pvr2_s_tuner,
826 .vidioc_g_tuner = pvr2_g_tuner,
827 .vidioc_g_std = pvr2_g_std,
828 .vidioc_s_std = pvr2_s_std,
Mike Isely0927ee62012-02-20 02:26:06 -0300829 .vidioc_querystd = pvr2_querystd,
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300830 .vidioc_log_status = pvr2_log_status,
831 .vidioc_enum_fmt_vid_cap = pvr2_enum_fmt_vid_cap,
832 .vidioc_g_fmt_vid_cap = pvr2_g_fmt_vid_cap,
833 .vidioc_s_fmt_vid_cap = pvr2_s_fmt_vid_cap,
834 .vidioc_try_fmt_vid_cap = pvr2_try_fmt_vid_cap,
835 .vidioc_streamon = pvr2_streamon,
836 .vidioc_streamoff = pvr2_streamoff,
837 .vidioc_queryctrl = pvr2_queryctrl,
838 .vidioc_querymenu = pvr2_querymenu,
839 .vidioc_g_ctrl = pvr2_g_ctrl,
840 .vidioc_s_ctrl = pvr2_s_ctrl,
841 .vidioc_g_ext_ctrls = pvr2_g_ext_ctrls,
842 .vidioc_s_ext_ctrls = pvr2_s_ext_ctrls,
843 .vidioc_try_ext_ctrls = pvr2_try_ext_ctrls,
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300844};
845
Mike Iselyd8554972006-06-26 20:58:46 -0300846static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
847{
Mike Isely0f0f257b2006-12-27 23:19:42 -0300848 struct pvr2_hdw *hdw = dip->v4lp->channel.mc_head->hdw;
Mike Isely16eb40d2006-12-30 18:27:32 -0300849 enum pvr2_config cfg = dip->config;
Mike Iselyd72baad2010-05-15 00:15:38 -0300850 char msg[80];
851 unsigned int mcnt;
852
853 /* Construct the unregistration message *before* we actually
854 perform the unregistration step. By doing it this way we don't
855 have to worry about potentially touching deleted resources. */
856 mcnt = scnprintf(msg, sizeof(msg) - 1,
857 "pvrusb2: unregistered device %s [%s]",
858 video_device_node_name(&dip->devbase),
859 pvr2_config_get_name(cfg));
860 msg[mcnt] = 0;
Mike Isely0f0f257b2006-12-27 23:19:42 -0300861
Mike Isely16eb40d2006-12-30 18:27:32 -0300862 pvr2_hdw_v4l_store_minor_number(hdw,dip->minor_type,-1);
Mike Isely75910052006-09-23 22:30:50 -0300863
864 /* Paranoia */
Randy Dunlapc2625bf2006-10-29 11:12:27 -0300865 dip->v4lp = NULL;
866 dip->stream = NULL;
Mike Isely75910052006-09-23 22:30:50 -0300867
868 /* Actual deallocation happens later when all internal references
869 are gone. */
870 video_unregister_device(&dip->devbase);
Mike Isely0f0f257b2006-12-27 23:19:42 -0300871
Mike Iselyd72baad2010-05-15 00:15:38 -0300872 printk(KERN_INFO "%s\n", msg);
Mike Isely0f0f257b2006-12-27 23:19:42 -0300873
Mike Iselyd8554972006-06-26 20:58:46 -0300874}
875
876
Mike Isely4a89baa2009-10-12 00:13:28 -0300877static void pvr2_v4l2_dev_disassociate_parent(struct pvr2_v4l2_dev *dip)
878{
879 if (!dip) return;
Hans Verkuila28fbd02013-06-10 09:16:25 -0300880 if (!dip->devbase.v4l2_dev->dev) return;
881 dip->devbase.v4l2_dev->dev = NULL;
Mike Isely4a89baa2009-10-12 00:13:28 -0300882 device_move(&dip->devbase.dev, NULL, DPM_ORDER_NONE);
883}
884
885
Mike Iselyd8554972006-06-26 20:58:46 -0300886static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp)
887{
Mike Isely0f0f257b2006-12-27 23:19:42 -0300888 if (vp->dev_video) {
889 pvr2_v4l2_dev_destroy(vp->dev_video);
Al Viro89952d12007-03-14 09:17:59 +0000890 vp->dev_video = NULL;
Mike Isely0f0f257b2006-12-27 23:19:42 -0300891 }
892 if (vp->dev_radio) {
893 pvr2_v4l2_dev_destroy(vp->dev_radio);
Al Viro89952d12007-03-14 09:17:59 +0000894 vp->dev_radio = NULL;
Mike Isely0f0f257b2006-12-27 23:19:42 -0300895 }
Mike Iselyd8554972006-06-26 20:58:46 -0300896
897 pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp);
898 pvr2_channel_done(&vp->channel);
899 kfree(vp);
900}
901
902
Mike Isely75910052006-09-23 22:30:50 -0300903static void pvr2_video_device_release(struct video_device *vdev)
904{
905 struct pvr2_v4l2_dev *dev;
906 dev = container_of(vdev,struct pvr2_v4l2_dev,devbase);
907 kfree(dev);
908}
909
910
Adrian Bunk07e337e2006-06-30 11:30:20 -0300911static void pvr2_v4l2_internal_check(struct pvr2_channel *chp)
Mike Iselyd8554972006-06-26 20:58:46 -0300912{
913 struct pvr2_v4l2 *vp;
914 vp = container_of(chp,struct pvr2_v4l2,channel);
915 if (!vp->channel.mc_head->disconnect_flag) return;
Mike Isely4a89baa2009-10-12 00:13:28 -0300916 pvr2_v4l2_dev_disassociate_parent(vp->dev_video);
917 pvr2_v4l2_dev_disassociate_parent(vp->dev_radio);
Hans Verkuilcee05cb2015-02-03 10:46:55 -0300918 if (!list_empty(&vp->dev_video->devbase.fh_list) ||
919 !list_empty(&vp->dev_radio->devbase.fh_list))
920 return;
Mike Iselyd8554972006-06-26 20:58:46 -0300921 pvr2_v4l2_destroy_no_lock(vp);
922}
923
924
Hans Verkuilbec43662008-12-30 06:58:20 -0300925static int pvr2_v4l2_release(struct file *file)
Mike Iselyd8554972006-06-26 20:58:46 -0300926{
927 struct pvr2_v4l2_fh *fhp = file->private_data;
Hans Verkuilcee05cb2015-02-03 10:46:55 -0300928 struct pvr2_v4l2 *vp = fhp->pdi->v4lp;
Mike Iselyc74e0062006-12-30 18:31:22 -0300929 struct pvr2_hdw *hdw = fhp->channel.mc_head->hdw;
Mike Iselyd8554972006-06-26 20:58:46 -0300930
931 pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_release");
932
933 if (fhp->rhp) {
934 struct pvr2_stream *sp;
Mike Iselyd8554972006-06-26 20:58:46 -0300935 pvr2_hdw_set_streaming(hdw,0);
936 sp = pvr2_ioread_get_stream(fhp->rhp);
Mike Iselya0fd1cb2006-06-30 11:35:28 -0300937 if (sp) pvr2_stream_set_callback(sp,NULL,NULL);
Mike Iselyd8554972006-06-26 20:58:46 -0300938 pvr2_ioread_destroy(fhp->rhp);
Mike Iselya0fd1cb2006-06-30 11:35:28 -0300939 fhp->rhp = NULL;
Mike Iselyd8554972006-06-26 20:58:46 -0300940 }
Pantelis Koukousoulasae2b9e22006-12-27 23:09:55 -0300941
Hans Verkuilcee05cb2015-02-03 10:46:55 -0300942 v4l2_fh_del(&fhp->fh);
943 v4l2_fh_exit(&fhp->fh);
Mike Iselyd8554972006-06-26 20:58:46 -0300944 file->private_data = NULL;
945
Mike Isely794b1602008-04-22 14:45:45 -0300946 pvr2_channel_done(&fhp->channel);
947 pvr2_trace(PVR2_TRACE_STRUCT,
948 "Destroying pvr_v4l2_fh id=%p",fhp);
Mike Iselye57b1c82008-04-21 03:52:34 -0300949 if (fhp->input_map) {
950 kfree(fhp->input_map);
951 fhp->input_map = NULL;
952 }
Mike Isely794b1602008-04-22 14:45:45 -0300953 kfree(fhp);
Hans Verkuilcee05cb2015-02-03 10:46:55 -0300954 if (vp->channel.mc_head->disconnect_flag &&
955 list_empty(&vp->dev_video->devbase.fh_list) &&
956 list_empty(&vp->dev_radio->devbase.fh_list)) {
Mike Isely794b1602008-04-22 14:45:45 -0300957 pvr2_v4l2_destroy_no_lock(vp);
958 }
Mike Iselyd8554972006-06-26 20:58:46 -0300959 return 0;
960}
961
962
Hans Verkuilbec43662008-12-30 06:58:20 -0300963static int pvr2_v4l2_open(struct file *file)
Mike Iselyd8554972006-06-26 20:58:46 -0300964{
Mike Isely75910052006-09-23 22:30:50 -0300965 struct pvr2_v4l2_dev *dip; /* Our own context pointer */
Mike Iselyd8554972006-06-26 20:58:46 -0300966 struct pvr2_v4l2_fh *fhp;
967 struct pvr2_v4l2 *vp;
968 struct pvr2_hdw *hdw;
Mike Isely1cb03b72008-04-21 03:47:43 -0300969 unsigned int input_mask = 0;
Mike Iselye57b1c82008-04-21 03:52:34 -0300970 unsigned int input_cnt,idx;
Mike Isely1cb03b72008-04-21 03:47:43 -0300971 int ret = 0;
Mike Iselyd8554972006-06-26 20:58:46 -0300972
Mike Isely75910052006-09-23 22:30:50 -0300973 dip = container_of(video_devdata(file),struct pvr2_v4l2_dev,devbase);
Mike Iselyd8554972006-06-26 20:58:46 -0300974
975 vp = dip->v4lp;
976 hdw = vp->channel.hdw;
977
978 pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_open");
979
980 if (!pvr2_hdw_dev_ok(hdw)) {
981 pvr2_trace(PVR2_TRACE_OPEN_CLOSE,
982 "pvr2_v4l2_open: hardware not ready");
983 return -EIO;
984 }
985
Mike Isely4b85dee2007-01-20 00:03:32 -0300986 fhp = kzalloc(sizeof(*fhp),GFP_KERNEL);
Mike Iselyd8554972006-06-26 20:58:46 -0300987 if (!fhp) {
988 return -ENOMEM;
989 }
Mike Iselyd8554972006-06-26 20:58:46 -0300990
Hans Verkuilcee05cb2015-02-03 10:46:55 -0300991 v4l2_fh_init(&fhp->fh, &dip->devbase);
Mike Iselyd8554972006-06-26 20:58:46 -0300992 init_waitqueue_head(&fhp->wait_data);
Joe Perches108bdd72010-04-05 16:05:39 -0300993 fhp->pdi = dip;
Mike Iselyd8554972006-06-26 20:58:46 -0300994
Mike Isely794b1602008-04-22 14:45:45 -0300995 pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp);
996 pvr2_channel_init(&fhp->channel,vp->channel.mc_head);
Pantelis Koukousoulasae2b9e22006-12-27 23:09:55 -0300997
Mike Isely1cb03b72008-04-21 03:47:43 -0300998 if (dip->v4l_type == VFL_TYPE_RADIO) {
999 /* Opening device as a radio, legal input selection subset
1000 is just the radio. */
1001 input_mask = (1 << PVR2_CVAL_INPUT_RADIO);
1002 } else {
1003 /* Opening the main V4L device, legal input selection
1004 subset includes all analog inputs. */
1005 input_mask = ((1 << PVR2_CVAL_INPUT_RADIO) |
1006 (1 << PVR2_CVAL_INPUT_TV) |
1007 (1 << PVR2_CVAL_INPUT_COMPOSITE) |
1008 (1 << PVR2_CVAL_INPUT_SVIDEO));
1009 }
1010 ret = pvr2_channel_limit_inputs(&fhp->channel,input_mask);
1011 if (ret) {
1012 pvr2_channel_done(&fhp->channel);
1013 pvr2_trace(PVR2_TRACE_STRUCT,
1014 "Destroying pvr_v4l2_fh id=%p (input mask error)",
1015 fhp);
Santosh Kumar Singh01faa0d2016-12-19 15:20:37 -02001016 v4l2_fh_exit(&fhp->fh);
Mike Isely1cb03b72008-04-21 03:47:43 -03001017 kfree(fhp);
1018 return ret;
1019 }
1020
Mike Iselye57b1c82008-04-21 03:52:34 -03001021 input_mask &= pvr2_hdw_get_input_available(hdw);
1022 input_cnt = 0;
1023 for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) {
1024 if (input_mask & (1 << idx)) input_cnt++;
1025 }
1026 fhp->input_cnt = input_cnt;
1027 fhp->input_map = kzalloc(input_cnt,GFP_KERNEL);
1028 if (!fhp->input_map) {
1029 pvr2_channel_done(&fhp->channel);
1030 pvr2_trace(PVR2_TRACE_STRUCT,
1031 "Destroying pvr_v4l2_fh id=%p (input map failure)",
1032 fhp);
Santosh Kumar Singh01faa0d2016-12-19 15:20:37 -02001033 v4l2_fh_exit(&fhp->fh);
Mike Iselye57b1c82008-04-21 03:52:34 -03001034 kfree(fhp);
1035 return -ENOMEM;
1036 }
1037 input_cnt = 0;
1038 for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) {
1039 if (!(input_mask & (1 << idx))) continue;
1040 fhp->input_map[input_cnt++] = idx;
1041 }
1042
Mike Iselyd8554972006-06-26 20:58:46 -03001043 fhp->file = file;
1044 file->private_data = fhp;
Mike Iselyd8554972006-06-26 20:58:46 -03001045
1046 fhp->fw_mode_flag = pvr2_hdw_cpufw_get_enabled(hdw);
Hans Verkuilcee05cb2015-02-03 10:46:55 -03001047 v4l2_fh_add(&fhp->fh);
Mike Iselyd8554972006-06-26 20:58:46 -03001048
1049 return 0;
1050}
1051
1052
1053static void pvr2_v4l2_notify(struct pvr2_v4l2_fh *fhp)
1054{
1055 wake_up(&fhp->wait_data);
1056}
1057
1058static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh)
1059{
1060 int ret;
1061 struct pvr2_stream *sp;
1062 struct pvr2_hdw *hdw;
1063 if (fh->rhp) return 0;
1064
Joe Perches108bdd72010-04-05 16:05:39 -03001065 if (!fh->pdi->stream) {
Mike Isely16eb40d2006-12-30 18:27:32 -03001066 /* No stream defined for this node. This means that we're
1067 not currently allowed to stream from this node. */
1068 return -EPERM;
1069 }
1070
Mike Iselyd8554972006-06-26 20:58:46 -03001071 /* First read() attempt. Try to claim the stream and start
1072 it... */
1073 if ((ret = pvr2_channel_claim_stream(&fh->channel,
Joe Perches108bdd72010-04-05 16:05:39 -03001074 fh->pdi->stream)) != 0) {
Mike Iselyd8554972006-06-26 20:58:46 -03001075 /* Someone else must already have it */
1076 return ret;
1077 }
1078
Joe Perches108bdd72010-04-05 16:05:39 -03001079 fh->rhp = pvr2_channel_create_mpeg_stream(fh->pdi->stream);
Mike Iselyd8554972006-06-26 20:58:46 -03001080 if (!fh->rhp) {
Mike Iselya0fd1cb2006-06-30 11:35:28 -03001081 pvr2_channel_claim_stream(&fh->channel,NULL);
Mike Iselyd8554972006-06-26 20:58:46 -03001082 return -ENOMEM;
1083 }
1084
1085 hdw = fh->channel.mc_head->hdw;
Joe Perches108bdd72010-04-05 16:05:39 -03001086 sp = fh->pdi->stream->stream;
Mike Iselyd8554972006-06-26 20:58:46 -03001087 pvr2_stream_set_callback(sp,(pvr2_stream_callback)pvr2_v4l2_notify,fh);
Joe Perches108bdd72010-04-05 16:05:39 -03001088 pvr2_hdw_set_stream_type(hdw,fh->pdi->config);
Mike Isely681c7392007-11-26 01:48:52 -03001089 if ((ret = pvr2_hdw_set_streaming(hdw,!0)) < 0) return ret;
1090 return pvr2_ioread_set_enabled(fh->rhp,!0);
Mike Iselyd8554972006-06-26 20:58:46 -03001091}
1092
1093
1094static ssize_t pvr2_v4l2_read(struct file *file,
1095 char __user *buff, size_t count, loff_t *ppos)
1096{
1097 struct pvr2_v4l2_fh *fh = file->private_data;
1098 int ret;
1099
1100 if (fh->fw_mode_flag) {
1101 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
1102 char *tbuf;
1103 int c1,c2;
1104 int tcnt = 0;
1105 unsigned int offs = *ppos;
1106
1107 tbuf = kmalloc(PAGE_SIZE,GFP_KERNEL);
1108 if (!tbuf) return -ENOMEM;
1109
1110 while (count) {
1111 c1 = count;
1112 if (c1 > PAGE_SIZE) c1 = PAGE_SIZE;
1113 c2 = pvr2_hdw_cpufw_get(hdw,offs,tbuf,c1);
1114 if (c2 < 0) {
1115 tcnt = c2;
1116 break;
1117 }
1118 if (!c2) break;
1119 if (copy_to_user(buff,tbuf,c2)) {
1120 tcnt = -EFAULT;
1121 break;
1122 }
1123 offs += c2;
1124 tcnt += c2;
1125 buff += c2;
1126 count -= c2;
1127 *ppos += c2;
1128 }
1129 kfree(tbuf);
1130 return tcnt;
1131 }
1132
1133 if (!fh->rhp) {
1134 ret = pvr2_v4l2_iosetup(fh);
1135 if (ret) {
1136 return ret;
1137 }
1138 }
1139
1140 for (;;) {
1141 ret = pvr2_ioread_read(fh->rhp,buff,count);
1142 if (ret >= 0) break;
1143 if (ret != -EAGAIN) break;
1144 if (file->f_flags & O_NONBLOCK) break;
1145 /* Doing blocking I/O. Wait here. */
1146 ret = wait_event_interruptible(
1147 fh->wait_data,
1148 pvr2_ioread_avail(fh->rhp) >= 0);
1149 if (ret < 0) break;
1150 }
1151
1152 return ret;
1153}
1154
1155
Al Viroc23e0cb2017-07-03 03:02:56 -04001156static __poll_t pvr2_v4l2_poll(struct file *file, poll_table *wait)
Mike Iselyd8554972006-06-26 20:58:46 -03001157{
Al Viroc23e0cb2017-07-03 03:02:56 -04001158 __poll_t mask = 0;
Mike Iselyd8554972006-06-26 20:58:46 -03001159 struct pvr2_v4l2_fh *fh = file->private_data;
1160 int ret;
1161
1162 if (fh->fw_mode_flag) {
Linus Torvaldsa9a08842018-02-11 14:34:03 -08001163 mask |= EPOLLIN | EPOLLRDNORM;
Mike Iselyd8554972006-06-26 20:58:46 -03001164 return mask;
1165 }
1166
1167 if (!fh->rhp) {
1168 ret = pvr2_v4l2_iosetup(fh);
Linus Torvaldsa9a08842018-02-11 14:34:03 -08001169 if (ret) return EPOLLERR;
Mike Iselyd8554972006-06-26 20:58:46 -03001170 }
1171
1172 poll_wait(file,&fh->wait_data,wait);
1173
1174 if (pvr2_ioread_avail(fh->rhp) >= 0) {
Linus Torvaldsa9a08842018-02-11 14:34:03 -08001175 mask |= EPOLLIN | EPOLLRDNORM;
Mike Iselyd8554972006-06-26 20:58:46 -03001176 }
1177
1178 return mask;
1179}
1180
1181
Hans Verkuilbec43662008-12-30 06:58:20 -03001182static const struct v4l2_file_operations vdev_fops = {
Mike Iselyd8554972006-06-26 20:58:46 -03001183 .owner = THIS_MODULE,
1184 .open = pvr2_v4l2_open,
1185 .release = pvr2_v4l2_release,
1186 .read = pvr2_v4l2_read,
Hans Verkuileba09b52018-05-24 16:35:01 -04001187 .unlocked_ioctl = video_ioctl2,
Mike Iselyd8554972006-06-26 20:58:46 -03001188 .poll = pvr2_v4l2_poll,
1189};
1190
1191
Bhumika Goyal86844942017-08-26 09:11:30 -04001192static const struct video_device vdev_template = {
Mike Iselyd8554972006-06-26 20:58:46 -03001193 .fops = &vdev_fops,
1194};
1195
1196
1197static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
1198 struct pvr2_v4l2 *vp,
Mike Isely16eb40d2006-12-30 18:27:32 -03001199 int v4l_type)
Mike Iselyd8554972006-06-26 20:58:46 -03001200{
1201 int mindevnum;
1202 int unit_number;
Mike Isely598e9782012-02-20 02:35:20 -03001203 struct pvr2_hdw *hdw;
Al Viro89952d12007-03-14 09:17:59 +00001204 int *nr_ptr = NULL;
Mike Iselyd8554972006-06-26 20:58:46 -03001205 dip->v4lp = vp;
Mike Iselyd8554972006-06-26 20:58:46 -03001206
Mike Isely598e9782012-02-20 02:35:20 -03001207 hdw = vp->channel.mc_head->hdw;
Mike Isely16eb40d2006-12-30 18:27:32 -03001208 dip->v4l_type = v4l_type;
1209 switch (v4l_type) {
1210 case VFL_TYPE_GRABBER:
Mike Iselyd8554972006-06-26 20:58:46 -03001211 dip->stream = &vp->channel.mc_head->video_stream;
Mike Isely16eb40d2006-12-30 18:27:32 -03001212 dip->config = pvr2_config_mpeg;
1213 dip->minor_type = pvr2_v4l_type_video;
1214 nr_ptr = video_nr;
Mike Iselyc74e0062006-12-30 18:31:22 -03001215 if (!dip->stream) {
Mauro Carvalho Chehabbe9ed512009-01-08 09:13:42 -03001216 pr_err(KBUILD_MODNAME
Mauro Carvalho Chehab96292c82016-10-18 17:44:18 -02001217 ": Failed to set up pvrusb2 v4l video dev due to missing stream instance\n");
Mike Iselyc74e0062006-12-30 18:31:22 -03001218 return;
1219 }
Mike Iselyd8554972006-06-26 20:58:46 -03001220 break;
Mike Isely16eb40d2006-12-30 18:27:32 -03001221 case VFL_TYPE_VBI:
1222 dip->config = pvr2_config_vbi;
1223 dip->minor_type = pvr2_v4l_type_vbi;
1224 nr_ptr = vbi_nr;
Mike Iselyd8554972006-06-26 20:58:46 -03001225 break;
Mike Isely16eb40d2006-12-30 18:27:32 -03001226 case VFL_TYPE_RADIO:
Mike Iselyaf78a482007-01-20 00:04:31 -03001227 dip->stream = &vp->channel.mc_head->video_stream;
1228 dip->config = pvr2_config_mpeg;
Mike Isely16eb40d2006-12-30 18:27:32 -03001229 dip->minor_type = pvr2_v4l_type_radio;
1230 nr_ptr = radio_nr;
Mike Iselyd8554972006-06-26 20:58:46 -03001231 break;
1232 default:
1233 /* Bail out (this should be impossible) */
Mauro Carvalho Chehab96292c82016-10-18 17:44:18 -02001234 pr_err(KBUILD_MODNAME ": Failed to set up pvrusb2 v4l dev due to unrecognized config\n");
Mike Iselyd8554972006-06-26 20:58:46 -03001235 return;
1236 }
1237
Ezequiel Garcia5338c162012-10-23 15:57:09 -03001238 dip->devbase = vdev_template;
Mike Isely75910052006-09-23 22:30:50 -03001239 dip->devbase.release = pvr2_video_device_release;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -03001240 dip->devbase.ioctl_ops = &pvr2_ioctl_ops;
Mike Iselyd8329f82012-02-20 02:33:06 -03001241 {
1242 int val;
1243 pvr2_ctrl_get_value(
Mike Isely598e9782012-02-20 02:35:20 -03001244 pvr2_hdw_get_ctrl_by_id(hdw,
Mike Iselyd8329f82012-02-20 02:33:06 -03001245 PVR2_CID_STDAVAIL), &val);
1246 dip->devbase.tvnorms = (v4l2_std_id)val;
1247 }
Mike Iselyd8554972006-06-26 20:58:46 -03001248
1249 mindevnum = -1;
Mike Isely598e9782012-02-20 02:35:20 -03001250 unit_number = pvr2_hdw_get_unit_number(hdw);
Mike Isely16eb40d2006-12-30 18:27:32 -03001251 if (nr_ptr && (unit_number >= 0) && (unit_number < PVR_NUM)) {
1252 mindevnum = nr_ptr[unit_number];
Mike Iselyd8554972006-06-26 20:58:46 -03001253 }
Hans Verkuila28fbd02013-06-10 09:16:25 -03001254 pvr2_hdw_set_v4l2_dev(hdw, &dip->devbase);
Mike Isely16eb40d2006-12-30 18:27:32 -03001255 if ((video_register_device(&dip->devbase,
1256 dip->v4l_type, mindevnum) < 0) &&
1257 (video_register_device(&dip->devbase,
1258 dip->v4l_type, -1) < 0)) {
Mauro Carvalho Chehabbe9ed512009-01-08 09:13:42 -03001259 pr_err(KBUILD_MODNAME
1260 ": Failed to register pvrusb2 v4l device\n");
Pantelis Koukousoulasae2b9e22006-12-27 23:09:55 -03001261 }
Mike Isely16eb40d2006-12-30 18:27:32 -03001262
Laurent Pinchart38c7c032009-11-27 13:57:15 -03001263 printk(KERN_INFO "pvrusb2: registered device %s [%s]\n",
1264 video_device_node_name(&dip->devbase),
Mike Isely16eb40d2006-12-30 18:27:32 -03001265 pvr2_config_get_name(dip->config));
Mike Iselyd8554972006-06-26 20:58:46 -03001266
Mike Isely598e9782012-02-20 02:35:20 -03001267 pvr2_hdw_v4l_store_minor_number(hdw,
Mike Isely16eb40d2006-12-30 18:27:32 -03001268 dip->minor_type,dip->devbase.minor);
Mike Iselyd8554972006-06-26 20:58:46 -03001269}
1270
1271
1272struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
1273{
1274 struct pvr2_v4l2 *vp;
1275
Mike Isely4b85dee2007-01-20 00:03:32 -03001276 vp = kzalloc(sizeof(*vp),GFP_KERNEL);
Mike Iselyd8554972006-06-26 20:58:46 -03001277 if (!vp) return vp;
Mike Iselyd8554972006-06-26 20:58:46 -03001278 pvr2_channel_init(&vp->channel,mnp);
1279 pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp);
1280
1281 vp->channel.check_func = pvr2_v4l2_internal_check;
1282
1283 /* register streams */
Mike Iselybeb0ecd2008-04-22 14:45:38 -03001284 vp->dev_video = kzalloc(sizeof(*vp->dev_video),GFP_KERNEL);
1285 if (!vp->dev_video) goto fail;
Mike Isely16eb40d2006-12-30 18:27:32 -03001286 pvr2_v4l2_dev_init(vp->dev_video,vp,VFL_TYPE_GRABBER);
Mike Iselye57b1c82008-04-21 03:52:34 -03001287 if (pvr2_hdw_get_input_available(vp->channel.mc_head->hdw) &
1288 (1 << PVR2_CVAL_INPUT_RADIO)) {
Mike Iselybeb0ecd2008-04-22 14:45:38 -03001289 vp->dev_radio = kzalloc(sizeof(*vp->dev_radio),GFP_KERNEL);
1290 if (!vp->dev_radio) goto fail;
1291 pvr2_v4l2_dev_init(vp->dev_radio,vp,VFL_TYPE_RADIO);
1292 }
Mike Iselyd8554972006-06-26 20:58:46 -03001293
1294 return vp;
Mike Iselybeb0ecd2008-04-22 14:45:38 -03001295 fail:
1296 pvr2_trace(PVR2_TRACE_STRUCT,"Failure creating pvr2_v4l2 id=%p",vp);
1297 pvr2_v4l2_destroy_no_lock(vp);
Harvey Harrisona6a3a172008-04-28 16:50:03 -07001298 return NULL;
Mike Iselyd8554972006-06-26 20:58:46 -03001299}