blob: cb6668580d772644446c1150a60a93e8158bf04e [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;
Mauro Carvalho Chehab85709cb2018-09-10 08:19:16 -0400287 strscpy(vin->name, "PVRUSB2 Audio", sizeof(vin->name));
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300288 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;
Mauro Carvalho Chehab85709cb2018-09-10 08:19:16 -0400296 strscpy(vin->name, "PVRUSB2 Audio", sizeof(vin->name));
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300297 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
Hans Verkuil5200ab62018-10-04 17:38:15 -0400706static int pvr2_g_pixelaspect(struct file *file, void *priv,
707 int type, struct v4l2_fract *f)
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300708{
709 struct pvr2_v4l2_fh *fh = file->private_data;
710 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
Hans Verkuil5200ab62018-10-04 17:38:15 -0400711 struct v4l2_cropcap cap = { .type = type };
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300712 int ret;
713
Hans Verkuil5200ab62018-10-04 17:38:15 -0400714 if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300715 return -EINVAL;
Hans Verkuil5200ab62018-10-04 17:38:15 -0400716 ret = pvr2_hdw_get_cropcap(hdw, &cap);
717 if (!ret)
718 *f = cap.pixelaspect;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300719 return ret;
720}
721
Hans Verkuil1f981a42016-07-03 08:14:17 -0300722static int pvr2_g_selection(struct file *file, void *priv,
723 struct v4l2_selection *sel)
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300724{
725 struct pvr2_v4l2_fh *fh = file->private_data;
726 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
Hans Verkuil1f981a42016-07-03 08:14:17 -0300727 struct v4l2_cropcap cap;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300728 int val = 0;
729 int ret;
730
Hans Verkuil1f981a42016-07-03 08:14:17 -0300731 if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300732 return -EINVAL;
Hans Verkuil1f981a42016-07-03 08:14:17 -0300733
734 cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
735
736 switch (sel->target) {
737 case V4L2_SEL_TGT_CROP:
738 ret = pvr2_ctrl_get_value(
739 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL), &val);
740 if (ret != 0)
741 return -EINVAL;
742 sel->r.left = val;
743 ret = pvr2_ctrl_get_value(
744 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT), &val);
745 if (ret != 0)
746 return -EINVAL;
747 sel->r.top = val;
748 ret = pvr2_ctrl_get_value(
749 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW), &val);
750 if (ret != 0)
751 return -EINVAL;
752 sel->r.width = val;
753 ret = pvr2_ctrl_get_value(
754 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH), &val);
755 if (ret != 0)
756 return -EINVAL;
757 sel->r.height = val;
758 break;
759 case V4L2_SEL_TGT_CROP_DEFAULT:
760 ret = pvr2_hdw_get_cropcap(hdw, &cap);
761 sel->r = cap.defrect;
762 break;
763 case V4L2_SEL_TGT_CROP_BOUNDS:
764 ret = pvr2_hdw_get_cropcap(hdw, &cap);
765 sel->r = cap.bounds;
766 break;
767 default:
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300768 return -EINVAL;
Hans Verkuil1f981a42016-07-03 08:14:17 -0300769 }
770 return ret;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300771}
772
Hans Verkuil1f981a42016-07-03 08:14:17 -0300773static int pvr2_s_selection(struct file *file, void *priv,
774 struct v4l2_selection *sel)
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300775{
776 struct pvr2_v4l2_fh *fh = file->private_data;
777 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300778 int ret;
779
Hans Verkuil1f981a42016-07-03 08:14:17 -0300780 if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
781 sel->target != V4L2_SEL_TGT_CROP)
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300782 return -EINVAL;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300783 ret = pvr2_ctrl_set_value(
784 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL),
Hans Verkuil1f981a42016-07-03 08:14:17 -0300785 sel->r.left);
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300786 if (ret != 0)
Hans Verkuileba09b52018-05-24 16:35:01 -0400787 goto commit;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300788 ret = pvr2_ctrl_set_value(
789 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT),
Hans Verkuil1f981a42016-07-03 08:14:17 -0300790 sel->r.top);
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300791 if (ret != 0)
Hans Verkuileba09b52018-05-24 16:35:01 -0400792 goto commit;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300793 ret = pvr2_ctrl_set_value(
794 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW),
Hans Verkuil1f981a42016-07-03 08:14:17 -0300795 sel->r.width);
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300796 if (ret != 0)
Hans Verkuileba09b52018-05-24 16:35:01 -0400797 goto commit;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300798 ret = pvr2_ctrl_set_value(
799 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH),
Hans Verkuil1f981a42016-07-03 08:14:17 -0300800 sel->r.height);
Hans Verkuileba09b52018-05-24 16:35:01 -0400801commit:
802 pvr2_hdw_commit_ctl(hdw);
803 return ret;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300804}
805
806static int pvr2_log_status(struct file *file, void *priv)
807{
808 struct pvr2_v4l2_fh *fh = file->private_data;
809 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
810
811 pvr2_hdw_trigger_module_log(hdw);
812 return 0;
813}
814
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300815static const struct v4l2_ioctl_ops pvr2_ioctl_ops = {
816 .vidioc_querycap = pvr2_querycap,
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300817 .vidioc_s_audio = pvr2_s_audio,
818 .vidioc_g_audio = pvr2_g_audio,
819 .vidioc_enumaudio = pvr2_enumaudio,
820 .vidioc_enum_input = pvr2_enum_input,
Hans Verkuil5200ab62018-10-04 17:38:15 -0400821 .vidioc_g_pixelaspect = pvr2_g_pixelaspect,
Hans Verkuil1f981a42016-07-03 08:14:17 -0300822 .vidioc_s_selection = pvr2_s_selection,
823 .vidioc_g_selection = pvr2_g_selection,
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300824 .vidioc_g_input = pvr2_g_input,
825 .vidioc_s_input = pvr2_s_input,
826 .vidioc_g_frequency = pvr2_g_frequency,
827 .vidioc_s_frequency = pvr2_s_frequency,
828 .vidioc_s_tuner = pvr2_s_tuner,
829 .vidioc_g_tuner = pvr2_g_tuner,
830 .vidioc_g_std = pvr2_g_std,
831 .vidioc_s_std = pvr2_s_std,
Mike Isely0927ee62012-02-20 02:26:06 -0300832 .vidioc_querystd = pvr2_querystd,
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300833 .vidioc_log_status = pvr2_log_status,
834 .vidioc_enum_fmt_vid_cap = pvr2_enum_fmt_vid_cap,
835 .vidioc_g_fmt_vid_cap = pvr2_g_fmt_vid_cap,
836 .vidioc_s_fmt_vid_cap = pvr2_s_fmt_vid_cap,
837 .vidioc_try_fmt_vid_cap = pvr2_try_fmt_vid_cap,
838 .vidioc_streamon = pvr2_streamon,
839 .vidioc_streamoff = pvr2_streamoff,
840 .vidioc_queryctrl = pvr2_queryctrl,
841 .vidioc_querymenu = pvr2_querymenu,
842 .vidioc_g_ctrl = pvr2_g_ctrl,
843 .vidioc_s_ctrl = pvr2_s_ctrl,
844 .vidioc_g_ext_ctrls = pvr2_g_ext_ctrls,
845 .vidioc_s_ext_ctrls = pvr2_s_ext_ctrls,
846 .vidioc_try_ext_ctrls = pvr2_try_ext_ctrls,
Hans Verkuilc6d26cf2012-02-20 02:21:00 -0300847};
848
Mike Iselyd8554972006-06-26 20:58:46 -0300849static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
850{
Mike Isely0f0f257b2006-12-27 23:19:42 -0300851 struct pvr2_hdw *hdw = dip->v4lp->channel.mc_head->hdw;
Mike Isely16eb40d2006-12-30 18:27:32 -0300852 enum pvr2_config cfg = dip->config;
Mike Iselyd72baad2010-05-15 00:15:38 -0300853 char msg[80];
854 unsigned int mcnt;
855
856 /* Construct the unregistration message *before* we actually
857 perform the unregistration step. By doing it this way we don't
858 have to worry about potentially touching deleted resources. */
859 mcnt = scnprintf(msg, sizeof(msg) - 1,
860 "pvrusb2: unregistered device %s [%s]",
861 video_device_node_name(&dip->devbase),
862 pvr2_config_get_name(cfg));
863 msg[mcnt] = 0;
Mike Isely0f0f257b2006-12-27 23:19:42 -0300864
Mike Isely16eb40d2006-12-30 18:27:32 -0300865 pvr2_hdw_v4l_store_minor_number(hdw,dip->minor_type,-1);
Mike Isely75910052006-09-23 22:30:50 -0300866
867 /* Paranoia */
Randy Dunlapc2625bf2006-10-29 11:12:27 -0300868 dip->v4lp = NULL;
869 dip->stream = NULL;
Mike Isely75910052006-09-23 22:30:50 -0300870
871 /* Actual deallocation happens later when all internal references
872 are gone. */
873 video_unregister_device(&dip->devbase);
Mike Isely0f0f257b2006-12-27 23:19:42 -0300874
Dafna Hirschfeld8f845c62018-10-08 08:06:47 -0400875 pr_info("%s\n", msg);
Mike Isely0f0f257b2006-12-27 23:19:42 -0300876
Mike Iselyd8554972006-06-26 20:58:46 -0300877}
878
879
Mike Isely4a89baa2009-10-12 00:13:28 -0300880static void pvr2_v4l2_dev_disassociate_parent(struct pvr2_v4l2_dev *dip)
881{
882 if (!dip) return;
Hans Verkuila28fbd02013-06-10 09:16:25 -0300883 if (!dip->devbase.v4l2_dev->dev) return;
884 dip->devbase.v4l2_dev->dev = NULL;
Mike Isely4a89baa2009-10-12 00:13:28 -0300885 device_move(&dip->devbase.dev, NULL, DPM_ORDER_NONE);
886}
887
888
Mike Iselyd8554972006-06-26 20:58:46 -0300889static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp)
890{
Mike Isely0f0f257b2006-12-27 23:19:42 -0300891 if (vp->dev_video) {
892 pvr2_v4l2_dev_destroy(vp->dev_video);
Al Viro89952d12007-03-14 09:17:59 +0000893 vp->dev_video = NULL;
Mike Isely0f0f257b2006-12-27 23:19:42 -0300894 }
895 if (vp->dev_radio) {
896 pvr2_v4l2_dev_destroy(vp->dev_radio);
Al Viro89952d12007-03-14 09:17:59 +0000897 vp->dev_radio = NULL;
Mike Isely0f0f257b2006-12-27 23:19:42 -0300898 }
Mike Iselyd8554972006-06-26 20:58:46 -0300899
900 pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp);
901 pvr2_channel_done(&vp->channel);
902 kfree(vp);
903}
904
905
Mike Isely75910052006-09-23 22:30:50 -0300906static void pvr2_video_device_release(struct video_device *vdev)
907{
908 struct pvr2_v4l2_dev *dev;
909 dev = container_of(vdev,struct pvr2_v4l2_dev,devbase);
910 kfree(dev);
911}
912
913
Adrian Bunk07e337e2006-06-30 11:30:20 -0300914static void pvr2_v4l2_internal_check(struct pvr2_channel *chp)
Mike Iselyd8554972006-06-26 20:58:46 -0300915{
916 struct pvr2_v4l2 *vp;
917 vp = container_of(chp,struct pvr2_v4l2,channel);
918 if (!vp->channel.mc_head->disconnect_flag) return;
Mike Isely4a89baa2009-10-12 00:13:28 -0300919 pvr2_v4l2_dev_disassociate_parent(vp->dev_video);
920 pvr2_v4l2_dev_disassociate_parent(vp->dev_radio);
Hans Verkuilcee05cb2015-02-03 10:46:55 -0300921 if (!list_empty(&vp->dev_video->devbase.fh_list) ||
922 !list_empty(&vp->dev_radio->devbase.fh_list))
923 return;
Mike Iselyd8554972006-06-26 20:58:46 -0300924 pvr2_v4l2_destroy_no_lock(vp);
925}
926
927
Hans Verkuilbec43662008-12-30 06:58:20 -0300928static int pvr2_v4l2_release(struct file *file)
Mike Iselyd8554972006-06-26 20:58:46 -0300929{
930 struct pvr2_v4l2_fh *fhp = file->private_data;
Hans Verkuilcee05cb2015-02-03 10:46:55 -0300931 struct pvr2_v4l2 *vp = fhp->pdi->v4lp;
Mike Iselyc74e0062006-12-30 18:31:22 -0300932 struct pvr2_hdw *hdw = fhp->channel.mc_head->hdw;
Mike Iselyd8554972006-06-26 20:58:46 -0300933
934 pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_release");
935
936 if (fhp->rhp) {
937 struct pvr2_stream *sp;
Mike Iselyd8554972006-06-26 20:58:46 -0300938 pvr2_hdw_set_streaming(hdw,0);
939 sp = pvr2_ioread_get_stream(fhp->rhp);
Mike Iselya0fd1cb2006-06-30 11:35:28 -0300940 if (sp) pvr2_stream_set_callback(sp,NULL,NULL);
Mike Iselyd8554972006-06-26 20:58:46 -0300941 pvr2_ioread_destroy(fhp->rhp);
Mike Iselya0fd1cb2006-06-30 11:35:28 -0300942 fhp->rhp = NULL;
Mike Iselyd8554972006-06-26 20:58:46 -0300943 }
Pantelis Koukousoulasae2b9e22006-12-27 23:09:55 -0300944
Hans Verkuilcee05cb2015-02-03 10:46:55 -0300945 v4l2_fh_del(&fhp->fh);
946 v4l2_fh_exit(&fhp->fh);
Mike Iselyd8554972006-06-26 20:58:46 -0300947 file->private_data = NULL;
948
Mike Isely794b1602008-04-22 14:45:45 -0300949 pvr2_channel_done(&fhp->channel);
950 pvr2_trace(PVR2_TRACE_STRUCT,
951 "Destroying pvr_v4l2_fh id=%p",fhp);
Mike Iselye57b1c82008-04-21 03:52:34 -0300952 if (fhp->input_map) {
953 kfree(fhp->input_map);
954 fhp->input_map = NULL;
955 }
Mike Isely794b1602008-04-22 14:45:45 -0300956 kfree(fhp);
Hans Verkuilcee05cb2015-02-03 10:46:55 -0300957 if (vp->channel.mc_head->disconnect_flag &&
958 list_empty(&vp->dev_video->devbase.fh_list) &&
959 list_empty(&vp->dev_radio->devbase.fh_list)) {
Mike Isely794b1602008-04-22 14:45:45 -0300960 pvr2_v4l2_destroy_no_lock(vp);
961 }
Mike Iselyd8554972006-06-26 20:58:46 -0300962 return 0;
963}
964
965
Hans Verkuilbec43662008-12-30 06:58:20 -0300966static int pvr2_v4l2_open(struct file *file)
Mike Iselyd8554972006-06-26 20:58:46 -0300967{
Mike Isely75910052006-09-23 22:30:50 -0300968 struct pvr2_v4l2_dev *dip; /* Our own context pointer */
Mike Iselyd8554972006-06-26 20:58:46 -0300969 struct pvr2_v4l2_fh *fhp;
970 struct pvr2_v4l2 *vp;
971 struct pvr2_hdw *hdw;
Mike Isely1cb03b72008-04-21 03:47:43 -0300972 unsigned int input_mask = 0;
Mike Iselye57b1c82008-04-21 03:52:34 -0300973 unsigned int input_cnt,idx;
Mike Isely1cb03b72008-04-21 03:47:43 -0300974 int ret = 0;
Mike Iselyd8554972006-06-26 20:58:46 -0300975
Mike Isely75910052006-09-23 22:30:50 -0300976 dip = container_of(video_devdata(file),struct pvr2_v4l2_dev,devbase);
Mike Iselyd8554972006-06-26 20:58:46 -0300977
978 vp = dip->v4lp;
979 hdw = vp->channel.hdw;
980
981 pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_open");
982
983 if (!pvr2_hdw_dev_ok(hdw)) {
984 pvr2_trace(PVR2_TRACE_OPEN_CLOSE,
985 "pvr2_v4l2_open: hardware not ready");
986 return -EIO;
987 }
988
Mike Isely4b85dee2007-01-20 00:03:32 -0300989 fhp = kzalloc(sizeof(*fhp),GFP_KERNEL);
Mike Iselyd8554972006-06-26 20:58:46 -0300990 if (!fhp) {
991 return -ENOMEM;
992 }
Mike Iselyd8554972006-06-26 20:58:46 -0300993
Hans Verkuilcee05cb2015-02-03 10:46:55 -0300994 v4l2_fh_init(&fhp->fh, &dip->devbase);
Mike Iselyd8554972006-06-26 20:58:46 -0300995 init_waitqueue_head(&fhp->wait_data);
Joe Perches108bdd72010-04-05 16:05:39 -0300996 fhp->pdi = dip;
Mike Iselyd8554972006-06-26 20:58:46 -0300997
Mike Isely794b1602008-04-22 14:45:45 -0300998 pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp);
999 pvr2_channel_init(&fhp->channel,vp->channel.mc_head);
Pantelis Koukousoulasae2b9e22006-12-27 23:09:55 -03001000
Mike Isely1cb03b72008-04-21 03:47:43 -03001001 if (dip->v4l_type == VFL_TYPE_RADIO) {
1002 /* Opening device as a radio, legal input selection subset
1003 is just the radio. */
1004 input_mask = (1 << PVR2_CVAL_INPUT_RADIO);
1005 } else {
1006 /* Opening the main V4L device, legal input selection
1007 subset includes all analog inputs. */
1008 input_mask = ((1 << PVR2_CVAL_INPUT_RADIO) |
1009 (1 << PVR2_CVAL_INPUT_TV) |
1010 (1 << PVR2_CVAL_INPUT_COMPOSITE) |
1011 (1 << PVR2_CVAL_INPUT_SVIDEO));
1012 }
1013 ret = pvr2_channel_limit_inputs(&fhp->channel,input_mask);
1014 if (ret) {
1015 pvr2_channel_done(&fhp->channel);
1016 pvr2_trace(PVR2_TRACE_STRUCT,
1017 "Destroying pvr_v4l2_fh id=%p (input mask error)",
1018 fhp);
Santosh Kumar Singh01faa0d2016-12-19 15:20:37 -02001019 v4l2_fh_exit(&fhp->fh);
Mike Isely1cb03b72008-04-21 03:47:43 -03001020 kfree(fhp);
1021 return ret;
1022 }
1023
Mike Iselye57b1c82008-04-21 03:52:34 -03001024 input_mask &= pvr2_hdw_get_input_available(hdw);
1025 input_cnt = 0;
1026 for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) {
1027 if (input_mask & (1 << idx)) input_cnt++;
1028 }
1029 fhp->input_cnt = input_cnt;
1030 fhp->input_map = kzalloc(input_cnt,GFP_KERNEL);
1031 if (!fhp->input_map) {
1032 pvr2_channel_done(&fhp->channel);
1033 pvr2_trace(PVR2_TRACE_STRUCT,
1034 "Destroying pvr_v4l2_fh id=%p (input map failure)",
1035 fhp);
Santosh Kumar Singh01faa0d2016-12-19 15:20:37 -02001036 v4l2_fh_exit(&fhp->fh);
Mike Iselye57b1c82008-04-21 03:52:34 -03001037 kfree(fhp);
1038 return -ENOMEM;
1039 }
1040 input_cnt = 0;
1041 for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) {
1042 if (!(input_mask & (1 << idx))) continue;
1043 fhp->input_map[input_cnt++] = idx;
1044 }
1045
Mike Iselyd8554972006-06-26 20:58:46 -03001046 fhp->file = file;
1047 file->private_data = fhp;
Mike Iselyd8554972006-06-26 20:58:46 -03001048
1049 fhp->fw_mode_flag = pvr2_hdw_cpufw_get_enabled(hdw);
Hans Verkuilcee05cb2015-02-03 10:46:55 -03001050 v4l2_fh_add(&fhp->fh);
Mike Iselyd8554972006-06-26 20:58:46 -03001051
1052 return 0;
1053}
1054
1055
1056static void pvr2_v4l2_notify(struct pvr2_v4l2_fh *fhp)
1057{
1058 wake_up(&fhp->wait_data);
1059}
1060
1061static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh)
1062{
1063 int ret;
1064 struct pvr2_stream *sp;
1065 struct pvr2_hdw *hdw;
1066 if (fh->rhp) return 0;
1067
Joe Perches108bdd72010-04-05 16:05:39 -03001068 if (!fh->pdi->stream) {
Mike Isely16eb40d2006-12-30 18:27:32 -03001069 /* No stream defined for this node. This means that we're
1070 not currently allowed to stream from this node. */
1071 return -EPERM;
1072 }
1073
Mike Iselyd8554972006-06-26 20:58:46 -03001074 /* First read() attempt. Try to claim the stream and start
1075 it... */
1076 if ((ret = pvr2_channel_claim_stream(&fh->channel,
Joe Perches108bdd72010-04-05 16:05:39 -03001077 fh->pdi->stream)) != 0) {
Mike Iselyd8554972006-06-26 20:58:46 -03001078 /* Someone else must already have it */
1079 return ret;
1080 }
1081
Joe Perches108bdd72010-04-05 16:05:39 -03001082 fh->rhp = pvr2_channel_create_mpeg_stream(fh->pdi->stream);
Mike Iselyd8554972006-06-26 20:58:46 -03001083 if (!fh->rhp) {
Mike Iselya0fd1cb2006-06-30 11:35:28 -03001084 pvr2_channel_claim_stream(&fh->channel,NULL);
Mike Iselyd8554972006-06-26 20:58:46 -03001085 return -ENOMEM;
1086 }
1087
1088 hdw = fh->channel.mc_head->hdw;
Joe Perches108bdd72010-04-05 16:05:39 -03001089 sp = fh->pdi->stream->stream;
Mike Iselyd8554972006-06-26 20:58:46 -03001090 pvr2_stream_set_callback(sp,(pvr2_stream_callback)pvr2_v4l2_notify,fh);
Joe Perches108bdd72010-04-05 16:05:39 -03001091 pvr2_hdw_set_stream_type(hdw,fh->pdi->config);
Mike Isely681c7392007-11-26 01:48:52 -03001092 if ((ret = pvr2_hdw_set_streaming(hdw,!0)) < 0) return ret;
1093 return pvr2_ioread_set_enabled(fh->rhp,!0);
Mike Iselyd8554972006-06-26 20:58:46 -03001094}
1095
1096
1097static ssize_t pvr2_v4l2_read(struct file *file,
1098 char __user *buff, size_t count, loff_t *ppos)
1099{
1100 struct pvr2_v4l2_fh *fh = file->private_data;
1101 int ret;
1102
1103 if (fh->fw_mode_flag) {
1104 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
1105 char *tbuf;
1106 int c1,c2;
1107 int tcnt = 0;
1108 unsigned int offs = *ppos;
1109
1110 tbuf = kmalloc(PAGE_SIZE,GFP_KERNEL);
1111 if (!tbuf) return -ENOMEM;
1112
1113 while (count) {
1114 c1 = count;
1115 if (c1 > PAGE_SIZE) c1 = PAGE_SIZE;
1116 c2 = pvr2_hdw_cpufw_get(hdw,offs,tbuf,c1);
1117 if (c2 < 0) {
1118 tcnt = c2;
1119 break;
1120 }
1121 if (!c2) break;
1122 if (copy_to_user(buff,tbuf,c2)) {
1123 tcnt = -EFAULT;
1124 break;
1125 }
1126 offs += c2;
1127 tcnt += c2;
1128 buff += c2;
1129 count -= c2;
1130 *ppos += c2;
1131 }
1132 kfree(tbuf);
1133 return tcnt;
1134 }
1135
1136 if (!fh->rhp) {
1137 ret = pvr2_v4l2_iosetup(fh);
1138 if (ret) {
1139 return ret;
1140 }
1141 }
1142
1143 for (;;) {
1144 ret = pvr2_ioread_read(fh->rhp,buff,count);
1145 if (ret >= 0) break;
1146 if (ret != -EAGAIN) break;
1147 if (file->f_flags & O_NONBLOCK) break;
1148 /* Doing blocking I/O. Wait here. */
1149 ret = wait_event_interruptible(
1150 fh->wait_data,
1151 pvr2_ioread_avail(fh->rhp) >= 0);
1152 if (ret < 0) break;
1153 }
1154
1155 return ret;
1156}
1157
1158
Al Viroc23e0cb2017-07-03 03:02:56 -04001159static __poll_t pvr2_v4l2_poll(struct file *file, poll_table *wait)
Mike Iselyd8554972006-06-26 20:58:46 -03001160{
Al Viroc23e0cb2017-07-03 03:02:56 -04001161 __poll_t mask = 0;
Mike Iselyd8554972006-06-26 20:58:46 -03001162 struct pvr2_v4l2_fh *fh = file->private_data;
1163 int ret;
1164
1165 if (fh->fw_mode_flag) {
Linus Torvaldsa9a08842018-02-11 14:34:03 -08001166 mask |= EPOLLIN | EPOLLRDNORM;
Mike Iselyd8554972006-06-26 20:58:46 -03001167 return mask;
1168 }
1169
1170 if (!fh->rhp) {
1171 ret = pvr2_v4l2_iosetup(fh);
Linus Torvaldsa9a08842018-02-11 14:34:03 -08001172 if (ret) return EPOLLERR;
Mike Iselyd8554972006-06-26 20:58:46 -03001173 }
1174
1175 poll_wait(file,&fh->wait_data,wait);
1176
1177 if (pvr2_ioread_avail(fh->rhp) >= 0) {
Linus Torvaldsa9a08842018-02-11 14:34:03 -08001178 mask |= EPOLLIN | EPOLLRDNORM;
Mike Iselyd8554972006-06-26 20:58:46 -03001179 }
1180
1181 return mask;
1182}
1183
1184
Hans Verkuilbec43662008-12-30 06:58:20 -03001185static const struct v4l2_file_operations vdev_fops = {
Mike Iselyd8554972006-06-26 20:58:46 -03001186 .owner = THIS_MODULE,
1187 .open = pvr2_v4l2_open,
1188 .release = pvr2_v4l2_release,
1189 .read = pvr2_v4l2_read,
Hans Verkuileba09b52018-05-24 16:35:01 -04001190 .unlocked_ioctl = video_ioctl2,
Mike Iselyd8554972006-06-26 20:58:46 -03001191 .poll = pvr2_v4l2_poll,
1192};
1193
1194
Bhumika Goyal86844942017-08-26 09:11:30 -04001195static const struct video_device vdev_template = {
Mike Iselyd8554972006-06-26 20:58:46 -03001196 .fops = &vdev_fops,
1197};
1198
1199
1200static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
1201 struct pvr2_v4l2 *vp,
Mike Isely16eb40d2006-12-30 18:27:32 -03001202 int v4l_type)
Mike Iselyd8554972006-06-26 20:58:46 -03001203{
1204 int mindevnum;
1205 int unit_number;
Mike Isely598e9782012-02-20 02:35:20 -03001206 struct pvr2_hdw *hdw;
Al Viro89952d12007-03-14 09:17:59 +00001207 int *nr_ptr = NULL;
Mike Iselyd8554972006-06-26 20:58:46 -03001208 dip->v4lp = vp;
Mike Iselyd8554972006-06-26 20:58:46 -03001209
Mike Isely598e9782012-02-20 02:35:20 -03001210 hdw = vp->channel.mc_head->hdw;
Mike Isely16eb40d2006-12-30 18:27:32 -03001211 dip->v4l_type = v4l_type;
1212 switch (v4l_type) {
1213 case VFL_TYPE_GRABBER:
Mike Iselyd8554972006-06-26 20:58:46 -03001214 dip->stream = &vp->channel.mc_head->video_stream;
Mike Isely16eb40d2006-12-30 18:27:32 -03001215 dip->config = pvr2_config_mpeg;
1216 dip->minor_type = pvr2_v4l_type_video;
1217 nr_ptr = video_nr;
Mike Iselyc74e0062006-12-30 18:31:22 -03001218 if (!dip->stream) {
Mauro Carvalho Chehabbe9ed512009-01-08 09:13:42 -03001219 pr_err(KBUILD_MODNAME
Mauro Carvalho Chehab96292c82016-10-18 17:44:18 -02001220 ": Failed to set up pvrusb2 v4l video dev due to missing stream instance\n");
Mike Iselyc74e0062006-12-30 18:31:22 -03001221 return;
1222 }
Mike Iselyd8554972006-06-26 20:58:46 -03001223 break;
Mike Isely16eb40d2006-12-30 18:27:32 -03001224 case VFL_TYPE_VBI:
1225 dip->config = pvr2_config_vbi;
1226 dip->minor_type = pvr2_v4l_type_vbi;
1227 nr_ptr = vbi_nr;
Mike Iselyd8554972006-06-26 20:58:46 -03001228 break;
Mike Isely16eb40d2006-12-30 18:27:32 -03001229 case VFL_TYPE_RADIO:
Mike Iselyaf78a482007-01-20 00:04:31 -03001230 dip->stream = &vp->channel.mc_head->video_stream;
1231 dip->config = pvr2_config_mpeg;
Mike Isely16eb40d2006-12-30 18:27:32 -03001232 dip->minor_type = pvr2_v4l_type_radio;
1233 nr_ptr = radio_nr;
Mike Iselyd8554972006-06-26 20:58:46 -03001234 break;
1235 default:
1236 /* Bail out (this should be impossible) */
Mauro Carvalho Chehab96292c82016-10-18 17:44:18 -02001237 pr_err(KBUILD_MODNAME ": Failed to set up pvrusb2 v4l dev due to unrecognized config\n");
Mike Iselyd8554972006-06-26 20:58:46 -03001238 return;
1239 }
1240
Ezequiel Garcia5338c162012-10-23 15:57:09 -03001241 dip->devbase = vdev_template;
Mike Isely75910052006-09-23 22:30:50 -03001242 dip->devbase.release = pvr2_video_device_release;
Hans Verkuilc6d26cf2012-02-20 02:21:00 -03001243 dip->devbase.ioctl_ops = &pvr2_ioctl_ops;
Mike Iselyd8329f82012-02-20 02:33:06 -03001244 {
1245 int val;
1246 pvr2_ctrl_get_value(
Mike Isely598e9782012-02-20 02:35:20 -03001247 pvr2_hdw_get_ctrl_by_id(hdw,
Mike Iselyd8329f82012-02-20 02:33:06 -03001248 PVR2_CID_STDAVAIL), &val);
1249 dip->devbase.tvnorms = (v4l2_std_id)val;
1250 }
Mike Iselyd8554972006-06-26 20:58:46 -03001251
1252 mindevnum = -1;
Mike Isely598e9782012-02-20 02:35:20 -03001253 unit_number = pvr2_hdw_get_unit_number(hdw);
Mike Isely16eb40d2006-12-30 18:27:32 -03001254 if (nr_ptr && (unit_number >= 0) && (unit_number < PVR_NUM)) {
1255 mindevnum = nr_ptr[unit_number];
Mike Iselyd8554972006-06-26 20:58:46 -03001256 }
Hans Verkuila28fbd02013-06-10 09:16:25 -03001257 pvr2_hdw_set_v4l2_dev(hdw, &dip->devbase);
Mike Isely16eb40d2006-12-30 18:27:32 -03001258 if ((video_register_device(&dip->devbase,
1259 dip->v4l_type, mindevnum) < 0) &&
1260 (video_register_device(&dip->devbase,
1261 dip->v4l_type, -1) < 0)) {
Mauro Carvalho Chehabbe9ed512009-01-08 09:13:42 -03001262 pr_err(KBUILD_MODNAME
1263 ": Failed to register pvrusb2 v4l device\n");
Pantelis Koukousoulasae2b9e22006-12-27 23:09:55 -03001264 }
Mike Isely16eb40d2006-12-30 18:27:32 -03001265
Dafna Hirschfeld8f845c62018-10-08 08:06:47 -04001266 pr_info("pvrusb2: registered device %s [%s]\n",
Laurent Pinchart38c7c032009-11-27 13:57:15 -03001267 video_device_node_name(&dip->devbase),
Mike Isely16eb40d2006-12-30 18:27:32 -03001268 pvr2_config_get_name(dip->config));
Mike Iselyd8554972006-06-26 20:58:46 -03001269
Mike Isely598e9782012-02-20 02:35:20 -03001270 pvr2_hdw_v4l_store_minor_number(hdw,
Mike Isely16eb40d2006-12-30 18:27:32 -03001271 dip->minor_type,dip->devbase.minor);
Mike Iselyd8554972006-06-26 20:58:46 -03001272}
1273
1274
1275struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
1276{
1277 struct pvr2_v4l2 *vp;
1278
Mike Isely4b85dee2007-01-20 00:03:32 -03001279 vp = kzalloc(sizeof(*vp),GFP_KERNEL);
Mike Iselyd8554972006-06-26 20:58:46 -03001280 if (!vp) return vp;
Mike Iselyd8554972006-06-26 20:58:46 -03001281 pvr2_channel_init(&vp->channel,mnp);
1282 pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp);
1283
1284 vp->channel.check_func = pvr2_v4l2_internal_check;
1285
1286 /* register streams */
Mike Iselybeb0ecd2008-04-22 14:45:38 -03001287 vp->dev_video = kzalloc(sizeof(*vp->dev_video),GFP_KERNEL);
1288 if (!vp->dev_video) goto fail;
Mike Isely16eb40d2006-12-30 18:27:32 -03001289 pvr2_v4l2_dev_init(vp->dev_video,vp,VFL_TYPE_GRABBER);
Mike Iselye57b1c82008-04-21 03:52:34 -03001290 if (pvr2_hdw_get_input_available(vp->channel.mc_head->hdw) &
1291 (1 << PVR2_CVAL_INPUT_RADIO)) {
Mike Iselybeb0ecd2008-04-22 14:45:38 -03001292 vp->dev_radio = kzalloc(sizeof(*vp->dev_radio),GFP_KERNEL);
1293 if (!vp->dev_radio) goto fail;
1294 pvr2_v4l2_dev_init(vp->dev_radio,vp,VFL_TYPE_RADIO);
1295 }
Mike Iselyd8554972006-06-26 20:58:46 -03001296
1297 return vp;
Mike Iselybeb0ecd2008-04-22 14:45:38 -03001298 fail:
1299 pvr2_trace(PVR2_TRACE_STRUCT,"Failure creating pvr2_v4l2 id=%p",vp);
1300 pvr2_v4l2_destroy_no_lock(vp);
Harvey Harrisona6a3a172008-04-28 16:50:03 -07001301 return NULL;
Mike Iselyd8554972006-06-26 20:58:46 -03001302}