blob: 6d666174dbb4491aff05b5f2c39c065f15b00b78 [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 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <linux/kernel.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090023#include <linux/slab.h>
Mauro Carvalho Chehabce4260c2006-06-26 22:26:08 -030024#include <linux/version.h>
Mike Iselyd8554972006-06-26 20:58:46 -030025#include "pvrusb2-context.h"
26#include "pvrusb2-hdw.h"
27#include "pvrusb2.h"
28#include "pvrusb2-debug.h"
29#include "pvrusb2-v4l2.h"
30#include "pvrusb2-ioread.h"
31#include <linux/videodev2.h>
Paul Gortmaker7a707b82011-07-03 14:03:12 -040032#include <linux/module.h>
Mike Isely43e06022006-09-23 23:47:50 -030033#include <media/v4l2-dev.h>
Mike Iselyd8554972006-06-26 20:58:46 -030034#include <media/v4l2-common.h>
Hans Verkuil35ea11f2008-07-20 08:12:02 -030035#include <media/v4l2-ioctl.h>
Mike Iselyd8554972006-06-26 20:58:46 -030036
37struct pvr2_v4l2_dev;
38struct pvr2_v4l2_fh;
39struct pvr2_v4l2;
40
Mike Iselyd8554972006-06-26 20:58:46 -030041struct pvr2_v4l2_dev {
Mike Isely75910052006-09-23 22:30:50 -030042 struct video_device devbase; /* MUST be first! */
Mike Iselyd8554972006-06-26 20:58:46 -030043 struct pvr2_v4l2 *v4lp;
Mike Iselyd8554972006-06-26 20:58:46 -030044 struct pvr2_context_stream *stream;
Mike Isely16eb40d2006-12-30 18:27:32 -030045 /* Information about this device: */
46 enum pvr2_config config; /* Expected stream format */
47 int v4l_type; /* V4L defined type for this device node */
48 enum pvr2_v4l_type minor_type; /* pvr2-understood minor device type */
Mike Iselyd8554972006-06-26 20:58:46 -030049};
50
51struct pvr2_v4l2_fh {
52 struct pvr2_channel channel;
Joe Perches108bdd72010-04-05 16:05:39 -030053 struct pvr2_v4l2_dev *pdi;
Mike Iselyd8554972006-06-26 20:58:46 -030054 enum v4l2_priority prio;
55 struct pvr2_ioread *rhp;
56 struct file *file;
57 struct pvr2_v4l2 *vhead;
58 struct pvr2_v4l2_fh *vnext;
59 struct pvr2_v4l2_fh *vprev;
60 wait_queue_head_t wait_data;
61 int fw_mode_flag;
Mike Iselye57b1c82008-04-21 03:52:34 -030062 /* Map contiguous ordinal value to input id */
63 unsigned char *input_map;
64 unsigned int input_cnt;
Mike Iselyd8554972006-06-26 20:58:46 -030065};
66
67struct pvr2_v4l2 {
68 struct pvr2_channel channel;
69 struct pvr2_v4l2_fh *vfirst;
70 struct pvr2_v4l2_fh *vlast;
71
72 struct v4l2_prio_state prio;
73
Mike Isely0f0f2572006-12-27 23:19:42 -030074 /* streams - Note that these must be separately, individually,
75 * allocated pointers. This is because the v4l core is going to
76 * manage their deletion - separately, individually... */
77 struct pvr2_v4l2_dev *dev_video;
78 struct pvr2_v4l2_dev *dev_radio;
Mike Iselyd8554972006-06-26 20:58:46 -030079};
80
81static int video_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
82module_param_array(video_nr, int, NULL, 0444);
Mike Isely5e6862c2006-12-27 23:17:26 -030083MODULE_PARM_DESC(video_nr, "Offset for device's video dev minor");
84static int radio_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
85module_param_array(radio_nr, int, NULL, 0444);
86MODULE_PARM_DESC(radio_nr, "Offset for device's radio dev minor");
87static int vbi_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
88module_param_array(vbi_nr, int, NULL, 0444);
89MODULE_PARM_DESC(vbi_nr, "Offset for device's vbi dev minor");
Mike Iselyd8554972006-06-26 20:58:46 -030090
Adrian Bunk07e337e2006-06-30 11:30:20 -030091static struct v4l2_capability pvr_capability ={
Mike Iselyd8554972006-06-26 20:58:46 -030092 .driver = "pvrusb2",
93 .card = "Hauppauge WinTV pvr-usb2",
94 .bus_info = "usb",
Mauro Carvalho Chehab083774d2011-06-25 13:34:24 -030095 .version = LINUX_VERSION_CODE,
Mike Iselyd166b022009-01-14 04:21:29 -030096 .capabilities = (V4L2_CAP_VIDEO_CAPTURE |
Pantelis Koukousoulasae2b9e22006-12-27 23:09:55 -030097 V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
Mike Iselyd8554972006-06-26 20:58:46 -030098 V4L2_CAP_READWRITE),
99 .reserved = {0,0,0,0}
100};
101
Adrian Bunk07e337e2006-06-30 11:30:20 -0300102static struct v4l2_fmtdesc pvr_fmtdesc [] = {
Mike Iselyd8554972006-06-26 20:58:46 -0300103 {
104 .index = 0,
105 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
106 .flags = V4L2_FMT_FLAG_COMPRESSED,
107 .description = "MPEG1/2",
108 // This should really be V4L2_PIX_FMT_MPEG, but xawtv
109 // breaks when I do that.
110 .pixelformat = 0, // V4L2_PIX_FMT_MPEG,
111 .reserved = { 0, 0, 0, 0 }
112 }
113};
114
115#define PVR_FORMAT_PIX 0
116#define PVR_FORMAT_VBI 1
117
Adrian Bunk07e337e2006-06-30 11:30:20 -0300118static struct v4l2_format pvr_format [] = {
Mike Iselyd8554972006-06-26 20:58:46 -0300119 [PVR_FORMAT_PIX] = {
120 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
121 .fmt = {
122 .pix = {
123 .width = 720,
124 .height = 576,
125 // This should really be V4L2_PIX_FMT_MPEG,
126 // but xawtv breaks when I do that.
127 .pixelformat = 0, // V4L2_PIX_FMT_MPEG,
128 .field = V4L2_FIELD_INTERLACED,
129 .bytesperline = 0, // doesn't make sense
130 // here
131 //FIXME : Don't know what to put here...
132 .sizeimage = (32*1024),
133 .colorspace = 0, // doesn't make sense here
134 .priv = 0
135 }
136 }
137 },
138 [PVR_FORMAT_VBI] = {
139 .type = V4L2_BUF_TYPE_VBI_CAPTURE,
140 .fmt = {
141 .vbi = {
142 .sampling_rate = 27000000,
143 .offset = 248,
144 .samples_per_line = 1443,
145 .sample_format = V4L2_PIX_FMT_GREY,
146 .start = { 0, 0 },
147 .count = { 0, 0 },
148 .flags = 0,
149 .reserved = { 0, 0 }
150 }
151 }
152 }
153};
154
Mike Isely16eb40d2006-12-30 18:27:32 -0300155
Mike Iselyd8554972006-06-26 20:58:46 -0300156/*
157 * pvr_ioctl()
158 *
159 * This is part of Video 4 Linux API. The procedure handles ioctl() calls.
160 *
161 */
Hans Verkuil069b7472008-12-30 07:04:34 -0300162static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
Mike Iselyd8554972006-06-26 20:58:46 -0300163{
164 struct pvr2_v4l2_fh *fh = file->private_data;
165 struct pvr2_v4l2 *vp = fh->vhead;
Joe Perches108bdd72010-04-05 16:05:39 -0300166 struct pvr2_v4l2_dev *pdi = fh->pdi;
Mike Iselyd8554972006-06-26 20:58:46 -0300167 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
Hans Verkuil069b7472008-12-30 07:04:34 -0300168 long ret = -EINVAL;
Mike Iselyd8554972006-06-26 20:58:46 -0300169
170 if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
171 v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),cmd);
172 }
173
174 if (!pvr2_hdw_dev_ok(hdw)) {
175 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
176 "ioctl failed - bad or no context");
177 return -EFAULT;
178 }
179
180 /* check priority */
181 switch (cmd) {
182 case VIDIOC_S_CTRL:
183 case VIDIOC_S_STD:
184 case VIDIOC_S_INPUT:
185 case VIDIOC_S_TUNER:
186 case VIDIOC_S_FREQUENCY:
Hans Verkuilffb48772010-05-01 08:03:24 -0300187 ret = v4l2_prio_check(&vp->prio, fh->prio);
Mike Iselyd8554972006-06-26 20:58:46 -0300188 if (ret)
189 return ret;
190 }
191
192 switch (cmd) {
193 case VIDIOC_QUERYCAP:
194 {
195 struct v4l2_capability *cap = arg;
196
197 memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
Mike Isely31a18542007-04-08 01:11:47 -0300198 strlcpy(cap->bus_info,pvr2_hdw_get_bus_info(hdw),
199 sizeof(cap->bus_info));
Mike Isely78a47102007-11-26 01:58:20 -0300200 strlcpy(cap->card,pvr2_hdw_get_desc(hdw),sizeof(cap->card));
Mike Iselyd8554972006-06-26 20:58:46 -0300201
202 ret = 0;
203 break;
204 }
205
206 case VIDIOC_G_PRIORITY:
207 {
208 enum v4l2_priority *p = arg;
209
210 *p = v4l2_prio_max(&vp->prio);
211 ret = 0;
212 break;
213 }
214
215 case VIDIOC_S_PRIORITY:
216 {
217 enum v4l2_priority *prio = arg;
218
219 ret = v4l2_prio_change(&vp->prio, &fh->prio, *prio);
220 break;
221 }
222
223 case VIDIOC_ENUMSTD:
224 {
225 struct v4l2_standard *vs = (struct v4l2_standard *)arg;
226 int idx = vs->index;
227 ret = pvr2_hdw_get_stdenum_value(hdw,vs,idx+1);
228 break;
229 }
230
Mauro Carvalho Chehab7383a472011-10-03 12:22:28 -0300231 case VIDIOC_QUERYSTD:
232 {
233 v4l2_std_id *std = arg;
Mauro Carvalho Chehaba5abdb62011-10-04 14:16:14 -0300234 *std = V4L2_STD_ALL;
Mauro Carvalho Chehab7383a472011-10-03 12:22:28 -0300235 ret = pvr2_hdw_get_detected_std(hdw, std);
236 break;
237 }
238
Mike Iselyd8554972006-06-26 20:58:46 -0300239 case VIDIOC_G_STD:
240 {
241 int val = 0;
242 ret = pvr2_ctrl_get_value(
243 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR),&val);
244 *(v4l2_std_id *)arg = val;
245 break;
246 }
247
248 case VIDIOC_S_STD:
249 {
250 ret = pvr2_ctrl_set_value(
251 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR),
252 *(v4l2_std_id *)arg);
253 break;
254 }
255
256 case VIDIOC_ENUMINPUT:
257 {
258 struct pvr2_ctrl *cptr;
259 struct v4l2_input *vi = (struct v4l2_input *)arg;
260 struct v4l2_input tmp;
261 unsigned int cnt;
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300262 int val;
Mike Iselyd8554972006-06-26 20:58:46 -0300263
264 cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
265
266 memset(&tmp,0,sizeof(tmp));
267 tmp.index = vi->index;
268 ret = 0;
Roel Kluin223ffe52009-05-02 16:38:47 -0300269 if (vi->index >= fh->input_cnt) {
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300270 ret = -EINVAL;
271 break;
272 }
Mike Iselye57b1c82008-04-21 03:52:34 -0300273 val = fh->input_map[vi->index];
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300274 switch (val) {
Mike Iselyd8554972006-06-26 20:58:46 -0300275 case PVR2_CVAL_INPUT_TV:
Mike Isely895c3e82008-04-22 14:45:37 -0300276 case PVR2_CVAL_INPUT_DTV:
Mike Iselyd8554972006-06-26 20:58:46 -0300277 case PVR2_CVAL_INPUT_RADIO:
278 tmp.type = V4L2_INPUT_TYPE_TUNER;
279 break;
280 case PVR2_CVAL_INPUT_SVIDEO:
281 case PVR2_CVAL_INPUT_COMPOSITE:
282 tmp.type = V4L2_INPUT_TYPE_CAMERA;
283 break;
284 default:
285 ret = -EINVAL;
286 break;
287 }
288 if (ret < 0) break;
289
290 cnt = 0;
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300291 pvr2_ctrl_get_valname(cptr,val,
Mike Iselyd8554972006-06-26 20:58:46 -0300292 tmp.name,sizeof(tmp.name)-1,&cnt);
293 tmp.name[cnt] = 0;
294
295 /* Don't bother with audioset, since this driver currently
296 always switches the audio whenever the video is
297 switched. */
298
299 /* Handling std is a tougher problem. It doesn't make
300 sense in cases where a device might be multi-standard.
301 We could just copy out the current value for the
302 standard, but it can change over time. For now just
303 leave it zero. */
304
305 memcpy(vi, &tmp, sizeof(tmp));
306
307 ret = 0;
308 break;
309 }
310
311 case VIDIOC_G_INPUT:
312 {
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300313 unsigned int idx;
Mike Iselyd8554972006-06-26 20:58:46 -0300314 struct pvr2_ctrl *cptr;
315 struct v4l2_input *vi = (struct v4l2_input *)arg;
316 int val;
317 cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
318 val = 0;
319 ret = pvr2_ctrl_get_value(cptr,&val);
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300320 vi->index = 0;
Mike Iselye57b1c82008-04-21 03:52:34 -0300321 for (idx = 0; idx < fh->input_cnt; idx++) {
322 if (fh->input_map[idx] == val) {
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300323 vi->index = idx;
324 break;
325 }
326 }
Mike Iselyd8554972006-06-26 20:58:46 -0300327 break;
328 }
329
330 case VIDIOC_S_INPUT:
331 {
332 struct v4l2_input *vi = (struct v4l2_input *)arg;
Roel Kluin223ffe52009-05-02 16:38:47 -0300333 if (vi->index >= fh->input_cnt) {
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300334 ret = -ERANGE;
335 break;
336 }
Mike Iselyd8554972006-06-26 20:58:46 -0300337 ret = pvr2_ctrl_set_value(
338 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
Mike Iselye57b1c82008-04-21 03:52:34 -0300339 fh->input_map[vi->index]);
Mike Iselyd8554972006-06-26 20:58:46 -0300340 break;
341 }
342
343 case VIDIOC_ENUMAUDIO:
344 {
Pantelis Koukousoulas848ed3c2007-01-20 01:57:36 -0300345 /* pkt: FIXME: We are returning one "fake" input here
346 which could very well be called "whatever_we_like".
347 This is for apps that want to see an audio input
348 just to feel comfortable, as well as to test if
349 it can do stereo or sth. There is actually no guarantee
350 that the actual audio input cannot change behind the app's
351 back, but most applications should not mind that either.
352
353 Hopefully, mplayer people will work with us on this (this
354 whole mess is to support mplayer pvr://), or Hans will come
355 up with a more standard way to say "we have inputs but we
356 don 't want you to change them independent of video" which
357 will sort this mess.
358 */
359 struct v4l2_audio *vin = arg;
Mike Iselyd8554972006-06-26 20:58:46 -0300360 ret = -EINVAL;
Pantelis Koukousoulas848ed3c2007-01-20 01:57:36 -0300361 if (vin->index > 0) break;
362 strncpy(vin->name, "PVRUSB2 Audio",14);
363 vin->capability = V4L2_AUDCAP_STEREO;
364 ret = 0;
365 break;
Mike Iselyd8554972006-06-26 20:58:46 -0300366 break;
367 }
368
369 case VIDIOC_G_AUDIO:
370 {
Pantelis Koukousoulas848ed3c2007-01-20 01:57:36 -0300371 /* pkt: FIXME: see above comment (VIDIOC_ENUMAUDIO) */
372 struct v4l2_audio *vin = arg;
373 memset(vin,0,sizeof(*vin));
374 vin->index = 0;
375 strncpy(vin->name, "PVRUSB2 Audio",14);
376 vin->capability = V4L2_AUDCAP_STEREO;
377 ret = 0;
Mike Iselyd8554972006-06-26 20:58:46 -0300378 break;
379 }
380
Mike Iselyd8554972006-06-26 20:58:46 -0300381 case VIDIOC_G_TUNER:
382 {
383 struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
Mauro Carvalho Chehab5cc1dd82007-01-21 22:02:58 -0300384
Michael Krufky8d364362007-01-22 02:17:55 -0300385 if (vt->index != 0) break; /* Only answer for the 1st tuner */
Mauro Carvalho Chehab5cc1dd82007-01-21 22:02:58 -0300386
Mike Isely18103c52007-01-20 00:09:47 -0300387 pvr2_hdw_execute_tuner_poll(hdw);
388 ret = pvr2_hdw_get_tuner_status(hdw,vt);
Mike Iselyd8554972006-06-26 20:58:46 -0300389 break;
390 }
391
392 case VIDIOC_S_TUNER:
393 {
394 struct v4l2_tuner *vt=(struct v4l2_tuner *)arg;
395
396 if (vt->index != 0)
397 break;
398
399 ret = pvr2_ctrl_set_value(
400 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE),
401 vt->audmode);
Mike Isely11fc76c2007-01-20 00:24:52 -0300402 break;
Mike Iselyd8554972006-06-26 20:58:46 -0300403 }
404
405 case VIDIOC_S_FREQUENCY:
406 {
407 const struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
Mike Iselyc0e69312006-12-27 23:25:06 -0300408 unsigned long fv;
Mike Isely18103c52007-01-20 00:09:47 -0300409 struct v4l2_tuner vt;
410 int cur_input;
411 struct pvr2_ctrl *ctrlp;
412 ret = pvr2_hdw_get_tuner_status(hdw,&vt);
413 if (ret != 0) break;
414 ctrlp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
415 ret = pvr2_ctrl_get_value(ctrlp,&cur_input);
416 if (ret != 0) break;
Mike Iselyc0e69312006-12-27 23:25:06 -0300417 if (vf->type == V4L2_TUNER_RADIO) {
Mike Isely18103c52007-01-20 00:09:47 -0300418 if (cur_input != PVR2_CVAL_INPUT_RADIO) {
419 pvr2_ctrl_set_value(ctrlp,
420 PVR2_CVAL_INPUT_RADIO);
421 }
422 } else {
423 if (cur_input == PVR2_CVAL_INPUT_RADIO) {
424 pvr2_ctrl_set_value(ctrlp,
425 PVR2_CVAL_INPUT_TV);
426 }
427 }
428 fv = vf->frequency;
429 if (vt.capability & V4L2_TUNER_CAP_LOW) {
Mike Iselyc0e69312006-12-27 23:25:06 -0300430 fv = (fv * 125) / 2;
431 } else {
432 fv = fv * 62500;
433 }
Mike Iselyd8554972006-06-26 20:58:46 -0300434 ret = pvr2_ctrl_set_value(
Mike Iselyc0e69312006-12-27 23:25:06 -0300435 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),fv);
Mike Iselyd8554972006-06-26 20:58:46 -0300436 break;
437 }
438
439 case VIDIOC_G_FREQUENCY:
440 {
441 struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
442 int val = 0;
Mike Isely18103c52007-01-20 00:09:47 -0300443 int cur_input;
444 struct v4l2_tuner vt;
445 ret = pvr2_hdw_get_tuner_status(hdw,&vt);
446 if (ret != 0) break;
Mike Iselyd8554972006-06-26 20:58:46 -0300447 ret = pvr2_ctrl_get_value(
448 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),
449 &val);
Mike Iselyc0e69312006-12-27 23:25:06 -0300450 if (ret != 0) break;
451 pvr2_ctrl_get_value(
452 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
453 &cur_input);
454 if (cur_input == PVR2_CVAL_INPUT_RADIO) {
Mike Iselyc0e69312006-12-27 23:25:06 -0300455 vf->type = V4L2_TUNER_RADIO;
456 } else {
Mike Iselyc0e69312006-12-27 23:25:06 -0300457 vf->type = V4L2_TUNER_ANALOG_TV;
458 }
Mike Isely18103c52007-01-20 00:09:47 -0300459 if (vt.capability & V4L2_TUNER_CAP_LOW) {
460 val = (val * 2) / 125;
461 } else {
462 val /= 62500;
463 }
464 vf->frequency = val;
Mike Iselyd8554972006-06-26 20:58:46 -0300465 break;
466 }
467
468 case VIDIOC_ENUM_FMT:
469 {
470 struct v4l2_fmtdesc *fd = (struct v4l2_fmtdesc *)arg;
471
472 /* Only one format is supported : mpeg.*/
473 if (fd->index != 0)
474 break;
475
476 memcpy(fd, pvr_fmtdesc, sizeof(struct v4l2_fmtdesc));
477 ret = 0;
478 break;
479 }
480
481 case VIDIOC_G_FMT:
482 {
483 struct v4l2_format *vf = (struct v4l2_format *)arg;
484 int val;
485 switch(vf->type) {
486 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
487 memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
488 sizeof(struct v4l2_format));
489 val = 0;
490 pvr2_ctrl_get_value(
491 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES),
492 &val);
493 vf->fmt.pix.width = val;
494 val = 0;
495 pvr2_ctrl_get_value(
Mike Iselyd8554972006-06-26 20:58:46 -0300496 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES),
497 &val);
498 vf->fmt.pix.height = val;
499 ret = 0;
500 break;
501 case V4L2_BUF_TYPE_VBI_CAPTURE:
502 // ????? Still need to figure out to do VBI correctly
503 ret = -EINVAL;
504 break;
505 default:
506 ret = -EINVAL;
507 break;
508 }
509 break;
510 }
511
512 case VIDIOC_TRY_FMT:
513 case VIDIOC_S_FMT:
514 {
515 struct v4l2_format *vf = (struct v4l2_format *)arg;
516
517 ret = 0;
518 switch(vf->type) {
519 case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
Pantelis Koukousoulasfd694962007-01-20 01:59:54 -0300520 int lmin,lmax,ldef;
Mike Iselye95a1912006-08-08 09:10:07 -0300521 struct pvr2_ctrl *hcp,*vcp;
Mike Iselyd8554972006-06-26 20:58:46 -0300522 int h = vf->fmt.pix.height;
523 int w = vf->fmt.pix.width;
Mike Iselye95a1912006-08-08 09:10:07 -0300524 hcp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES);
525 vcp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES);
Mike Iselyd8554972006-06-26 20:58:46 -0300526
Mike Iselye95a1912006-08-08 09:10:07 -0300527 lmin = pvr2_ctrl_get_min(hcp);
528 lmax = pvr2_ctrl_get_max(hcp);
Mike Isely26dd1c52008-08-31 20:55:03 -0300529 pvr2_ctrl_get_def(hcp, &ldef);
Pantelis Koukousoulasfd694962007-01-20 01:59:54 -0300530 if (w == -1) {
531 w = ldef;
532 } else if (w < lmin) {
Mike Iselye95a1912006-08-08 09:10:07 -0300533 w = lmin;
534 } else if (w > lmax) {
535 w = lmax;
Mike Isely039c4302006-06-25 20:04:16 -0300536 }
Hans Verkuilb31e3412006-09-01 18:36:10 -0300537 lmin = pvr2_ctrl_get_min(vcp);
538 lmax = pvr2_ctrl_get_max(vcp);
Mike Isely26dd1c52008-08-31 20:55:03 -0300539 pvr2_ctrl_get_def(vcp, &ldef);
Pantelis Koukousoulasfd694962007-01-20 01:59:54 -0300540 if (h == -1) {
541 h = ldef;
542 } else if (h < lmin) {
Hans Verkuilb31e3412006-09-01 18:36:10 -0300543 h = lmin;
544 } else if (h > lmax) {
545 h = lmax;
546 }
Mike Iselyd8554972006-06-26 20:58:46 -0300547
548 memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
549 sizeof(struct v4l2_format));
Mike Isely039c4302006-06-25 20:04:16 -0300550 vf->fmt.pix.width = w;
551 vf->fmt.pix.height = h;
Mike Iselyd8554972006-06-26 20:58:46 -0300552
553 if (cmd == VIDIOC_S_FMT) {
Mike Iselye95a1912006-08-08 09:10:07 -0300554 pvr2_ctrl_set_value(hcp,vf->fmt.pix.width);
555 pvr2_ctrl_set_value(vcp,vf->fmt.pix.height);
Mike Iselyd8554972006-06-26 20:58:46 -0300556 }
557 } break;
558 case V4L2_BUF_TYPE_VBI_CAPTURE:
559 // ????? Still need to figure out to do VBI correctly
560 ret = -EINVAL;
561 break;
562 default:
563 ret = -EINVAL;
564 break;
565 }
566 break;
567 }
568
569 case VIDIOC_STREAMON:
570 {
Joe Perches108bdd72010-04-05 16:05:39 -0300571 if (!fh->pdi->stream) {
Mike Isely16eb40d2006-12-30 18:27:32 -0300572 /* No stream defined for this node. This means
573 that we're not currently allowed to stream from
574 this node. */
575 ret = -EPERM;
576 break;
577 }
Joe Perches108bdd72010-04-05 16:05:39 -0300578 ret = pvr2_hdw_set_stream_type(hdw,pdi->config);
Mike Iselyd8554972006-06-26 20:58:46 -0300579 if (ret < 0) return ret;
580 ret = pvr2_hdw_set_streaming(hdw,!0);
581 break;
582 }
583
584 case VIDIOC_STREAMOFF:
585 {
Joe Perches108bdd72010-04-05 16:05:39 -0300586 if (!fh->pdi->stream) {
Mike Isely16eb40d2006-12-30 18:27:32 -0300587 /* No stream defined for this node. This means
588 that we're not currently allowed to stream from
589 this node. */
590 ret = -EPERM;
591 break;
592 }
Mike Iselyd8554972006-06-26 20:58:46 -0300593 ret = pvr2_hdw_set_streaming(hdw,0);
594 break;
595 }
596
597 case VIDIOC_QUERYCTRL:
598 {
599 struct pvr2_ctrl *cptr;
Mike Isely26dd1c52008-08-31 20:55:03 -0300600 int val;
Mike Iselyd8554972006-06-26 20:58:46 -0300601 struct v4l2_queryctrl *vc = (struct v4l2_queryctrl *)arg;
602 ret = 0;
Mike Isely1d9f8462006-06-25 20:04:58 -0300603 if (vc->id & V4L2_CTRL_FLAG_NEXT_CTRL) {
604 cptr = pvr2_hdw_get_ctrl_nextv4l(
605 hdw,(vc->id & ~V4L2_CTRL_FLAG_NEXT_CTRL));
606 if (cptr) vc->id = pvr2_ctrl_get_v4lid(cptr);
607 } else {
608 cptr = pvr2_hdw_get_ctrl_v4l(hdw,vc->id);
609 }
Mike Iselyd8554972006-06-26 20:58:46 -0300610 if (!cptr) {
Mike Isely0885ba12006-06-25 21:30:47 -0300611 pvr2_trace(PVR2_TRACE_V4LIOCTL,
Mike Iselya761f432006-06-25 20:04:44 -0300612 "QUERYCTRL id=0x%x not implemented here",
613 vc->id);
Mike Iselyd8554972006-06-26 20:58:46 -0300614 ret = -EINVAL;
615 break;
616 }
617
Mike Iselya761f432006-06-25 20:04:44 -0300618 pvr2_trace(PVR2_TRACE_V4LIOCTL,
619 "QUERYCTRL id=0x%x mapping name=%s (%s)",
620 vc->id,pvr2_ctrl_get_name(cptr),
621 pvr2_ctrl_get_desc(cptr));
622 strlcpy(vc->name,pvr2_ctrl_get_desc(cptr),sizeof(vc->name));
623 vc->flags = pvr2_ctrl_get_v4lflags(cptr);
Mike Isely26dd1c52008-08-31 20:55:03 -0300624 pvr2_ctrl_get_def(cptr, &val);
625 vc->default_value = val;
Mike Iselyd8554972006-06-26 20:58:46 -0300626 switch (pvr2_ctrl_get_type(cptr)) {
627 case pvr2_ctl_enum:
628 vc->type = V4L2_CTRL_TYPE_MENU;
629 vc->minimum = 0;
630 vc->maximum = pvr2_ctrl_get_cnt(cptr) - 1;
631 vc->step = 1;
632 break;
Mike Isely33213962006-06-25 20:04:40 -0300633 case pvr2_ctl_bool:
Mike Isely1d9f8462006-06-25 20:04:58 -0300634 vc->type = V4L2_CTRL_TYPE_BOOLEAN;
Mike Isely33213962006-06-25 20:04:40 -0300635 vc->minimum = 0;
636 vc->maximum = 1;
637 vc->step = 1;
638 break;
Mike Iselyd8554972006-06-26 20:58:46 -0300639 case pvr2_ctl_int:
640 vc->type = V4L2_CTRL_TYPE_INTEGER;
641 vc->minimum = pvr2_ctrl_get_min(cptr);
642 vc->maximum = pvr2_ctrl_get_max(cptr);
643 vc->step = 1;
644 break;
645 default:
Mike Isely0885ba12006-06-25 21:30:47 -0300646 pvr2_trace(PVR2_TRACE_V4LIOCTL,
Mike Iselya761f432006-06-25 20:04:44 -0300647 "QUERYCTRL id=0x%x name=%s not mappable",
648 vc->id,pvr2_ctrl_get_name(cptr));
Mike Iselyd8554972006-06-26 20:58:46 -0300649 ret = -EINVAL;
650 break;
651 }
652 break;
653 }
654
655 case VIDIOC_QUERYMENU:
656 {
657 struct v4l2_querymenu *vm = (struct v4l2_querymenu *)arg;
658 unsigned int cnt = 0;
659 ret = pvr2_ctrl_get_valname(pvr2_hdw_get_ctrl_v4l(hdw,vm->id),
660 vm->index,
661 vm->name,sizeof(vm->name)-1,
662 &cnt);
663 vm->name[cnt] = 0;
664 break;
665 }
666
667 case VIDIOC_G_CTRL:
668 {
669 struct v4l2_control *vc = (struct v4l2_control *)arg;
670 int val = 0;
671 ret = pvr2_ctrl_get_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id),
672 &val);
673 vc->value = val;
674 break;
675 }
676
677 case VIDIOC_S_CTRL:
678 {
679 struct v4l2_control *vc = (struct v4l2_control *)arg;
680 ret = pvr2_ctrl_set_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id),
681 vc->value);
682 break;
683 }
684
Mike Isely1d9f8462006-06-25 20:04:58 -0300685 case VIDIOC_G_EXT_CTRLS:
686 {
687 struct v4l2_ext_controls *ctls =
688 (struct v4l2_ext_controls *)arg;
689 struct v4l2_ext_control *ctrl;
690 unsigned int idx;
691 int val;
Mike Iselyc1c26802007-01-20 00:30:23 -0300692 ret = 0;
Mike Isely1d9f8462006-06-25 20:04:58 -0300693 for (idx = 0; idx < ctls->count; idx++) {
694 ctrl = ctls->controls + idx;
695 ret = pvr2_ctrl_get_value(
696 pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),&val);
697 if (ret) {
698 ctls->error_idx = idx;
699 break;
700 }
701 /* Ensure that if read as a 64 bit value, the user
702 will still get a hopefully sane value */
703 ctrl->value64 = 0;
704 ctrl->value = val;
705 }
706 break;
707 }
708
709 case VIDIOC_S_EXT_CTRLS:
710 {
711 struct v4l2_ext_controls *ctls =
712 (struct v4l2_ext_controls *)arg;
713 struct v4l2_ext_control *ctrl;
714 unsigned int idx;
Mike Iselyc1c26802007-01-20 00:30:23 -0300715 ret = 0;
Mike Isely1d9f8462006-06-25 20:04:58 -0300716 for (idx = 0; idx < ctls->count; idx++) {
717 ctrl = ctls->controls + idx;
718 ret = pvr2_ctrl_set_value(
719 pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),
720 ctrl->value);
721 if (ret) {
722 ctls->error_idx = idx;
723 break;
724 }
725 }
726 break;
727 }
728
729 case VIDIOC_TRY_EXT_CTRLS:
730 {
731 struct v4l2_ext_controls *ctls =
732 (struct v4l2_ext_controls *)arg;
733 struct v4l2_ext_control *ctrl;
734 struct pvr2_ctrl *pctl;
735 unsigned int idx;
736 /* For the moment just validate that the requested control
737 actually exists. */
Mike Iselyc1c26802007-01-20 00:30:23 -0300738 ret = 0;
Mike Isely1d9f8462006-06-25 20:04:58 -0300739 for (idx = 0; idx < ctls->count; idx++) {
740 ctrl = ctls->controls + idx;
741 pctl = pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id);
742 if (!pctl) {
743 ret = -EINVAL;
744 ctls->error_idx = idx;
745 break;
746 }
747 }
748 break;
749 }
750
Mike Isely432907f2008-08-31 21:02:20 -0300751 case VIDIOC_CROPCAP:
752 {
753 struct v4l2_cropcap *cap = (struct v4l2_cropcap *)arg;
754 if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
755 ret = -EINVAL;
756 break;
757 }
758 ret = pvr2_hdw_get_cropcap(hdw, cap);
759 cap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* paranoia */
760 break;
761 }
762 case VIDIOC_G_CROP:
763 {
764 struct v4l2_crop *crop = (struct v4l2_crop *)arg;
765 int val = 0;
766 if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
767 ret = -EINVAL;
768 break;
769 }
770 ret = pvr2_ctrl_get_value(
771 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL), &val);
772 if (ret != 0) {
773 ret = -EINVAL;
774 break;
775 }
776 crop->c.left = val;
777 ret = pvr2_ctrl_get_value(
778 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT), &val);
779 if (ret != 0) {
780 ret = -EINVAL;
781 break;
782 }
783 crop->c.top = val;
784 ret = pvr2_ctrl_get_value(
785 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW), &val);
786 if (ret != 0) {
787 ret = -EINVAL;
788 break;
789 }
790 crop->c.width = val;
791 ret = pvr2_ctrl_get_value(
792 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH), &val);
793 if (ret != 0) {
794 ret = -EINVAL;
795 break;
796 }
797 crop->c.height = val;
798 }
799 case VIDIOC_S_CROP:
800 {
801 struct v4l2_crop *crop = (struct v4l2_crop *)arg;
Mike Isely432907f2008-08-31 21:02:20 -0300802 if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
803 ret = -EINVAL;
804 break;
805 }
Mike Isely432907f2008-08-31 21:02:20 -0300806 ret = pvr2_ctrl_set_value(
807 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL),
808 crop->c.left);
809 if (ret != 0) {
810 ret = -EINVAL;
811 break;
812 }
813 ret = pvr2_ctrl_set_value(
814 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT),
815 crop->c.top);
816 if (ret != 0) {
817 ret = -EINVAL;
818 break;
819 }
820 ret = pvr2_ctrl_set_value(
821 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW),
822 crop->c.width);
823 if (ret != 0) {
824 ret = -EINVAL;
825 break;
826 }
827 ret = pvr2_ctrl_set_value(
828 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH),
829 crop->c.height);
830 if (ret != 0) {
831 ret = -EINVAL;
832 break;
833 }
834 }
Mike Iselyd8554972006-06-26 20:58:46 -0300835 case VIDIOC_LOG_STATUS:
836 {
Mike Iselyd8554972006-06-26 20:58:46 -0300837 pvr2_hdw_trigger_module_log(hdw);
Mike Iselyd8554972006-06-26 20:58:46 -0300838 ret = 0;
839 break;
840 }
Mike Isely32ffa9a2006-09-23 22:26:52 -0300841#ifdef CONFIG_VIDEO_ADV_DEBUG
Trent Piepho52ebc762007-01-23 22:38:13 -0300842 case VIDIOC_DBG_S_REGISTER:
Trent Piepho52ebc762007-01-23 22:38:13 -0300843 case VIDIOC_DBG_G_REGISTER:
Mike Isely32ffa9a2006-09-23 22:26:52 -0300844 {
Hans Verkuilf3d092b2007-02-23 20:55:14 -0300845 u64 val;
Hans Verkuilaecde8b2008-12-30 07:14:19 -0300846 struct v4l2_dbg_register *req = (struct v4l2_dbg_register *)arg;
Trent Piepho52ebc762007-01-23 22:38:13 -0300847 if (cmd == VIDIOC_DBG_S_REGISTER) val = req->val;
Mike Isely32ffa9a2006-09-23 22:26:52 -0300848 ret = pvr2_hdw_register_access(
Hans Verkuilaecde8b2008-12-30 07:14:19 -0300849 hdw, &req->match, req->reg,
850 cmd == VIDIOC_DBG_S_REGISTER, &val);
Trent Piepho52ebc762007-01-23 22:38:13 -0300851 if (cmd == VIDIOC_DBG_G_REGISTER) req->val = val;
Mike Isely32ffa9a2006-09-23 22:26:52 -0300852 break;
853 }
854#endif
Mike Iselyd8554972006-06-26 20:58:46 -0300855
856 default :
Mauro Carvalho Chehab7a286cc2011-06-26 10:18:03 -0300857 ret = -ENOTTY;
Hans Verkuil08af2452010-12-24 10:33:19 -0300858 break;
Mike Iselyd8554972006-06-26 20:58:46 -0300859 }
860
861 pvr2_hdw_commit_ctl(hdw);
862
863 if (ret < 0) {
864 if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
Mike Isely0885ba12006-06-25 21:30:47 -0300865 pvr2_trace(PVR2_TRACE_V4LIOCTL,
Hans Verkuil069b7472008-12-30 07:04:34 -0300866 "pvr2_v4l2_do_ioctl failure, ret=%ld", ret);
Mike Iselyd8554972006-06-26 20:58:46 -0300867 } else {
Mike Isely0885ba12006-06-25 21:30:47 -0300868 if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
869 pvr2_trace(PVR2_TRACE_V4LIOCTL,
Hans Verkuil069b7472008-12-30 07:04:34 -0300870 "pvr2_v4l2_do_ioctl failure, ret=%ld"
871 " command was:", ret);
Mike Iselyd8554972006-06-26 20:58:46 -0300872 v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),
873 cmd);
874 }
875 }
876 } else {
877 pvr2_trace(PVR2_TRACE_V4LIOCTL,
Hans Verkuil069b7472008-12-30 07:04:34 -0300878 "pvr2_v4l2_do_ioctl complete, ret=%ld (0x%lx)",
879 ret, ret);
Mike Iselyd8554972006-06-26 20:58:46 -0300880 }
881 return ret;
882}
883
Mike Iselyd8554972006-06-26 20:58:46 -0300884static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
885{
Mike Isely0f0f2572006-12-27 23:19:42 -0300886 struct pvr2_hdw *hdw = dip->v4lp->channel.mc_head->hdw;
Mike Isely16eb40d2006-12-30 18:27:32 -0300887 enum pvr2_config cfg = dip->config;
Mike Iselyd72baad2010-05-15 00:15:38 -0300888 char msg[80];
889 unsigned int mcnt;
890
891 /* Construct the unregistration message *before* we actually
892 perform the unregistration step. By doing it this way we don't
893 have to worry about potentially touching deleted resources. */
894 mcnt = scnprintf(msg, sizeof(msg) - 1,
895 "pvrusb2: unregistered device %s [%s]",
896 video_device_node_name(&dip->devbase),
897 pvr2_config_get_name(cfg));
898 msg[mcnt] = 0;
Mike Isely0f0f2572006-12-27 23:19:42 -0300899
Mike Isely16eb40d2006-12-30 18:27:32 -0300900 pvr2_hdw_v4l_store_minor_number(hdw,dip->minor_type,-1);
Mike Isely75910052006-09-23 22:30:50 -0300901
902 /* Paranoia */
Randy Dunlapc2625bf2006-10-29 11:12:27 -0300903 dip->v4lp = NULL;
904 dip->stream = NULL;
Mike Isely75910052006-09-23 22:30:50 -0300905
906 /* Actual deallocation happens later when all internal references
907 are gone. */
908 video_unregister_device(&dip->devbase);
Mike Isely0f0f2572006-12-27 23:19:42 -0300909
Mike Iselyd72baad2010-05-15 00:15:38 -0300910 printk(KERN_INFO "%s\n", msg);
Mike Isely0f0f2572006-12-27 23:19:42 -0300911
Mike Iselyd8554972006-06-26 20:58:46 -0300912}
913
914
Mike Isely4a89baa2009-10-12 00:13:28 -0300915static void pvr2_v4l2_dev_disassociate_parent(struct pvr2_v4l2_dev *dip)
916{
917 if (!dip) return;
918 if (!dip->devbase.parent) return;
919 dip->devbase.parent = NULL;
920 device_move(&dip->devbase.dev, NULL, DPM_ORDER_NONE);
921}
922
923
Mike Iselyd8554972006-06-26 20:58:46 -0300924static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp)
925{
Mike Isely0f0f2572006-12-27 23:19:42 -0300926 if (vp->dev_video) {
927 pvr2_v4l2_dev_destroy(vp->dev_video);
Al Viro89952d12007-03-14 09:17:59 +0000928 vp->dev_video = NULL;
Mike Isely0f0f2572006-12-27 23:19:42 -0300929 }
930 if (vp->dev_radio) {
931 pvr2_v4l2_dev_destroy(vp->dev_radio);
Al Viro89952d12007-03-14 09:17:59 +0000932 vp->dev_radio = NULL;
Mike Isely0f0f2572006-12-27 23:19:42 -0300933 }
Mike Iselyd8554972006-06-26 20:58:46 -0300934
935 pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp);
936 pvr2_channel_done(&vp->channel);
937 kfree(vp);
938}
939
940
Mike Isely75910052006-09-23 22:30:50 -0300941static void pvr2_video_device_release(struct video_device *vdev)
942{
943 struct pvr2_v4l2_dev *dev;
944 dev = container_of(vdev,struct pvr2_v4l2_dev,devbase);
945 kfree(dev);
946}
947
948
Adrian Bunk07e337e2006-06-30 11:30:20 -0300949static void pvr2_v4l2_internal_check(struct pvr2_channel *chp)
Mike Iselyd8554972006-06-26 20:58:46 -0300950{
951 struct pvr2_v4l2 *vp;
952 vp = container_of(chp,struct pvr2_v4l2,channel);
953 if (!vp->channel.mc_head->disconnect_flag) return;
Mike Isely4a89baa2009-10-12 00:13:28 -0300954 pvr2_v4l2_dev_disassociate_parent(vp->dev_video);
955 pvr2_v4l2_dev_disassociate_parent(vp->dev_radio);
Mike Iselyd8554972006-06-26 20:58:46 -0300956 if (vp->vfirst) return;
957 pvr2_v4l2_destroy_no_lock(vp);
958}
959
960
Hans Verkuil069b7472008-12-30 07:04:34 -0300961static long pvr2_v4l2_ioctl(struct file *file,
Adrian Bunk07e337e2006-06-30 11:30:20 -0300962 unsigned int cmd, unsigned long arg)
Mike Iselyd8554972006-06-26 20:58:46 -0300963{
964
Hans Verkuilf473bf72008-11-01 08:25:11 -0300965 return video_usercopy(file, cmd, arg, pvr2_v4l2_do_ioctl);
Mike Iselyd8554972006-06-26 20:58:46 -0300966}
967
968
Hans Verkuilbec43662008-12-30 06:58:20 -0300969static int pvr2_v4l2_release(struct file *file)
Mike Iselyd8554972006-06-26 20:58:46 -0300970{
971 struct pvr2_v4l2_fh *fhp = file->private_data;
972 struct pvr2_v4l2 *vp = fhp->vhead;
Mike Iselyc74e0062006-12-30 18:31:22 -0300973 struct pvr2_hdw *hdw = fhp->channel.mc_head->hdw;
Mike Iselyd8554972006-06-26 20:58:46 -0300974
975 pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_release");
976
977 if (fhp->rhp) {
978 struct pvr2_stream *sp;
Mike Iselyd8554972006-06-26 20:58:46 -0300979 pvr2_hdw_set_streaming(hdw,0);
980 sp = pvr2_ioread_get_stream(fhp->rhp);
Mike Iselya0fd1cb2006-06-30 11:35:28 -0300981 if (sp) pvr2_stream_set_callback(sp,NULL,NULL);
Mike Iselyd8554972006-06-26 20:58:46 -0300982 pvr2_ioread_destroy(fhp->rhp);
Mike Iselya0fd1cb2006-06-30 11:35:28 -0300983 fhp->rhp = NULL;
Mike Iselyd8554972006-06-26 20:58:46 -0300984 }
Pantelis Koukousoulasae2b9e22006-12-27 23:09:55 -0300985
Hans Verkuilffb48772010-05-01 08:03:24 -0300986 v4l2_prio_close(&vp->prio, fhp->prio);
Mike Iselyd8554972006-06-26 20:58:46 -0300987 file->private_data = NULL;
988
Mike Isely794b1602008-04-22 14:45:45 -0300989 if (fhp->vnext) {
990 fhp->vnext->vprev = fhp->vprev;
991 } else {
992 vp->vlast = fhp->vprev;
993 }
994 if (fhp->vprev) {
995 fhp->vprev->vnext = fhp->vnext;
996 } else {
997 vp->vfirst = fhp->vnext;
998 }
999 fhp->vnext = NULL;
1000 fhp->vprev = NULL;
1001 fhp->vhead = NULL;
1002 pvr2_channel_done(&fhp->channel);
1003 pvr2_trace(PVR2_TRACE_STRUCT,
1004 "Destroying pvr_v4l2_fh id=%p",fhp);
Mike Iselye57b1c82008-04-21 03:52:34 -03001005 if (fhp->input_map) {
1006 kfree(fhp->input_map);
1007 fhp->input_map = NULL;
1008 }
Mike Isely794b1602008-04-22 14:45:45 -03001009 kfree(fhp);
1010 if (vp->channel.mc_head->disconnect_flag && !vp->vfirst) {
1011 pvr2_v4l2_destroy_no_lock(vp);
1012 }
Mike Iselyd8554972006-06-26 20:58:46 -03001013 return 0;
1014}
1015
1016
Hans Verkuilbec43662008-12-30 06:58:20 -03001017static int pvr2_v4l2_open(struct file *file)
Mike Iselyd8554972006-06-26 20:58:46 -03001018{
Mike Isely75910052006-09-23 22:30:50 -03001019 struct pvr2_v4l2_dev *dip; /* Our own context pointer */
Mike Iselyd8554972006-06-26 20:58:46 -03001020 struct pvr2_v4l2_fh *fhp;
1021 struct pvr2_v4l2 *vp;
1022 struct pvr2_hdw *hdw;
Mike Isely1cb03b72008-04-21 03:47:43 -03001023 unsigned int input_mask = 0;
Mike Iselye57b1c82008-04-21 03:52:34 -03001024 unsigned int input_cnt,idx;
Mike Isely1cb03b72008-04-21 03:47:43 -03001025 int ret = 0;
Mike Iselyd8554972006-06-26 20:58:46 -03001026
Mike Isely75910052006-09-23 22:30:50 -03001027 dip = container_of(video_devdata(file),struct pvr2_v4l2_dev,devbase);
Mike Iselyd8554972006-06-26 20:58:46 -03001028
1029 vp = dip->v4lp;
1030 hdw = vp->channel.hdw;
1031
1032 pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_open");
1033
1034 if (!pvr2_hdw_dev_ok(hdw)) {
1035 pvr2_trace(PVR2_TRACE_OPEN_CLOSE,
1036 "pvr2_v4l2_open: hardware not ready");
1037 return -EIO;
1038 }
1039
Mike Isely4b85dee2007-01-20 00:03:32 -03001040 fhp = kzalloc(sizeof(*fhp),GFP_KERNEL);
Mike Iselyd8554972006-06-26 20:58:46 -03001041 if (!fhp) {
1042 return -ENOMEM;
1043 }
Mike Iselyd8554972006-06-26 20:58:46 -03001044
1045 init_waitqueue_head(&fhp->wait_data);
Joe Perches108bdd72010-04-05 16:05:39 -03001046 fhp->pdi = dip;
Mike Iselyd8554972006-06-26 20:58:46 -03001047
Mike Isely794b1602008-04-22 14:45:45 -03001048 pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp);
1049 pvr2_channel_init(&fhp->channel,vp->channel.mc_head);
Pantelis Koukousoulasae2b9e22006-12-27 23:09:55 -03001050
Mike Isely1cb03b72008-04-21 03:47:43 -03001051 if (dip->v4l_type == VFL_TYPE_RADIO) {
1052 /* Opening device as a radio, legal input selection subset
1053 is just the radio. */
1054 input_mask = (1 << PVR2_CVAL_INPUT_RADIO);
1055 } else {
1056 /* Opening the main V4L device, legal input selection
1057 subset includes all analog inputs. */
1058 input_mask = ((1 << PVR2_CVAL_INPUT_RADIO) |
1059 (1 << PVR2_CVAL_INPUT_TV) |
1060 (1 << PVR2_CVAL_INPUT_COMPOSITE) |
1061 (1 << PVR2_CVAL_INPUT_SVIDEO));
1062 }
1063 ret = pvr2_channel_limit_inputs(&fhp->channel,input_mask);
1064 if (ret) {
1065 pvr2_channel_done(&fhp->channel);
1066 pvr2_trace(PVR2_TRACE_STRUCT,
1067 "Destroying pvr_v4l2_fh id=%p (input mask error)",
1068 fhp);
1069
1070 kfree(fhp);
1071 return ret;
1072 }
1073
Mike Iselye57b1c82008-04-21 03:52:34 -03001074 input_mask &= pvr2_hdw_get_input_available(hdw);
1075 input_cnt = 0;
1076 for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) {
1077 if (input_mask & (1 << idx)) input_cnt++;
1078 }
1079 fhp->input_cnt = input_cnt;
1080 fhp->input_map = kzalloc(input_cnt,GFP_KERNEL);
1081 if (!fhp->input_map) {
1082 pvr2_channel_done(&fhp->channel);
1083 pvr2_trace(PVR2_TRACE_STRUCT,
1084 "Destroying pvr_v4l2_fh id=%p (input map failure)",
1085 fhp);
1086 kfree(fhp);
1087 return -ENOMEM;
1088 }
1089 input_cnt = 0;
1090 for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) {
1091 if (!(input_mask & (1 << idx))) continue;
1092 fhp->input_map[input_cnt++] = idx;
1093 }
1094
Mike Isely794b1602008-04-22 14:45:45 -03001095 fhp->vnext = NULL;
1096 fhp->vprev = vp->vlast;
1097 if (vp->vlast) {
1098 vp->vlast->vnext = fhp;
1099 } else {
1100 vp->vfirst = fhp;
1101 }
1102 vp->vlast = fhp;
1103 fhp->vhead = vp;
Mike Iselyc74e0062006-12-30 18:31:22 -03001104
Mike Iselyd8554972006-06-26 20:58:46 -03001105 fhp->file = file;
1106 file->private_data = fhp;
Hans Verkuilffb48772010-05-01 08:03:24 -03001107 v4l2_prio_open(&vp->prio, &fhp->prio);
Mike Iselyd8554972006-06-26 20:58:46 -03001108
1109 fhp->fw_mode_flag = pvr2_hdw_cpufw_get_enabled(hdw);
1110
1111 return 0;
1112}
1113
1114
1115static void pvr2_v4l2_notify(struct pvr2_v4l2_fh *fhp)
1116{
1117 wake_up(&fhp->wait_data);
1118}
1119
1120static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh)
1121{
1122 int ret;
1123 struct pvr2_stream *sp;
1124 struct pvr2_hdw *hdw;
1125 if (fh->rhp) return 0;
1126
Joe Perches108bdd72010-04-05 16:05:39 -03001127 if (!fh->pdi->stream) {
Mike Isely16eb40d2006-12-30 18:27:32 -03001128 /* No stream defined for this node. This means that we're
1129 not currently allowed to stream from this node. */
1130 return -EPERM;
1131 }
1132
Mike Iselyd8554972006-06-26 20:58:46 -03001133 /* First read() attempt. Try to claim the stream and start
1134 it... */
1135 if ((ret = pvr2_channel_claim_stream(&fh->channel,
Joe Perches108bdd72010-04-05 16:05:39 -03001136 fh->pdi->stream)) != 0) {
Mike Iselyd8554972006-06-26 20:58:46 -03001137 /* Someone else must already have it */
1138 return ret;
1139 }
1140
Joe Perches108bdd72010-04-05 16:05:39 -03001141 fh->rhp = pvr2_channel_create_mpeg_stream(fh->pdi->stream);
Mike Iselyd8554972006-06-26 20:58:46 -03001142 if (!fh->rhp) {
Mike Iselya0fd1cb2006-06-30 11:35:28 -03001143 pvr2_channel_claim_stream(&fh->channel,NULL);
Mike Iselyd8554972006-06-26 20:58:46 -03001144 return -ENOMEM;
1145 }
1146
1147 hdw = fh->channel.mc_head->hdw;
Joe Perches108bdd72010-04-05 16:05:39 -03001148 sp = fh->pdi->stream->stream;
Mike Iselyd8554972006-06-26 20:58:46 -03001149 pvr2_stream_set_callback(sp,(pvr2_stream_callback)pvr2_v4l2_notify,fh);
Joe Perches108bdd72010-04-05 16:05:39 -03001150 pvr2_hdw_set_stream_type(hdw,fh->pdi->config);
Mike Isely681c7392007-11-26 01:48:52 -03001151 if ((ret = pvr2_hdw_set_streaming(hdw,!0)) < 0) return ret;
1152 return pvr2_ioread_set_enabled(fh->rhp,!0);
Mike Iselyd8554972006-06-26 20:58:46 -03001153}
1154
1155
1156static ssize_t pvr2_v4l2_read(struct file *file,
1157 char __user *buff, size_t count, loff_t *ppos)
1158{
1159 struct pvr2_v4l2_fh *fh = file->private_data;
1160 int ret;
1161
1162 if (fh->fw_mode_flag) {
1163 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
1164 char *tbuf;
1165 int c1,c2;
1166 int tcnt = 0;
1167 unsigned int offs = *ppos;
1168
1169 tbuf = kmalloc(PAGE_SIZE,GFP_KERNEL);
1170 if (!tbuf) return -ENOMEM;
1171
1172 while (count) {
1173 c1 = count;
1174 if (c1 > PAGE_SIZE) c1 = PAGE_SIZE;
1175 c2 = pvr2_hdw_cpufw_get(hdw,offs,tbuf,c1);
1176 if (c2 < 0) {
1177 tcnt = c2;
1178 break;
1179 }
1180 if (!c2) break;
1181 if (copy_to_user(buff,tbuf,c2)) {
1182 tcnt = -EFAULT;
1183 break;
1184 }
1185 offs += c2;
1186 tcnt += c2;
1187 buff += c2;
1188 count -= c2;
1189 *ppos += c2;
1190 }
1191 kfree(tbuf);
1192 return tcnt;
1193 }
1194
1195 if (!fh->rhp) {
1196 ret = pvr2_v4l2_iosetup(fh);
1197 if (ret) {
1198 return ret;
1199 }
1200 }
1201
1202 for (;;) {
1203 ret = pvr2_ioread_read(fh->rhp,buff,count);
1204 if (ret >= 0) break;
1205 if (ret != -EAGAIN) break;
1206 if (file->f_flags & O_NONBLOCK) break;
1207 /* Doing blocking I/O. Wait here. */
1208 ret = wait_event_interruptible(
1209 fh->wait_data,
1210 pvr2_ioread_avail(fh->rhp) >= 0);
1211 if (ret < 0) break;
1212 }
1213
1214 return ret;
1215}
1216
1217
1218static unsigned int pvr2_v4l2_poll(struct file *file, poll_table *wait)
1219{
1220 unsigned int mask = 0;
1221 struct pvr2_v4l2_fh *fh = file->private_data;
1222 int ret;
1223
1224 if (fh->fw_mode_flag) {
1225 mask |= POLLIN | POLLRDNORM;
1226 return mask;
1227 }
1228
1229 if (!fh->rhp) {
1230 ret = pvr2_v4l2_iosetup(fh);
1231 if (ret) return POLLERR;
1232 }
1233
1234 poll_wait(file,&fh->wait_data,wait);
1235
1236 if (pvr2_ioread_avail(fh->rhp) >= 0) {
1237 mask |= POLLIN | POLLRDNORM;
1238 }
1239
1240 return mask;
1241}
1242
1243
Hans Verkuilbec43662008-12-30 06:58:20 -03001244static const struct v4l2_file_operations vdev_fops = {
Mike Iselyd8554972006-06-26 20:58:46 -03001245 .owner = THIS_MODULE,
1246 .open = pvr2_v4l2_open,
1247 .release = pvr2_v4l2_release,
1248 .read = pvr2_v4l2_read,
1249 .ioctl = pvr2_v4l2_ioctl,
Mike Iselyd8554972006-06-26 20:58:46 -03001250 .poll = pvr2_v4l2_poll,
1251};
1252
1253
Mike Iselyd8554972006-06-26 20:58:46 -03001254static struct video_device vdev_template = {
Mike Iselyd8554972006-06-26 20:58:46 -03001255 .fops = &vdev_fops,
1256};
1257
1258
1259static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
1260 struct pvr2_v4l2 *vp,
Mike Isely16eb40d2006-12-30 18:27:32 -03001261 int v4l_type)
Mike Iselyd8554972006-06-26 20:58:46 -03001262{
Mike Isely4a89baa2009-10-12 00:13:28 -03001263 struct usb_device *usbdev;
Mike Iselyd8554972006-06-26 20:58:46 -03001264 int mindevnum;
1265 int unit_number;
Al Viro89952d12007-03-14 09:17:59 +00001266 int *nr_ptr = NULL;
Mike Iselyd8554972006-06-26 20:58:46 -03001267 dip->v4lp = vp;
Mike Iselyd8554972006-06-26 20:58:46 -03001268
Mike Isely4a89baa2009-10-12 00:13:28 -03001269 usbdev = pvr2_hdw_get_dev(vp->channel.mc_head->hdw);
Mike Isely16eb40d2006-12-30 18:27:32 -03001270 dip->v4l_type = v4l_type;
1271 switch (v4l_type) {
1272 case VFL_TYPE_GRABBER:
Mike Iselyd8554972006-06-26 20:58:46 -03001273 dip->stream = &vp->channel.mc_head->video_stream;
Mike Isely16eb40d2006-12-30 18:27:32 -03001274 dip->config = pvr2_config_mpeg;
1275 dip->minor_type = pvr2_v4l_type_video;
1276 nr_ptr = video_nr;
Mike Iselyc74e0062006-12-30 18:31:22 -03001277 if (!dip->stream) {
Mauro Carvalho Chehabbe9ed512009-01-08 09:13:42 -03001278 pr_err(KBUILD_MODNAME
1279 ": Failed to set up pvrusb2 v4l video dev"
1280 " due to missing stream instance\n");
Mike Iselyc74e0062006-12-30 18:31:22 -03001281 return;
1282 }
Mike Iselyd8554972006-06-26 20:58:46 -03001283 break;
Mike Isely16eb40d2006-12-30 18:27:32 -03001284 case VFL_TYPE_VBI:
1285 dip->config = pvr2_config_vbi;
1286 dip->minor_type = pvr2_v4l_type_vbi;
1287 nr_ptr = vbi_nr;
Mike Iselyd8554972006-06-26 20:58:46 -03001288 break;
Mike Isely16eb40d2006-12-30 18:27:32 -03001289 case VFL_TYPE_RADIO:
Mike Iselyaf78a482007-01-20 00:04:31 -03001290 dip->stream = &vp->channel.mc_head->video_stream;
1291 dip->config = pvr2_config_mpeg;
Mike Isely16eb40d2006-12-30 18:27:32 -03001292 dip->minor_type = pvr2_v4l_type_radio;
1293 nr_ptr = radio_nr;
Mike Iselyd8554972006-06-26 20:58:46 -03001294 break;
1295 default:
1296 /* Bail out (this should be impossible) */
Mauro Carvalho Chehabbe9ed512009-01-08 09:13:42 -03001297 pr_err(KBUILD_MODNAME ": Failed to set up pvrusb2 v4l dev"
1298 " due to unrecognized config\n");
Mike Iselyd8554972006-06-26 20:58:46 -03001299 return;
1300 }
1301
Mike Isely75910052006-09-23 22:30:50 -03001302 memcpy(&dip->devbase,&vdev_template,sizeof(vdev_template));
1303 dip->devbase.release = pvr2_video_device_release;
Mike Iselyd8554972006-06-26 20:58:46 -03001304
1305 mindevnum = -1;
1306 unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw);
Mike Isely16eb40d2006-12-30 18:27:32 -03001307 if (nr_ptr && (unit_number >= 0) && (unit_number < PVR_NUM)) {
1308 mindevnum = nr_ptr[unit_number];
Mike Iselyd8554972006-06-26 20:58:46 -03001309 }
Mike Isely4a89baa2009-10-12 00:13:28 -03001310 dip->devbase.parent = &usbdev->dev;
Mike Isely16eb40d2006-12-30 18:27:32 -03001311 if ((video_register_device(&dip->devbase,
1312 dip->v4l_type, mindevnum) < 0) &&
1313 (video_register_device(&dip->devbase,
1314 dip->v4l_type, -1) < 0)) {
Mauro Carvalho Chehabbe9ed512009-01-08 09:13:42 -03001315 pr_err(KBUILD_MODNAME
1316 ": Failed to register pvrusb2 v4l device\n");
Pantelis Koukousoulasae2b9e22006-12-27 23:09:55 -03001317 }
Mike Isely16eb40d2006-12-30 18:27:32 -03001318
Laurent Pinchart38c7c032009-11-27 13:57:15 -03001319 printk(KERN_INFO "pvrusb2: registered device %s [%s]\n",
1320 video_device_node_name(&dip->devbase),
Mike Isely16eb40d2006-12-30 18:27:32 -03001321 pvr2_config_get_name(dip->config));
Mike Iselyd8554972006-06-26 20:58:46 -03001322
Mike Iselyd8554972006-06-26 20:58:46 -03001323 pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,
Mike Isely16eb40d2006-12-30 18:27:32 -03001324 dip->minor_type,dip->devbase.minor);
Mike Iselyd8554972006-06-26 20:58:46 -03001325}
1326
1327
1328struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
1329{
1330 struct pvr2_v4l2 *vp;
1331
Mike Isely4b85dee2007-01-20 00:03:32 -03001332 vp = kzalloc(sizeof(*vp),GFP_KERNEL);
Mike Iselyd8554972006-06-26 20:58:46 -03001333 if (!vp) return vp;
Mike Iselyd8554972006-06-26 20:58:46 -03001334 pvr2_channel_init(&vp->channel,mnp);
1335 pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp);
1336
1337 vp->channel.check_func = pvr2_v4l2_internal_check;
1338
1339 /* register streams */
Mike Iselybeb0ecd2008-04-22 14:45:38 -03001340 vp->dev_video = kzalloc(sizeof(*vp->dev_video),GFP_KERNEL);
1341 if (!vp->dev_video) goto fail;
Mike Isely16eb40d2006-12-30 18:27:32 -03001342 pvr2_v4l2_dev_init(vp->dev_video,vp,VFL_TYPE_GRABBER);
Mike Iselye57b1c82008-04-21 03:52:34 -03001343 if (pvr2_hdw_get_input_available(vp->channel.mc_head->hdw) &
1344 (1 << PVR2_CVAL_INPUT_RADIO)) {
Mike Iselybeb0ecd2008-04-22 14:45:38 -03001345 vp->dev_radio = kzalloc(sizeof(*vp->dev_radio),GFP_KERNEL);
1346 if (!vp->dev_radio) goto fail;
1347 pvr2_v4l2_dev_init(vp->dev_radio,vp,VFL_TYPE_RADIO);
1348 }
Mike Iselyd8554972006-06-26 20:58:46 -03001349
1350 return vp;
Mike Iselybeb0ecd2008-04-22 14:45:38 -03001351 fail:
1352 pvr2_trace(PVR2_TRACE_STRUCT,"Failure creating pvr2_v4l2 id=%p",vp);
1353 pvr2_v4l2_destroy_no_lock(vp);
Harvey Harrisona6a3a172008-04-28 16:50:03 -07001354 return NULL;
Mike Iselyd8554972006-06-26 20:58:46 -03001355}
1356
1357/*
1358 Stuff for Emacs to see, in order to encourage consistent editing style:
1359 *** Local Variables: ***
1360 *** mode: c ***
1361 *** fill-column: 75 ***
1362 *** tab-width: 8 ***
1363 *** c-basic-offset: 8 ***
1364 *** End: ***
1365 */