blob: cc8ddb2d2382902bb8e67194e3b79dfeaad0a65c [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>
Mauro Carvalho Chehabce4260c2006-06-26 22:26:08 -030023#include <linux/version.h>
Mike Iselyd8554972006-06-26 20:58:46 -030024#include "pvrusb2-context.h"
25#include "pvrusb2-hdw.h"
26#include "pvrusb2.h"
27#include "pvrusb2-debug.h"
28#include "pvrusb2-v4l2.h"
29#include "pvrusb2-ioread.h"
30#include <linux/videodev2.h>
Mike Isely43e06022006-09-23 23:47:50 -030031#include <media/v4l2-dev.h>
Mike Iselyd8554972006-06-26 20:58:46 -030032#include <media/v4l2-common.h>
Hans Verkuil35ea11f2008-07-20 08:12:02 -030033#include <media/v4l2-ioctl.h>
Mike Iselyd8554972006-06-26 20:58:46 -030034
35struct pvr2_v4l2_dev;
36struct pvr2_v4l2_fh;
37struct pvr2_v4l2;
38
Mike Iselyd8554972006-06-26 20:58:46 -030039struct pvr2_v4l2_dev {
Mike Isely75910052006-09-23 22:30:50 -030040 struct video_device devbase; /* MUST be first! */
Mike Iselyd8554972006-06-26 20:58:46 -030041 struct pvr2_v4l2 *v4lp;
Mike Iselyd8554972006-06-26 20:58:46 -030042 struct pvr2_context_stream *stream;
Mike Isely16eb40d2006-12-30 18:27:32 -030043 /* Information about this device: */
44 enum pvr2_config config; /* Expected stream format */
45 int v4l_type; /* V4L defined type for this device node */
46 enum pvr2_v4l_type minor_type; /* pvr2-understood minor device type */
Mike Iselyd8554972006-06-26 20:58:46 -030047};
48
49struct pvr2_v4l2_fh {
50 struct pvr2_channel channel;
51 struct pvr2_v4l2_dev *dev_info;
52 enum v4l2_priority prio;
53 struct pvr2_ioread *rhp;
54 struct file *file;
55 struct pvr2_v4l2 *vhead;
56 struct pvr2_v4l2_fh *vnext;
57 struct pvr2_v4l2_fh *vprev;
58 wait_queue_head_t wait_data;
59 int fw_mode_flag;
Mike Iselye57b1c82008-04-21 03:52:34 -030060 /* Map contiguous ordinal value to input id */
61 unsigned char *input_map;
62 unsigned int input_cnt;
Mike Iselyd8554972006-06-26 20:58:46 -030063};
64
65struct pvr2_v4l2 {
66 struct pvr2_channel channel;
67 struct pvr2_v4l2_fh *vfirst;
68 struct pvr2_v4l2_fh *vlast;
69
70 struct v4l2_prio_state prio;
71
Mike Isely0f0f2572006-12-27 23:19:42 -030072 /* streams - Note that these must be separately, individually,
73 * allocated pointers. This is because the v4l core is going to
74 * manage their deletion - separately, individually... */
75 struct pvr2_v4l2_dev *dev_video;
76 struct pvr2_v4l2_dev *dev_radio;
Mike Iselyd8554972006-06-26 20:58:46 -030077};
78
79static int video_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
80module_param_array(video_nr, int, NULL, 0444);
Mike Isely5e6862c2006-12-27 23:17:26 -030081MODULE_PARM_DESC(video_nr, "Offset for device's video dev minor");
82static int radio_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
83module_param_array(radio_nr, int, NULL, 0444);
84MODULE_PARM_DESC(radio_nr, "Offset for device's radio dev minor");
85static int vbi_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
86module_param_array(vbi_nr, int, NULL, 0444);
87MODULE_PARM_DESC(vbi_nr, "Offset for device's vbi dev minor");
Mike Iselyd8554972006-06-26 20:58:46 -030088
Adrian Bunk07e337e2006-06-30 11:30:20 -030089static struct v4l2_capability pvr_capability ={
Mike Iselyd8554972006-06-26 20:58:46 -030090 .driver = "pvrusb2",
91 .card = "Hauppauge WinTV pvr-usb2",
92 .bus_info = "usb",
Mike Isely48c5b0d2009-05-02 00:04:35 -030093 .version = KERNEL_VERSION(0, 9, 0),
Mike Iselyd166b022009-01-14 04:21:29 -030094 .capabilities = (V4L2_CAP_VIDEO_CAPTURE |
Pantelis Koukousoulasae2b9e22006-12-27 23:09:55 -030095 V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
Mike Iselyd8554972006-06-26 20:58:46 -030096 V4L2_CAP_READWRITE),
97 .reserved = {0,0,0,0}
98};
99
Adrian Bunk07e337e2006-06-30 11:30:20 -0300100static struct v4l2_fmtdesc pvr_fmtdesc [] = {
Mike Iselyd8554972006-06-26 20:58:46 -0300101 {
102 .index = 0,
103 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
104 .flags = V4L2_FMT_FLAG_COMPRESSED,
105 .description = "MPEG1/2",
106 // This should really be V4L2_PIX_FMT_MPEG, but xawtv
107 // breaks when I do that.
108 .pixelformat = 0, // V4L2_PIX_FMT_MPEG,
109 .reserved = { 0, 0, 0, 0 }
110 }
111};
112
113#define PVR_FORMAT_PIX 0
114#define PVR_FORMAT_VBI 1
115
Adrian Bunk07e337e2006-06-30 11:30:20 -0300116static struct v4l2_format pvr_format [] = {
Mike Iselyd8554972006-06-26 20:58:46 -0300117 [PVR_FORMAT_PIX] = {
118 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
119 .fmt = {
120 .pix = {
121 .width = 720,
122 .height = 576,
123 // This should really be V4L2_PIX_FMT_MPEG,
124 // but xawtv breaks when I do that.
125 .pixelformat = 0, // V4L2_PIX_FMT_MPEG,
126 .field = V4L2_FIELD_INTERLACED,
127 .bytesperline = 0, // doesn't make sense
128 // here
129 //FIXME : Don't know what to put here...
130 .sizeimage = (32*1024),
131 .colorspace = 0, // doesn't make sense here
132 .priv = 0
133 }
134 }
135 },
136 [PVR_FORMAT_VBI] = {
137 .type = V4L2_BUF_TYPE_VBI_CAPTURE,
138 .fmt = {
139 .vbi = {
140 .sampling_rate = 27000000,
141 .offset = 248,
142 .samples_per_line = 1443,
143 .sample_format = V4L2_PIX_FMT_GREY,
144 .start = { 0, 0 },
145 .count = { 0, 0 },
146 .flags = 0,
147 .reserved = { 0, 0 }
148 }
149 }
150 }
151};
152
Mike Isely16eb40d2006-12-30 18:27:32 -0300153
Mike Iselyd8554972006-06-26 20:58:46 -0300154/*
155 * pvr_ioctl()
156 *
157 * This is part of Video 4 Linux API. The procedure handles ioctl() calls.
158 *
159 */
Hans Verkuil069b7472008-12-30 07:04:34 -0300160static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
Mike Iselyd8554972006-06-26 20:58:46 -0300161{
162 struct pvr2_v4l2_fh *fh = file->private_data;
163 struct pvr2_v4l2 *vp = fh->vhead;
164 struct pvr2_v4l2_dev *dev_info = fh->dev_info;
165 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
Hans Verkuil069b7472008-12-30 07:04:34 -0300166 long ret = -EINVAL;
Mike Iselyd8554972006-06-26 20:58:46 -0300167
168 if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
169 v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),cmd);
170 }
171
172 if (!pvr2_hdw_dev_ok(hdw)) {
173 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
174 "ioctl failed - bad or no context");
175 return -EFAULT;
176 }
177
178 /* check priority */
179 switch (cmd) {
180 case VIDIOC_S_CTRL:
181 case VIDIOC_S_STD:
182 case VIDIOC_S_INPUT:
183 case VIDIOC_S_TUNER:
184 case VIDIOC_S_FREQUENCY:
185 ret = v4l2_prio_check(&vp->prio, &fh->prio);
186 if (ret)
187 return ret;
188 }
189
190 switch (cmd) {
191 case VIDIOC_QUERYCAP:
192 {
193 struct v4l2_capability *cap = arg;
194
195 memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
Mike Isely31a18542007-04-08 01:11:47 -0300196 strlcpy(cap->bus_info,pvr2_hdw_get_bus_info(hdw),
197 sizeof(cap->bus_info));
Mike Isely78a47102007-11-26 01:58:20 -0300198 strlcpy(cap->card,pvr2_hdw_get_desc(hdw),sizeof(cap->card));
Mike Iselyd8554972006-06-26 20:58:46 -0300199
200 ret = 0;
201 break;
202 }
203
204 case VIDIOC_G_PRIORITY:
205 {
206 enum v4l2_priority *p = arg;
207
208 *p = v4l2_prio_max(&vp->prio);
209 ret = 0;
210 break;
211 }
212
213 case VIDIOC_S_PRIORITY:
214 {
215 enum v4l2_priority *prio = arg;
216
217 ret = v4l2_prio_change(&vp->prio, &fh->prio, *prio);
218 break;
219 }
220
221 case VIDIOC_ENUMSTD:
222 {
223 struct v4l2_standard *vs = (struct v4l2_standard *)arg;
224 int idx = vs->index;
225 ret = pvr2_hdw_get_stdenum_value(hdw,vs,idx+1);
226 break;
227 }
228
229 case VIDIOC_G_STD:
230 {
231 int val = 0;
232 ret = pvr2_ctrl_get_value(
233 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR),&val);
234 *(v4l2_std_id *)arg = val;
235 break;
236 }
237
238 case VIDIOC_S_STD:
239 {
240 ret = pvr2_ctrl_set_value(
241 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR),
242 *(v4l2_std_id *)arg);
243 break;
244 }
245
246 case VIDIOC_ENUMINPUT:
247 {
248 struct pvr2_ctrl *cptr;
249 struct v4l2_input *vi = (struct v4l2_input *)arg;
250 struct v4l2_input tmp;
251 unsigned int cnt;
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300252 int val;
Mike Iselyd8554972006-06-26 20:58:46 -0300253
254 cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
255
256 memset(&tmp,0,sizeof(tmp));
257 tmp.index = vi->index;
258 ret = 0;
Roel Kluin223ffe52009-05-02 16:38:47 -0300259 if (vi->index >= fh->input_cnt) {
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300260 ret = -EINVAL;
261 break;
262 }
Mike Iselye57b1c82008-04-21 03:52:34 -0300263 val = fh->input_map[vi->index];
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300264 switch (val) {
Mike Iselyd8554972006-06-26 20:58:46 -0300265 case PVR2_CVAL_INPUT_TV:
Mike Isely895c3e82008-04-22 14:45:37 -0300266 case PVR2_CVAL_INPUT_DTV:
Mike Iselyd8554972006-06-26 20:58:46 -0300267 case PVR2_CVAL_INPUT_RADIO:
268 tmp.type = V4L2_INPUT_TYPE_TUNER;
269 break;
270 case PVR2_CVAL_INPUT_SVIDEO:
271 case PVR2_CVAL_INPUT_COMPOSITE:
272 tmp.type = V4L2_INPUT_TYPE_CAMERA;
273 break;
274 default:
275 ret = -EINVAL;
276 break;
277 }
278 if (ret < 0) break;
279
280 cnt = 0;
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300281 pvr2_ctrl_get_valname(cptr,val,
Mike Iselyd8554972006-06-26 20:58:46 -0300282 tmp.name,sizeof(tmp.name)-1,&cnt);
283 tmp.name[cnt] = 0;
284
285 /* Don't bother with audioset, since this driver currently
286 always switches the audio whenever the video is
287 switched. */
288
289 /* Handling std is a tougher problem. It doesn't make
290 sense in cases where a device might be multi-standard.
291 We could just copy out the current value for the
292 standard, but it can change over time. For now just
293 leave it zero. */
294
295 memcpy(vi, &tmp, sizeof(tmp));
296
297 ret = 0;
298 break;
299 }
300
301 case VIDIOC_G_INPUT:
302 {
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300303 unsigned int idx;
Mike Iselyd8554972006-06-26 20:58:46 -0300304 struct pvr2_ctrl *cptr;
305 struct v4l2_input *vi = (struct v4l2_input *)arg;
306 int val;
307 cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
308 val = 0;
309 ret = pvr2_ctrl_get_value(cptr,&val);
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300310 vi->index = 0;
Mike Iselye57b1c82008-04-21 03:52:34 -0300311 for (idx = 0; idx < fh->input_cnt; idx++) {
312 if (fh->input_map[idx] == val) {
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300313 vi->index = idx;
314 break;
315 }
316 }
Mike Iselyd8554972006-06-26 20:58:46 -0300317 break;
318 }
319
320 case VIDIOC_S_INPUT:
321 {
322 struct v4l2_input *vi = (struct v4l2_input *)arg;
Roel Kluin223ffe52009-05-02 16:38:47 -0300323 if (vi->index >= fh->input_cnt) {
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300324 ret = -ERANGE;
325 break;
326 }
Mike Iselyd8554972006-06-26 20:58:46 -0300327 ret = pvr2_ctrl_set_value(
328 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
Mike Iselye57b1c82008-04-21 03:52:34 -0300329 fh->input_map[vi->index]);
Mike Iselyd8554972006-06-26 20:58:46 -0300330 break;
331 }
332
333 case VIDIOC_ENUMAUDIO:
334 {
Pantelis Koukousoulas848ed3c2007-01-20 01:57:36 -0300335 /* pkt: FIXME: We are returning one "fake" input here
336 which could very well be called "whatever_we_like".
337 This is for apps that want to see an audio input
338 just to feel comfortable, as well as to test if
339 it can do stereo or sth. There is actually no guarantee
340 that the actual audio input cannot change behind the app's
341 back, but most applications should not mind that either.
342
343 Hopefully, mplayer people will work with us on this (this
344 whole mess is to support mplayer pvr://), or Hans will come
345 up with a more standard way to say "we have inputs but we
346 don 't want you to change them independent of video" which
347 will sort this mess.
348 */
349 struct v4l2_audio *vin = arg;
Mike Iselyd8554972006-06-26 20:58:46 -0300350 ret = -EINVAL;
Pantelis Koukousoulas848ed3c2007-01-20 01:57:36 -0300351 if (vin->index > 0) break;
352 strncpy(vin->name, "PVRUSB2 Audio",14);
353 vin->capability = V4L2_AUDCAP_STEREO;
354 ret = 0;
355 break;
Mike Iselyd8554972006-06-26 20:58:46 -0300356 break;
357 }
358
359 case VIDIOC_G_AUDIO:
360 {
Pantelis Koukousoulas848ed3c2007-01-20 01:57:36 -0300361 /* pkt: FIXME: see above comment (VIDIOC_ENUMAUDIO) */
362 struct v4l2_audio *vin = arg;
363 memset(vin,0,sizeof(*vin));
364 vin->index = 0;
365 strncpy(vin->name, "PVRUSB2 Audio",14);
366 vin->capability = V4L2_AUDCAP_STEREO;
367 ret = 0;
Mike Iselyd8554972006-06-26 20:58:46 -0300368 break;
369 }
370
371 case VIDIOC_S_AUDIO:
372 {
373 ret = -EINVAL;
374 break;
375 }
376 case VIDIOC_G_TUNER:
377 {
378 struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
Mauro Carvalho Chehab5cc1dd82007-01-21 22:02:58 -0300379
Michael Krufky8d364362007-01-22 02:17:55 -0300380 if (vt->index != 0) break; /* Only answer for the 1st tuner */
Mauro Carvalho Chehab5cc1dd82007-01-21 22:02:58 -0300381
Mike Isely18103c572007-01-20 00:09:47 -0300382 pvr2_hdw_execute_tuner_poll(hdw);
383 ret = pvr2_hdw_get_tuner_status(hdw,vt);
Mike Iselyd8554972006-06-26 20:58:46 -0300384 break;
385 }
386
387 case VIDIOC_S_TUNER:
388 {
389 struct v4l2_tuner *vt=(struct v4l2_tuner *)arg;
390
391 if (vt->index != 0)
392 break;
393
394 ret = pvr2_ctrl_set_value(
395 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE),
396 vt->audmode);
Mike Isely11fc76c2007-01-20 00:24:52 -0300397 break;
Mike Iselyd8554972006-06-26 20:58:46 -0300398 }
399
400 case VIDIOC_S_FREQUENCY:
401 {
402 const struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
Mike Iselyc0e69312006-12-27 23:25:06 -0300403 unsigned long fv;
Mike Isely18103c572007-01-20 00:09:47 -0300404 struct v4l2_tuner vt;
405 int cur_input;
406 struct pvr2_ctrl *ctrlp;
407 ret = pvr2_hdw_get_tuner_status(hdw,&vt);
408 if (ret != 0) break;
409 ctrlp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
410 ret = pvr2_ctrl_get_value(ctrlp,&cur_input);
411 if (ret != 0) break;
Mike Iselyc0e69312006-12-27 23:25:06 -0300412 if (vf->type == V4L2_TUNER_RADIO) {
Mike Isely18103c572007-01-20 00:09:47 -0300413 if (cur_input != PVR2_CVAL_INPUT_RADIO) {
414 pvr2_ctrl_set_value(ctrlp,
415 PVR2_CVAL_INPUT_RADIO);
416 }
417 } else {
418 if (cur_input == PVR2_CVAL_INPUT_RADIO) {
419 pvr2_ctrl_set_value(ctrlp,
420 PVR2_CVAL_INPUT_TV);
421 }
422 }
423 fv = vf->frequency;
424 if (vt.capability & V4L2_TUNER_CAP_LOW) {
Mike Iselyc0e69312006-12-27 23:25:06 -0300425 fv = (fv * 125) / 2;
426 } else {
427 fv = fv * 62500;
428 }
Mike Iselyd8554972006-06-26 20:58:46 -0300429 ret = pvr2_ctrl_set_value(
Mike Iselyc0e69312006-12-27 23:25:06 -0300430 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),fv);
Mike Iselyd8554972006-06-26 20:58:46 -0300431 break;
432 }
433
434 case VIDIOC_G_FREQUENCY:
435 {
436 struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
437 int val = 0;
Mike Isely18103c572007-01-20 00:09:47 -0300438 int cur_input;
439 struct v4l2_tuner vt;
440 ret = pvr2_hdw_get_tuner_status(hdw,&vt);
441 if (ret != 0) break;
Mike Iselyd8554972006-06-26 20:58:46 -0300442 ret = pvr2_ctrl_get_value(
443 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),
444 &val);
Mike Iselyc0e69312006-12-27 23:25:06 -0300445 if (ret != 0) break;
446 pvr2_ctrl_get_value(
447 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
448 &cur_input);
449 if (cur_input == PVR2_CVAL_INPUT_RADIO) {
Mike Iselyc0e69312006-12-27 23:25:06 -0300450 vf->type = V4L2_TUNER_RADIO;
451 } else {
Mike Iselyc0e69312006-12-27 23:25:06 -0300452 vf->type = V4L2_TUNER_ANALOG_TV;
453 }
Mike Isely18103c572007-01-20 00:09:47 -0300454 if (vt.capability & V4L2_TUNER_CAP_LOW) {
455 val = (val * 2) / 125;
456 } else {
457 val /= 62500;
458 }
459 vf->frequency = val;
Mike Iselyd8554972006-06-26 20:58:46 -0300460 break;
461 }
462
463 case VIDIOC_ENUM_FMT:
464 {
465 struct v4l2_fmtdesc *fd = (struct v4l2_fmtdesc *)arg;
466
467 /* Only one format is supported : mpeg.*/
468 if (fd->index != 0)
469 break;
470
471 memcpy(fd, pvr_fmtdesc, sizeof(struct v4l2_fmtdesc));
472 ret = 0;
473 break;
474 }
475
476 case VIDIOC_G_FMT:
477 {
478 struct v4l2_format *vf = (struct v4l2_format *)arg;
479 int val;
480 switch(vf->type) {
481 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
482 memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
483 sizeof(struct v4l2_format));
484 val = 0;
485 pvr2_ctrl_get_value(
486 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES),
487 &val);
488 vf->fmt.pix.width = val;
489 val = 0;
490 pvr2_ctrl_get_value(
Mike Iselyd8554972006-06-26 20:58:46 -0300491 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES),
492 &val);
493 vf->fmt.pix.height = val;
494 ret = 0;
495 break;
496 case V4L2_BUF_TYPE_VBI_CAPTURE:
497 // ????? Still need to figure out to do VBI correctly
498 ret = -EINVAL;
499 break;
500 default:
501 ret = -EINVAL;
502 break;
503 }
504 break;
505 }
506
507 case VIDIOC_TRY_FMT:
508 case VIDIOC_S_FMT:
509 {
510 struct v4l2_format *vf = (struct v4l2_format *)arg;
511
512 ret = 0;
513 switch(vf->type) {
514 case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
Pantelis Koukousoulasfd694962007-01-20 01:59:54 -0300515 int lmin,lmax,ldef;
Mike Iselye95a1912006-08-08 09:10:07 -0300516 struct pvr2_ctrl *hcp,*vcp;
Mike Iselyd8554972006-06-26 20:58:46 -0300517 int h = vf->fmt.pix.height;
518 int w = vf->fmt.pix.width;
Mike Iselye95a1912006-08-08 09:10:07 -0300519 hcp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES);
520 vcp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES);
Mike Iselyd8554972006-06-26 20:58:46 -0300521
Mike Iselye95a1912006-08-08 09:10:07 -0300522 lmin = pvr2_ctrl_get_min(hcp);
523 lmax = pvr2_ctrl_get_max(hcp);
Mike Isely26dd1c572008-08-31 20:55:03 -0300524 pvr2_ctrl_get_def(hcp, &ldef);
Pantelis Koukousoulasfd694962007-01-20 01:59:54 -0300525 if (w == -1) {
526 w = ldef;
527 } else if (w < lmin) {
Mike Iselye95a1912006-08-08 09:10:07 -0300528 w = lmin;
529 } else if (w > lmax) {
530 w = lmax;
Mike Isely039c4302006-06-25 20:04:16 -0300531 }
Hans Verkuilb31e3412006-09-01 18:36:10 -0300532 lmin = pvr2_ctrl_get_min(vcp);
533 lmax = pvr2_ctrl_get_max(vcp);
Mike Isely26dd1c572008-08-31 20:55:03 -0300534 pvr2_ctrl_get_def(vcp, &ldef);
Pantelis Koukousoulasfd694962007-01-20 01:59:54 -0300535 if (h == -1) {
536 h = ldef;
537 } else if (h < lmin) {
Hans Verkuilb31e3412006-09-01 18:36:10 -0300538 h = lmin;
539 } else if (h > lmax) {
540 h = lmax;
541 }
Mike Iselyd8554972006-06-26 20:58:46 -0300542
543 memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
544 sizeof(struct v4l2_format));
Mike Isely039c4302006-06-25 20:04:16 -0300545 vf->fmt.pix.width = w;
546 vf->fmt.pix.height = h;
Mike Iselyd8554972006-06-26 20:58:46 -0300547
548 if (cmd == VIDIOC_S_FMT) {
Mike Iselye95a1912006-08-08 09:10:07 -0300549 pvr2_ctrl_set_value(hcp,vf->fmt.pix.width);
550 pvr2_ctrl_set_value(vcp,vf->fmt.pix.height);
Mike Iselyd8554972006-06-26 20:58:46 -0300551 }
552 } break;
553 case V4L2_BUF_TYPE_VBI_CAPTURE:
554 // ????? Still need to figure out to do VBI correctly
555 ret = -EINVAL;
556 break;
557 default:
558 ret = -EINVAL;
559 break;
560 }
561 break;
562 }
563
564 case VIDIOC_STREAMON:
565 {
Mike Isely16eb40d2006-12-30 18:27:32 -0300566 if (!fh->dev_info->stream) {
567 /* No stream defined for this node. This means
568 that we're not currently allowed to stream from
569 this node. */
570 ret = -EPERM;
571 break;
572 }
Mike Iselyd8554972006-06-26 20:58:46 -0300573 ret = pvr2_hdw_set_stream_type(hdw,dev_info->config);
574 if (ret < 0) return ret;
575 ret = pvr2_hdw_set_streaming(hdw,!0);
576 break;
577 }
578
579 case VIDIOC_STREAMOFF:
580 {
Mike Isely16eb40d2006-12-30 18:27:32 -0300581 if (!fh->dev_info->stream) {
582 /* No stream defined for this node. This means
583 that we're not currently allowed to stream from
584 this node. */
585 ret = -EPERM;
586 break;
587 }
Mike Iselyd8554972006-06-26 20:58:46 -0300588 ret = pvr2_hdw_set_streaming(hdw,0);
589 break;
590 }
591
592 case VIDIOC_QUERYCTRL:
593 {
594 struct pvr2_ctrl *cptr;
Mike Isely26dd1c572008-08-31 20:55:03 -0300595 int val;
Mike Iselyd8554972006-06-26 20:58:46 -0300596 struct v4l2_queryctrl *vc = (struct v4l2_queryctrl *)arg;
597 ret = 0;
Mike Isely1d9f8462006-06-25 20:04:58 -0300598 if (vc->id & V4L2_CTRL_FLAG_NEXT_CTRL) {
599 cptr = pvr2_hdw_get_ctrl_nextv4l(
600 hdw,(vc->id & ~V4L2_CTRL_FLAG_NEXT_CTRL));
601 if (cptr) vc->id = pvr2_ctrl_get_v4lid(cptr);
602 } else {
603 cptr = pvr2_hdw_get_ctrl_v4l(hdw,vc->id);
604 }
Mike Iselyd8554972006-06-26 20:58:46 -0300605 if (!cptr) {
Mike Isely0885ba12006-06-25 21:30:47 -0300606 pvr2_trace(PVR2_TRACE_V4LIOCTL,
Mike Iselya761f432006-06-25 20:04:44 -0300607 "QUERYCTRL id=0x%x not implemented here",
608 vc->id);
Mike Iselyd8554972006-06-26 20:58:46 -0300609 ret = -EINVAL;
610 break;
611 }
612
Mike Iselya761f432006-06-25 20:04:44 -0300613 pvr2_trace(PVR2_TRACE_V4LIOCTL,
614 "QUERYCTRL id=0x%x mapping name=%s (%s)",
615 vc->id,pvr2_ctrl_get_name(cptr),
616 pvr2_ctrl_get_desc(cptr));
617 strlcpy(vc->name,pvr2_ctrl_get_desc(cptr),sizeof(vc->name));
618 vc->flags = pvr2_ctrl_get_v4lflags(cptr);
Mike Isely26dd1c572008-08-31 20:55:03 -0300619 pvr2_ctrl_get_def(cptr, &val);
620 vc->default_value = val;
Mike Iselyd8554972006-06-26 20:58:46 -0300621 switch (pvr2_ctrl_get_type(cptr)) {
622 case pvr2_ctl_enum:
623 vc->type = V4L2_CTRL_TYPE_MENU;
624 vc->minimum = 0;
625 vc->maximum = pvr2_ctrl_get_cnt(cptr) - 1;
626 vc->step = 1;
627 break;
Mike Isely33213962006-06-25 20:04:40 -0300628 case pvr2_ctl_bool:
Mike Isely1d9f8462006-06-25 20:04:58 -0300629 vc->type = V4L2_CTRL_TYPE_BOOLEAN;
Mike Isely33213962006-06-25 20:04:40 -0300630 vc->minimum = 0;
631 vc->maximum = 1;
632 vc->step = 1;
633 break;
Mike Iselyd8554972006-06-26 20:58:46 -0300634 case pvr2_ctl_int:
635 vc->type = V4L2_CTRL_TYPE_INTEGER;
636 vc->minimum = pvr2_ctrl_get_min(cptr);
637 vc->maximum = pvr2_ctrl_get_max(cptr);
638 vc->step = 1;
639 break;
640 default:
Mike Isely0885ba12006-06-25 21:30:47 -0300641 pvr2_trace(PVR2_TRACE_V4LIOCTL,
Mike Iselya761f432006-06-25 20:04:44 -0300642 "QUERYCTRL id=0x%x name=%s not mappable",
643 vc->id,pvr2_ctrl_get_name(cptr));
Mike Iselyd8554972006-06-26 20:58:46 -0300644 ret = -EINVAL;
645 break;
646 }
647 break;
648 }
649
650 case VIDIOC_QUERYMENU:
651 {
652 struct v4l2_querymenu *vm = (struct v4l2_querymenu *)arg;
653 unsigned int cnt = 0;
654 ret = pvr2_ctrl_get_valname(pvr2_hdw_get_ctrl_v4l(hdw,vm->id),
655 vm->index,
656 vm->name,sizeof(vm->name)-1,
657 &cnt);
658 vm->name[cnt] = 0;
659 break;
660 }
661
662 case VIDIOC_G_CTRL:
663 {
664 struct v4l2_control *vc = (struct v4l2_control *)arg;
665 int val = 0;
666 ret = pvr2_ctrl_get_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id),
667 &val);
668 vc->value = val;
669 break;
670 }
671
672 case VIDIOC_S_CTRL:
673 {
674 struct v4l2_control *vc = (struct v4l2_control *)arg;
675 ret = pvr2_ctrl_set_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id),
676 vc->value);
677 break;
678 }
679
Mike Isely1d9f8462006-06-25 20:04:58 -0300680 case VIDIOC_G_EXT_CTRLS:
681 {
682 struct v4l2_ext_controls *ctls =
683 (struct v4l2_ext_controls *)arg;
684 struct v4l2_ext_control *ctrl;
685 unsigned int idx;
686 int val;
Mike Iselyc1c26802007-01-20 00:30:23 -0300687 ret = 0;
Mike Isely1d9f8462006-06-25 20:04:58 -0300688 for (idx = 0; idx < ctls->count; idx++) {
689 ctrl = ctls->controls + idx;
690 ret = pvr2_ctrl_get_value(
691 pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),&val);
692 if (ret) {
693 ctls->error_idx = idx;
694 break;
695 }
696 /* Ensure that if read as a 64 bit value, the user
697 will still get a hopefully sane value */
698 ctrl->value64 = 0;
699 ctrl->value = val;
700 }
701 break;
702 }
703
704 case VIDIOC_S_EXT_CTRLS:
705 {
706 struct v4l2_ext_controls *ctls =
707 (struct v4l2_ext_controls *)arg;
708 struct v4l2_ext_control *ctrl;
709 unsigned int idx;
Mike Iselyc1c26802007-01-20 00:30:23 -0300710 ret = 0;
Mike Isely1d9f8462006-06-25 20:04:58 -0300711 for (idx = 0; idx < ctls->count; idx++) {
712 ctrl = ctls->controls + idx;
713 ret = pvr2_ctrl_set_value(
714 pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),
715 ctrl->value);
716 if (ret) {
717 ctls->error_idx = idx;
718 break;
719 }
720 }
721 break;
722 }
723
724 case VIDIOC_TRY_EXT_CTRLS:
725 {
726 struct v4l2_ext_controls *ctls =
727 (struct v4l2_ext_controls *)arg;
728 struct v4l2_ext_control *ctrl;
729 struct pvr2_ctrl *pctl;
730 unsigned int idx;
731 /* For the moment just validate that the requested control
732 actually exists. */
Mike Iselyc1c26802007-01-20 00:30:23 -0300733 ret = 0;
Mike Isely1d9f8462006-06-25 20:04:58 -0300734 for (idx = 0; idx < ctls->count; idx++) {
735 ctrl = ctls->controls + idx;
736 pctl = pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id);
737 if (!pctl) {
738 ret = -EINVAL;
739 ctls->error_idx = idx;
740 break;
741 }
742 }
743 break;
744 }
745
Mike Isely432907f2008-08-31 21:02:20 -0300746 case VIDIOC_CROPCAP:
747 {
748 struct v4l2_cropcap *cap = (struct v4l2_cropcap *)arg;
749 if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
750 ret = -EINVAL;
751 break;
752 }
753 ret = pvr2_hdw_get_cropcap(hdw, cap);
754 cap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* paranoia */
755 break;
756 }
757 case VIDIOC_G_CROP:
758 {
759 struct v4l2_crop *crop = (struct v4l2_crop *)arg;
760 int val = 0;
761 if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
762 ret = -EINVAL;
763 break;
764 }
765 ret = pvr2_ctrl_get_value(
766 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL), &val);
767 if (ret != 0) {
768 ret = -EINVAL;
769 break;
770 }
771 crop->c.left = val;
772 ret = pvr2_ctrl_get_value(
773 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT), &val);
774 if (ret != 0) {
775 ret = -EINVAL;
776 break;
777 }
778 crop->c.top = val;
779 ret = pvr2_ctrl_get_value(
780 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW), &val);
781 if (ret != 0) {
782 ret = -EINVAL;
783 break;
784 }
785 crop->c.width = val;
786 ret = pvr2_ctrl_get_value(
787 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH), &val);
788 if (ret != 0) {
789 ret = -EINVAL;
790 break;
791 }
792 crop->c.height = val;
793 }
794 case VIDIOC_S_CROP:
795 {
796 struct v4l2_crop *crop = (struct v4l2_crop *)arg;
797 struct v4l2_cropcap cap;
798 if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
799 ret = -EINVAL;
800 break;
801 }
802 cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
803 ret = pvr2_ctrl_set_value(
804 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL),
805 crop->c.left);
806 if (ret != 0) {
807 ret = -EINVAL;
808 break;
809 }
810 ret = pvr2_ctrl_set_value(
811 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT),
812 crop->c.top);
813 if (ret != 0) {
814 ret = -EINVAL;
815 break;
816 }
817 ret = pvr2_ctrl_set_value(
818 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW),
819 crop->c.width);
820 if (ret != 0) {
821 ret = -EINVAL;
822 break;
823 }
824 ret = pvr2_ctrl_set_value(
825 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH),
826 crop->c.height);
827 if (ret != 0) {
828 ret = -EINVAL;
829 break;
830 }
831 }
Mike Iselyd8554972006-06-26 20:58:46 -0300832 case VIDIOC_LOG_STATUS:
833 {
Mike Iselyd8554972006-06-26 20:58:46 -0300834 pvr2_hdw_trigger_module_log(hdw);
Mike Iselyd8554972006-06-26 20:58:46 -0300835 ret = 0;
836 break;
837 }
Mike Isely32ffa9a2006-09-23 22:26:52 -0300838#ifdef CONFIG_VIDEO_ADV_DEBUG
Trent Piepho52ebc762007-01-23 22:38:13 -0300839 case VIDIOC_DBG_S_REGISTER:
Trent Piepho52ebc762007-01-23 22:38:13 -0300840 case VIDIOC_DBG_G_REGISTER:
Mike Isely32ffa9a2006-09-23 22:26:52 -0300841 {
Hans Verkuilf3d092b2007-02-23 20:55:14 -0300842 u64 val;
Hans Verkuilaecde8b52008-12-30 07:14:19 -0300843 struct v4l2_dbg_register *req = (struct v4l2_dbg_register *)arg;
Trent Piepho52ebc762007-01-23 22:38:13 -0300844 if (cmd == VIDIOC_DBG_S_REGISTER) val = req->val;
Mike Isely32ffa9a2006-09-23 22:26:52 -0300845 ret = pvr2_hdw_register_access(
Hans Verkuilaecde8b52008-12-30 07:14:19 -0300846 hdw, &req->match, req->reg,
847 cmd == VIDIOC_DBG_S_REGISTER, &val);
Trent Piepho52ebc762007-01-23 22:38:13 -0300848 if (cmd == VIDIOC_DBG_G_REGISTER) req->val = val;
Mike Isely32ffa9a2006-09-23 22:26:52 -0300849 break;
850 }
851#endif
Mike Iselyd8554972006-06-26 20:58:46 -0300852
853 default :
Mauro Carvalho Chehabb1f88402008-10-21 11:27:20 -0300854 ret = v4l_compat_translate_ioctl(file, cmd,
Hans Verkuilf473bf72008-11-01 08:25:11 -0300855 arg, pvr2_v4l2_do_ioctl);
Mike Iselyd8554972006-06-26 20:58:46 -0300856 }
857
858 pvr2_hdw_commit_ctl(hdw);
859
860 if (ret < 0) {
861 if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
Mike Isely0885ba12006-06-25 21:30:47 -0300862 pvr2_trace(PVR2_TRACE_V4LIOCTL,
Hans Verkuil069b7472008-12-30 07:04:34 -0300863 "pvr2_v4l2_do_ioctl failure, ret=%ld", ret);
Mike Iselyd8554972006-06-26 20:58:46 -0300864 } else {
Mike Isely0885ba12006-06-25 21:30:47 -0300865 if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
866 pvr2_trace(PVR2_TRACE_V4LIOCTL,
Hans Verkuil069b7472008-12-30 07:04:34 -0300867 "pvr2_v4l2_do_ioctl failure, ret=%ld"
868 " command was:", ret);
Mike Iselyd8554972006-06-26 20:58:46 -0300869 v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),
870 cmd);
871 }
872 }
873 } else {
874 pvr2_trace(PVR2_TRACE_V4LIOCTL,
Hans Verkuil069b7472008-12-30 07:04:34 -0300875 "pvr2_v4l2_do_ioctl complete, ret=%ld (0x%lx)",
876 ret, ret);
Mike Iselyd8554972006-06-26 20:58:46 -0300877 }
878 return ret;
879}
880
Mike Iselyd8554972006-06-26 20:58:46 -0300881static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
882{
Mike Isely0f0f2572006-12-27 23:19:42 -0300883 struct pvr2_hdw *hdw = dip->v4lp->channel.mc_head->hdw;
Mike Isely16eb40d2006-12-30 18:27:32 -0300884 enum pvr2_config cfg = dip->config;
Mike Isely0f0f2572006-12-27 23:19:42 -0300885
Mike Isely16eb40d2006-12-30 18:27:32 -0300886 pvr2_hdw_v4l_store_minor_number(hdw,dip->minor_type,-1);
Mike Isely75910052006-09-23 22:30:50 -0300887
888 /* Paranoia */
Randy Dunlapc2625bf2006-10-29 11:12:27 -0300889 dip->v4lp = NULL;
890 dip->stream = NULL;
Mike Isely75910052006-09-23 22:30:50 -0300891
892 /* Actual deallocation happens later when all internal references
893 are gone. */
894 video_unregister_device(&dip->devbase);
Mike Isely0f0f2572006-12-27 23:19:42 -0300895
Laurent Pinchart38c7c032009-11-27 13:57:15 -0300896 printk(KERN_INFO "pvrusb2: unregistered device %s [%s]\n",
897 video_device_node_name(&dip->devbase),
Mike Isely16eb40d2006-12-30 18:27:32 -0300898 pvr2_config_get_name(cfg));
Mike Isely0f0f2572006-12-27 23:19:42 -0300899
Mike Iselyd8554972006-06-26 20:58:46 -0300900}
901
902
Mike Isely4a89baa2009-10-12 00:13:28 -0300903static void pvr2_v4l2_dev_disassociate_parent(struct pvr2_v4l2_dev *dip)
904{
905 if (!dip) return;
906 if (!dip->devbase.parent) return;
907 dip->devbase.parent = NULL;
908 device_move(&dip->devbase.dev, NULL, DPM_ORDER_NONE);
909}
910
911
Mike Iselyd8554972006-06-26 20:58:46 -0300912static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp)
913{
Mike Isely0f0f2572006-12-27 23:19:42 -0300914 if (vp->dev_video) {
915 pvr2_v4l2_dev_destroy(vp->dev_video);
Al Viro89952d12007-03-14 09:17:59 +0000916 vp->dev_video = NULL;
Mike Isely0f0f2572006-12-27 23:19:42 -0300917 }
918 if (vp->dev_radio) {
919 pvr2_v4l2_dev_destroy(vp->dev_radio);
Al Viro89952d12007-03-14 09:17:59 +0000920 vp->dev_radio = NULL;
Mike Isely0f0f2572006-12-27 23:19:42 -0300921 }
Mike Iselyd8554972006-06-26 20:58:46 -0300922
923 pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp);
924 pvr2_channel_done(&vp->channel);
925 kfree(vp);
926}
927
928
Mike Isely75910052006-09-23 22:30:50 -0300929static void pvr2_video_device_release(struct video_device *vdev)
930{
931 struct pvr2_v4l2_dev *dev;
932 dev = container_of(vdev,struct pvr2_v4l2_dev,devbase);
933 kfree(dev);
934}
935
936
Adrian Bunk07e337e2006-06-30 11:30:20 -0300937static void pvr2_v4l2_internal_check(struct pvr2_channel *chp)
Mike Iselyd8554972006-06-26 20:58:46 -0300938{
939 struct pvr2_v4l2 *vp;
940 vp = container_of(chp,struct pvr2_v4l2,channel);
941 if (!vp->channel.mc_head->disconnect_flag) return;
Mike Isely4a89baa2009-10-12 00:13:28 -0300942 pvr2_v4l2_dev_disassociate_parent(vp->dev_video);
943 pvr2_v4l2_dev_disassociate_parent(vp->dev_radio);
Mike Iselyd8554972006-06-26 20:58:46 -0300944 if (vp->vfirst) return;
945 pvr2_v4l2_destroy_no_lock(vp);
946}
947
948
Hans Verkuil069b7472008-12-30 07:04:34 -0300949static long pvr2_v4l2_ioctl(struct file *file,
Adrian Bunk07e337e2006-06-30 11:30:20 -0300950 unsigned int cmd, unsigned long arg)
Mike Iselyd8554972006-06-26 20:58:46 -0300951{
952
Hans Verkuilf473bf72008-11-01 08:25:11 -0300953 return video_usercopy(file, cmd, arg, pvr2_v4l2_do_ioctl);
Mike Iselyd8554972006-06-26 20:58:46 -0300954}
955
956
Hans Verkuilbec43662008-12-30 06:58:20 -0300957static int pvr2_v4l2_release(struct file *file)
Mike Iselyd8554972006-06-26 20:58:46 -0300958{
959 struct pvr2_v4l2_fh *fhp = file->private_data;
960 struct pvr2_v4l2 *vp = fhp->vhead;
Mike Iselyc74e0062006-12-30 18:31:22 -0300961 struct pvr2_hdw *hdw = fhp->channel.mc_head->hdw;
Mike Iselyd8554972006-06-26 20:58:46 -0300962
963 pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_release");
964
965 if (fhp->rhp) {
966 struct pvr2_stream *sp;
Mike Iselyd8554972006-06-26 20:58:46 -0300967 pvr2_hdw_set_streaming(hdw,0);
968 sp = pvr2_ioread_get_stream(fhp->rhp);
Mike Iselya0fd1cb2006-06-30 11:35:28 -0300969 if (sp) pvr2_stream_set_callback(sp,NULL,NULL);
Mike Iselyd8554972006-06-26 20:58:46 -0300970 pvr2_ioread_destroy(fhp->rhp);
Mike Iselya0fd1cb2006-06-30 11:35:28 -0300971 fhp->rhp = NULL;
Mike Iselyd8554972006-06-26 20:58:46 -0300972 }
Pantelis Koukousoulasae2b9e22006-12-27 23:09:55 -0300973
Mike Iselyd8554972006-06-26 20:58:46 -0300974 v4l2_prio_close(&vp->prio, &fhp->prio);
975 file->private_data = NULL;
976
Mike Isely794b1602008-04-22 14:45:45 -0300977 if (fhp->vnext) {
978 fhp->vnext->vprev = fhp->vprev;
979 } else {
980 vp->vlast = fhp->vprev;
981 }
982 if (fhp->vprev) {
983 fhp->vprev->vnext = fhp->vnext;
984 } else {
985 vp->vfirst = fhp->vnext;
986 }
987 fhp->vnext = NULL;
988 fhp->vprev = NULL;
989 fhp->vhead = NULL;
990 pvr2_channel_done(&fhp->channel);
991 pvr2_trace(PVR2_TRACE_STRUCT,
992 "Destroying pvr_v4l2_fh id=%p",fhp);
Mike Iselye57b1c82008-04-21 03:52:34 -0300993 if (fhp->input_map) {
994 kfree(fhp->input_map);
995 fhp->input_map = NULL;
996 }
Mike Isely794b1602008-04-22 14:45:45 -0300997 kfree(fhp);
998 if (vp->channel.mc_head->disconnect_flag && !vp->vfirst) {
999 pvr2_v4l2_destroy_no_lock(vp);
1000 }
Mike Iselyd8554972006-06-26 20:58:46 -03001001 return 0;
1002}
1003
1004
Hans Verkuilbec43662008-12-30 06:58:20 -03001005static int pvr2_v4l2_open(struct file *file)
Mike Iselyd8554972006-06-26 20:58:46 -03001006{
Mike Isely75910052006-09-23 22:30:50 -03001007 struct pvr2_v4l2_dev *dip; /* Our own context pointer */
Mike Iselyd8554972006-06-26 20:58:46 -03001008 struct pvr2_v4l2_fh *fhp;
1009 struct pvr2_v4l2 *vp;
1010 struct pvr2_hdw *hdw;
Mike Isely1cb03b72008-04-21 03:47:43 -03001011 unsigned int input_mask = 0;
Mike Iselye57b1c82008-04-21 03:52:34 -03001012 unsigned int input_cnt,idx;
Mike Isely1cb03b72008-04-21 03:47:43 -03001013 int ret = 0;
Mike Iselyd8554972006-06-26 20:58:46 -03001014
Mike Isely75910052006-09-23 22:30:50 -03001015 dip = container_of(video_devdata(file),struct pvr2_v4l2_dev,devbase);
Mike Iselyd8554972006-06-26 20:58:46 -03001016
1017 vp = dip->v4lp;
1018 hdw = vp->channel.hdw;
1019
1020 pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_open");
1021
1022 if (!pvr2_hdw_dev_ok(hdw)) {
1023 pvr2_trace(PVR2_TRACE_OPEN_CLOSE,
1024 "pvr2_v4l2_open: hardware not ready");
1025 return -EIO;
1026 }
1027
Mike Isely4b85dee2007-01-20 00:03:32 -03001028 fhp = kzalloc(sizeof(*fhp),GFP_KERNEL);
Mike Iselyd8554972006-06-26 20:58:46 -03001029 if (!fhp) {
1030 return -ENOMEM;
1031 }
Mike Iselyd8554972006-06-26 20:58:46 -03001032
1033 init_waitqueue_head(&fhp->wait_data);
1034 fhp->dev_info = dip;
1035
Mike Isely794b1602008-04-22 14:45:45 -03001036 pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp);
1037 pvr2_channel_init(&fhp->channel,vp->channel.mc_head);
Pantelis Koukousoulasae2b9e22006-12-27 23:09:55 -03001038
Mike Isely1cb03b72008-04-21 03:47:43 -03001039 if (dip->v4l_type == VFL_TYPE_RADIO) {
1040 /* Opening device as a radio, legal input selection subset
1041 is just the radio. */
1042 input_mask = (1 << PVR2_CVAL_INPUT_RADIO);
1043 } else {
1044 /* Opening the main V4L device, legal input selection
1045 subset includes all analog inputs. */
1046 input_mask = ((1 << PVR2_CVAL_INPUT_RADIO) |
1047 (1 << PVR2_CVAL_INPUT_TV) |
1048 (1 << PVR2_CVAL_INPUT_COMPOSITE) |
1049 (1 << PVR2_CVAL_INPUT_SVIDEO));
1050 }
1051 ret = pvr2_channel_limit_inputs(&fhp->channel,input_mask);
1052 if (ret) {
1053 pvr2_channel_done(&fhp->channel);
1054 pvr2_trace(PVR2_TRACE_STRUCT,
1055 "Destroying pvr_v4l2_fh id=%p (input mask error)",
1056 fhp);
1057
1058 kfree(fhp);
1059 return ret;
1060 }
1061
Mike Iselye57b1c82008-04-21 03:52:34 -03001062 input_mask &= pvr2_hdw_get_input_available(hdw);
1063 input_cnt = 0;
1064 for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) {
1065 if (input_mask & (1 << idx)) input_cnt++;
1066 }
1067 fhp->input_cnt = input_cnt;
1068 fhp->input_map = kzalloc(input_cnt,GFP_KERNEL);
1069 if (!fhp->input_map) {
1070 pvr2_channel_done(&fhp->channel);
1071 pvr2_trace(PVR2_TRACE_STRUCT,
1072 "Destroying pvr_v4l2_fh id=%p (input map failure)",
1073 fhp);
1074 kfree(fhp);
1075 return -ENOMEM;
1076 }
1077 input_cnt = 0;
1078 for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) {
1079 if (!(input_mask & (1 << idx))) continue;
1080 fhp->input_map[input_cnt++] = idx;
1081 }
1082
Mike Isely794b1602008-04-22 14:45:45 -03001083 fhp->vnext = NULL;
1084 fhp->vprev = vp->vlast;
1085 if (vp->vlast) {
1086 vp->vlast->vnext = fhp;
1087 } else {
1088 vp->vfirst = fhp;
1089 }
1090 vp->vlast = fhp;
1091 fhp->vhead = vp;
Mike Iselyc74e0062006-12-30 18:31:22 -03001092
Mike Iselyd8554972006-06-26 20:58:46 -03001093 fhp->file = file;
1094 file->private_data = fhp;
1095 v4l2_prio_open(&vp->prio,&fhp->prio);
1096
1097 fhp->fw_mode_flag = pvr2_hdw_cpufw_get_enabled(hdw);
1098
1099 return 0;
1100}
1101
1102
1103static void pvr2_v4l2_notify(struct pvr2_v4l2_fh *fhp)
1104{
1105 wake_up(&fhp->wait_data);
1106}
1107
1108static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh)
1109{
1110 int ret;
1111 struct pvr2_stream *sp;
1112 struct pvr2_hdw *hdw;
1113 if (fh->rhp) return 0;
1114
Mike Isely16eb40d2006-12-30 18:27:32 -03001115 if (!fh->dev_info->stream) {
1116 /* No stream defined for this node. This means that we're
1117 not currently allowed to stream from this node. */
1118 return -EPERM;
1119 }
1120
Mike Iselyd8554972006-06-26 20:58:46 -03001121 /* First read() attempt. Try to claim the stream and start
1122 it... */
1123 if ((ret = pvr2_channel_claim_stream(&fh->channel,
1124 fh->dev_info->stream)) != 0) {
1125 /* Someone else must already have it */
1126 return ret;
1127 }
1128
1129 fh->rhp = pvr2_channel_create_mpeg_stream(fh->dev_info->stream);
1130 if (!fh->rhp) {
Mike Iselya0fd1cb2006-06-30 11:35:28 -03001131 pvr2_channel_claim_stream(&fh->channel,NULL);
Mike Iselyd8554972006-06-26 20:58:46 -03001132 return -ENOMEM;
1133 }
1134
1135 hdw = fh->channel.mc_head->hdw;
1136 sp = fh->dev_info->stream->stream;
1137 pvr2_stream_set_callback(sp,(pvr2_stream_callback)pvr2_v4l2_notify,fh);
1138 pvr2_hdw_set_stream_type(hdw,fh->dev_info->config);
Mike Isely681c7392007-11-26 01:48:52 -03001139 if ((ret = pvr2_hdw_set_streaming(hdw,!0)) < 0) return ret;
1140 return pvr2_ioread_set_enabled(fh->rhp,!0);
Mike Iselyd8554972006-06-26 20:58:46 -03001141}
1142
1143
1144static ssize_t pvr2_v4l2_read(struct file *file,
1145 char __user *buff, size_t count, loff_t *ppos)
1146{
1147 struct pvr2_v4l2_fh *fh = file->private_data;
1148 int ret;
1149
1150 if (fh->fw_mode_flag) {
1151 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
1152 char *tbuf;
1153 int c1,c2;
1154 int tcnt = 0;
1155 unsigned int offs = *ppos;
1156
1157 tbuf = kmalloc(PAGE_SIZE,GFP_KERNEL);
1158 if (!tbuf) return -ENOMEM;
1159
1160 while (count) {
1161 c1 = count;
1162 if (c1 > PAGE_SIZE) c1 = PAGE_SIZE;
1163 c2 = pvr2_hdw_cpufw_get(hdw,offs,tbuf,c1);
1164 if (c2 < 0) {
1165 tcnt = c2;
1166 break;
1167 }
1168 if (!c2) break;
1169 if (copy_to_user(buff,tbuf,c2)) {
1170 tcnt = -EFAULT;
1171 break;
1172 }
1173 offs += c2;
1174 tcnt += c2;
1175 buff += c2;
1176 count -= c2;
1177 *ppos += c2;
1178 }
1179 kfree(tbuf);
1180 return tcnt;
1181 }
1182
1183 if (!fh->rhp) {
1184 ret = pvr2_v4l2_iosetup(fh);
1185 if (ret) {
1186 return ret;
1187 }
1188 }
1189
1190 for (;;) {
1191 ret = pvr2_ioread_read(fh->rhp,buff,count);
1192 if (ret >= 0) break;
1193 if (ret != -EAGAIN) break;
1194 if (file->f_flags & O_NONBLOCK) break;
1195 /* Doing blocking I/O. Wait here. */
1196 ret = wait_event_interruptible(
1197 fh->wait_data,
1198 pvr2_ioread_avail(fh->rhp) >= 0);
1199 if (ret < 0) break;
1200 }
1201
1202 return ret;
1203}
1204
1205
1206static unsigned int pvr2_v4l2_poll(struct file *file, poll_table *wait)
1207{
1208 unsigned int mask = 0;
1209 struct pvr2_v4l2_fh *fh = file->private_data;
1210 int ret;
1211
1212 if (fh->fw_mode_flag) {
1213 mask |= POLLIN | POLLRDNORM;
1214 return mask;
1215 }
1216
1217 if (!fh->rhp) {
1218 ret = pvr2_v4l2_iosetup(fh);
1219 if (ret) return POLLERR;
1220 }
1221
1222 poll_wait(file,&fh->wait_data,wait);
1223
1224 if (pvr2_ioread_avail(fh->rhp) >= 0) {
1225 mask |= POLLIN | POLLRDNORM;
1226 }
1227
1228 return mask;
1229}
1230
1231
Hans Verkuilbec43662008-12-30 06:58:20 -03001232static const struct v4l2_file_operations vdev_fops = {
Mike Iselyd8554972006-06-26 20:58:46 -03001233 .owner = THIS_MODULE,
1234 .open = pvr2_v4l2_open,
1235 .release = pvr2_v4l2_release,
1236 .read = pvr2_v4l2_read,
1237 .ioctl = pvr2_v4l2_ioctl,
Mike Iselyd8554972006-06-26 20:58:46 -03001238 .poll = pvr2_v4l2_poll,
1239};
1240
1241
Mike Iselyd8554972006-06-26 20:58:46 -03001242static struct video_device vdev_template = {
Mike Iselyd8554972006-06-26 20:58:46 -03001243 .fops = &vdev_fops,
1244};
1245
1246
1247static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
1248 struct pvr2_v4l2 *vp,
Mike Isely16eb40d2006-12-30 18:27:32 -03001249 int v4l_type)
Mike Iselyd8554972006-06-26 20:58:46 -03001250{
Mike Isely4a89baa2009-10-12 00:13:28 -03001251 struct usb_device *usbdev;
Mike Iselyd8554972006-06-26 20:58:46 -03001252 int mindevnum;
1253 int unit_number;
Al Viro89952d12007-03-14 09:17:59 +00001254 int *nr_ptr = NULL;
Mike Iselyd8554972006-06-26 20:58:46 -03001255 dip->v4lp = vp;
Mike Iselyd8554972006-06-26 20:58:46 -03001256
Mike Isely4a89baa2009-10-12 00:13:28 -03001257 usbdev = pvr2_hdw_get_dev(vp->channel.mc_head->hdw);
Mike Isely16eb40d2006-12-30 18:27:32 -03001258 dip->v4l_type = v4l_type;
1259 switch (v4l_type) {
1260 case VFL_TYPE_GRABBER:
Mike Iselyd8554972006-06-26 20:58:46 -03001261 dip->stream = &vp->channel.mc_head->video_stream;
Mike Isely16eb40d2006-12-30 18:27:32 -03001262 dip->config = pvr2_config_mpeg;
1263 dip->minor_type = pvr2_v4l_type_video;
1264 nr_ptr = video_nr;
Mike Iselyc74e0062006-12-30 18:31:22 -03001265 if (!dip->stream) {
Mauro Carvalho Chehabbe9ed512009-01-08 09:13:42 -03001266 pr_err(KBUILD_MODNAME
1267 ": Failed to set up pvrusb2 v4l video dev"
1268 " due to missing stream instance\n");
Mike Iselyc74e0062006-12-30 18:31:22 -03001269 return;
1270 }
Mike Iselyd8554972006-06-26 20:58:46 -03001271 break;
Mike Isely16eb40d2006-12-30 18:27:32 -03001272 case VFL_TYPE_VBI:
1273 dip->config = pvr2_config_vbi;
1274 dip->minor_type = pvr2_v4l_type_vbi;
1275 nr_ptr = vbi_nr;
Mike Iselyd8554972006-06-26 20:58:46 -03001276 break;
Mike Isely16eb40d2006-12-30 18:27:32 -03001277 case VFL_TYPE_RADIO:
Mike Iselyaf78a482007-01-20 00:04:31 -03001278 dip->stream = &vp->channel.mc_head->video_stream;
1279 dip->config = pvr2_config_mpeg;
Mike Isely16eb40d2006-12-30 18:27:32 -03001280 dip->minor_type = pvr2_v4l_type_radio;
1281 nr_ptr = radio_nr;
Mike Iselyd8554972006-06-26 20:58:46 -03001282 break;
1283 default:
1284 /* Bail out (this should be impossible) */
Mauro Carvalho Chehabbe9ed512009-01-08 09:13:42 -03001285 pr_err(KBUILD_MODNAME ": Failed to set up pvrusb2 v4l dev"
1286 " due to unrecognized config\n");
Mike Iselyd8554972006-06-26 20:58:46 -03001287 return;
1288 }
1289
Mike Isely75910052006-09-23 22:30:50 -03001290 memcpy(&dip->devbase,&vdev_template,sizeof(vdev_template));
1291 dip->devbase.release = pvr2_video_device_release;
Mike Iselyd8554972006-06-26 20:58:46 -03001292
1293 mindevnum = -1;
1294 unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw);
Mike Isely16eb40d2006-12-30 18:27:32 -03001295 if (nr_ptr && (unit_number >= 0) && (unit_number < PVR_NUM)) {
1296 mindevnum = nr_ptr[unit_number];
Mike Iselyd8554972006-06-26 20:58:46 -03001297 }
Mike Isely4a89baa2009-10-12 00:13:28 -03001298 dip->devbase.parent = &usbdev->dev;
Mike Isely16eb40d2006-12-30 18:27:32 -03001299 if ((video_register_device(&dip->devbase,
1300 dip->v4l_type, mindevnum) < 0) &&
1301 (video_register_device(&dip->devbase,
1302 dip->v4l_type, -1) < 0)) {
Mauro Carvalho Chehabbe9ed512009-01-08 09:13:42 -03001303 pr_err(KBUILD_MODNAME
1304 ": Failed to register pvrusb2 v4l device\n");
Pantelis Koukousoulasae2b9e22006-12-27 23:09:55 -03001305 }
Mike Isely16eb40d2006-12-30 18:27:32 -03001306
Laurent Pinchart38c7c032009-11-27 13:57:15 -03001307 printk(KERN_INFO "pvrusb2: registered device %s [%s]\n",
1308 video_device_node_name(&dip->devbase),
Mike Isely16eb40d2006-12-30 18:27:32 -03001309 pvr2_config_get_name(dip->config));
Mike Iselyd8554972006-06-26 20:58:46 -03001310
Mike Iselyd8554972006-06-26 20:58:46 -03001311 pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,
Mike Isely16eb40d2006-12-30 18:27:32 -03001312 dip->minor_type,dip->devbase.minor);
Mike Iselyd8554972006-06-26 20:58:46 -03001313}
1314
1315
1316struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
1317{
1318 struct pvr2_v4l2 *vp;
1319
Mike Isely4b85dee2007-01-20 00:03:32 -03001320 vp = kzalloc(sizeof(*vp),GFP_KERNEL);
Mike Iselyd8554972006-06-26 20:58:46 -03001321 if (!vp) return vp;
Mike Iselyd8554972006-06-26 20:58:46 -03001322 pvr2_channel_init(&vp->channel,mnp);
1323 pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp);
1324
1325 vp->channel.check_func = pvr2_v4l2_internal_check;
1326
1327 /* register streams */
Mike Iselybeb0ecd2008-04-22 14:45:38 -03001328 vp->dev_video = kzalloc(sizeof(*vp->dev_video),GFP_KERNEL);
1329 if (!vp->dev_video) goto fail;
Mike Isely16eb40d2006-12-30 18:27:32 -03001330 pvr2_v4l2_dev_init(vp->dev_video,vp,VFL_TYPE_GRABBER);
Mike Iselye57b1c82008-04-21 03:52:34 -03001331 if (pvr2_hdw_get_input_available(vp->channel.mc_head->hdw) &
1332 (1 << PVR2_CVAL_INPUT_RADIO)) {
Mike Iselybeb0ecd2008-04-22 14:45:38 -03001333 vp->dev_radio = kzalloc(sizeof(*vp->dev_radio),GFP_KERNEL);
1334 if (!vp->dev_radio) goto fail;
1335 pvr2_v4l2_dev_init(vp->dev_radio,vp,VFL_TYPE_RADIO);
1336 }
Mike Iselyd8554972006-06-26 20:58:46 -03001337
1338 return vp;
Mike Iselybeb0ecd2008-04-22 14:45:38 -03001339 fail:
1340 pvr2_trace(PVR2_TRACE_STRUCT,"Failure creating pvr2_v4l2 id=%p",vp);
1341 pvr2_v4l2_destroy_no_lock(vp);
Harvey Harrisona6a3a172008-04-28 16:50:03 -07001342 return NULL;
Mike Iselyd8554972006-06-26 20:58:46 -03001343}
1344
1345/*
1346 Stuff for Emacs to see, in order to encourage consistent editing style:
1347 *** Local Variables: ***
1348 *** mode: c ***
1349 *** fill-column: 75 ***
1350 *** tab-width: 8 ***
1351 *** c-basic-offset: 8 ***
1352 *** End: ***
1353 */