blob: 97ed95957992ff9d5107ff90b1c754f3f2c6bbdc [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",
93 .version = KERNEL_VERSION(0,8,0),
94 .capabilities = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_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
154static const char *get_v4l_name(int v4l_type)
155{
156 switch (v4l_type) {
157 case VFL_TYPE_GRABBER: return "video";
158 case VFL_TYPE_RADIO: return "radio";
159 case VFL_TYPE_VBI: return "vbi";
160 default: return "?";
161 }
162}
163
164
Mike Iselyd8554972006-06-26 20:58:46 -0300165/*
166 * pvr_ioctl()
167 *
168 * This is part of Video 4 Linux API. The procedure handles ioctl() calls.
169 *
170 */
Mauro Carvalho Chehabb1f88402008-10-21 11:27:20 -0300171static int __pvr2_v4l2_do_ioctl(struct file *file,
Mike Iselyd8554972006-06-26 20:58:46 -0300172 unsigned int cmd, void *arg)
173{
174 struct pvr2_v4l2_fh *fh = file->private_data;
175 struct pvr2_v4l2 *vp = fh->vhead;
176 struct pvr2_v4l2_dev *dev_info = fh->dev_info;
177 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
178 int ret = -EINVAL;
179
180 if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
181 v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),cmd);
182 }
183
184 if (!pvr2_hdw_dev_ok(hdw)) {
185 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
186 "ioctl failed - bad or no context");
187 return -EFAULT;
188 }
189
190 /* check priority */
191 switch (cmd) {
192 case VIDIOC_S_CTRL:
193 case VIDIOC_S_STD:
194 case VIDIOC_S_INPUT:
195 case VIDIOC_S_TUNER:
196 case VIDIOC_S_FREQUENCY:
197 ret = v4l2_prio_check(&vp->prio, &fh->prio);
198 if (ret)
199 return ret;
200 }
201
202 switch (cmd) {
203 case VIDIOC_QUERYCAP:
204 {
205 struct v4l2_capability *cap = arg;
206
207 memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
Mike Isely31a18542007-04-08 01:11:47 -0300208 strlcpy(cap->bus_info,pvr2_hdw_get_bus_info(hdw),
209 sizeof(cap->bus_info));
Mike Isely78a47102007-11-26 01:58:20 -0300210 strlcpy(cap->card,pvr2_hdw_get_desc(hdw),sizeof(cap->card));
Mike Iselyd8554972006-06-26 20:58:46 -0300211
212 ret = 0;
213 break;
214 }
215
216 case VIDIOC_G_PRIORITY:
217 {
218 enum v4l2_priority *p = arg;
219
220 *p = v4l2_prio_max(&vp->prio);
221 ret = 0;
222 break;
223 }
224
225 case VIDIOC_S_PRIORITY:
226 {
227 enum v4l2_priority *prio = arg;
228
229 ret = v4l2_prio_change(&vp->prio, &fh->prio, *prio);
230 break;
231 }
232
233 case VIDIOC_ENUMSTD:
234 {
235 struct v4l2_standard *vs = (struct v4l2_standard *)arg;
236 int idx = vs->index;
237 ret = pvr2_hdw_get_stdenum_value(hdw,vs,idx+1);
238 break;
239 }
240
241 case VIDIOC_G_STD:
242 {
243 int val = 0;
244 ret = pvr2_ctrl_get_value(
245 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR),&val);
246 *(v4l2_std_id *)arg = val;
247 break;
248 }
249
250 case VIDIOC_S_STD:
251 {
252 ret = pvr2_ctrl_set_value(
253 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR),
254 *(v4l2_std_id *)arg);
255 break;
256 }
257
258 case VIDIOC_ENUMINPUT:
259 {
260 struct pvr2_ctrl *cptr;
261 struct v4l2_input *vi = (struct v4l2_input *)arg;
262 struct v4l2_input tmp;
263 unsigned int cnt;
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300264 int val;
Mike Iselyd8554972006-06-26 20:58:46 -0300265
266 cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
267
268 memset(&tmp,0,sizeof(tmp));
269 tmp.index = vi->index;
270 ret = 0;
Mike Iselye57b1c82008-04-21 03:52:34 -0300271 if ((vi->index < 0) || (vi->index >= fh->input_cnt)) {
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300272 ret = -EINVAL;
273 break;
274 }
Mike Iselye57b1c82008-04-21 03:52:34 -0300275 val = fh->input_map[vi->index];
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300276 switch (val) {
Mike Iselyd8554972006-06-26 20:58:46 -0300277 case PVR2_CVAL_INPUT_TV:
Mike Isely895c3e82008-04-22 14:45:37 -0300278 case PVR2_CVAL_INPUT_DTV:
Mike Iselyd8554972006-06-26 20:58:46 -0300279 case PVR2_CVAL_INPUT_RADIO:
280 tmp.type = V4L2_INPUT_TYPE_TUNER;
281 break;
282 case PVR2_CVAL_INPUT_SVIDEO:
283 case PVR2_CVAL_INPUT_COMPOSITE:
284 tmp.type = V4L2_INPUT_TYPE_CAMERA;
285 break;
286 default:
287 ret = -EINVAL;
288 break;
289 }
290 if (ret < 0) break;
291
292 cnt = 0;
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300293 pvr2_ctrl_get_valname(cptr,val,
Mike Iselyd8554972006-06-26 20:58:46 -0300294 tmp.name,sizeof(tmp.name)-1,&cnt);
295 tmp.name[cnt] = 0;
296
297 /* Don't bother with audioset, since this driver currently
298 always switches the audio whenever the video is
299 switched. */
300
301 /* Handling std is a tougher problem. It doesn't make
302 sense in cases where a device might be multi-standard.
303 We could just copy out the current value for the
304 standard, but it can change over time. For now just
305 leave it zero. */
306
307 memcpy(vi, &tmp, sizeof(tmp));
308
309 ret = 0;
310 break;
311 }
312
313 case VIDIOC_G_INPUT:
314 {
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300315 unsigned int idx;
Mike Iselyd8554972006-06-26 20:58:46 -0300316 struct pvr2_ctrl *cptr;
317 struct v4l2_input *vi = (struct v4l2_input *)arg;
318 int val;
319 cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
320 val = 0;
321 ret = pvr2_ctrl_get_value(cptr,&val);
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300322 vi->index = 0;
Mike Iselye57b1c82008-04-21 03:52:34 -0300323 for (idx = 0; idx < fh->input_cnt; idx++) {
324 if (fh->input_map[idx] == val) {
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300325 vi->index = idx;
326 break;
327 }
328 }
Mike Iselyd8554972006-06-26 20:58:46 -0300329 break;
330 }
331
332 case VIDIOC_S_INPUT:
333 {
334 struct v4l2_input *vi = (struct v4l2_input *)arg;
Mike Iselye57b1c82008-04-21 03:52:34 -0300335 if ((vi->index < 0) || (vi->index >= fh->input_cnt)) {
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300336 ret = -ERANGE;
337 break;
338 }
Mike Iselyd8554972006-06-26 20:58:46 -0300339 ret = pvr2_ctrl_set_value(
340 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
Mike Iselye57b1c82008-04-21 03:52:34 -0300341 fh->input_map[vi->index]);
Mike Iselyd8554972006-06-26 20:58:46 -0300342 break;
343 }
344
345 case VIDIOC_ENUMAUDIO:
346 {
Pantelis Koukousoulas848ed3c2007-01-20 01:57:36 -0300347 /* pkt: FIXME: We are returning one "fake" input here
348 which could very well be called "whatever_we_like".
349 This is for apps that want to see an audio input
350 just to feel comfortable, as well as to test if
351 it can do stereo or sth. There is actually no guarantee
352 that the actual audio input cannot change behind the app's
353 back, but most applications should not mind that either.
354
355 Hopefully, mplayer people will work with us on this (this
356 whole mess is to support mplayer pvr://), or Hans will come
357 up with a more standard way to say "we have inputs but we
358 don 't want you to change them independent of video" which
359 will sort this mess.
360 */
361 struct v4l2_audio *vin = arg;
Mike Iselyd8554972006-06-26 20:58:46 -0300362 ret = -EINVAL;
Pantelis Koukousoulas848ed3c2007-01-20 01:57:36 -0300363 if (vin->index > 0) break;
364 strncpy(vin->name, "PVRUSB2 Audio",14);
365 vin->capability = V4L2_AUDCAP_STEREO;
366 ret = 0;
367 break;
Mike Iselyd8554972006-06-26 20:58:46 -0300368 break;
369 }
370
371 case VIDIOC_G_AUDIO:
372 {
Pantelis Koukousoulas848ed3c2007-01-20 01:57:36 -0300373 /* pkt: FIXME: see above comment (VIDIOC_ENUMAUDIO) */
374 struct v4l2_audio *vin = arg;
375 memset(vin,0,sizeof(*vin));
376 vin->index = 0;
377 strncpy(vin->name, "PVRUSB2 Audio",14);
378 vin->capability = V4L2_AUDCAP_STEREO;
379 ret = 0;
Mike Iselyd8554972006-06-26 20:58:46 -0300380 break;
381 }
382
383 case VIDIOC_S_AUDIO:
384 {
385 ret = -EINVAL;
386 break;
387 }
388 case VIDIOC_G_TUNER:
389 {
390 struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
Mauro Carvalho Chehab5cc1dd82007-01-21 22:02:58 -0300391
Michael Krufky8d364362007-01-22 02:17:55 -0300392 if (vt->index != 0) break; /* Only answer for the 1st tuner */
Mauro Carvalho Chehab5cc1dd82007-01-21 22:02:58 -0300393
Mike Isely18103c52007-01-20 00:09:47 -0300394 pvr2_hdw_execute_tuner_poll(hdw);
395 ret = pvr2_hdw_get_tuner_status(hdw,vt);
Mike Iselyd8554972006-06-26 20:58:46 -0300396 break;
397 }
398
399 case VIDIOC_S_TUNER:
400 {
401 struct v4l2_tuner *vt=(struct v4l2_tuner *)arg;
402
403 if (vt->index != 0)
404 break;
405
406 ret = pvr2_ctrl_set_value(
407 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE),
408 vt->audmode);
Mike Isely11fc76c2007-01-20 00:24:52 -0300409 break;
Mike Iselyd8554972006-06-26 20:58:46 -0300410 }
411
412 case VIDIOC_S_FREQUENCY:
413 {
414 const struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
Mike Iselyc0e69312006-12-27 23:25:06 -0300415 unsigned long fv;
Mike Isely18103c52007-01-20 00:09:47 -0300416 struct v4l2_tuner vt;
417 int cur_input;
418 struct pvr2_ctrl *ctrlp;
419 ret = pvr2_hdw_get_tuner_status(hdw,&vt);
420 if (ret != 0) break;
421 ctrlp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
422 ret = pvr2_ctrl_get_value(ctrlp,&cur_input);
423 if (ret != 0) break;
Mike Iselyc0e69312006-12-27 23:25:06 -0300424 if (vf->type == V4L2_TUNER_RADIO) {
Mike Isely18103c52007-01-20 00:09:47 -0300425 if (cur_input != PVR2_CVAL_INPUT_RADIO) {
426 pvr2_ctrl_set_value(ctrlp,
427 PVR2_CVAL_INPUT_RADIO);
428 }
429 } else {
430 if (cur_input == PVR2_CVAL_INPUT_RADIO) {
431 pvr2_ctrl_set_value(ctrlp,
432 PVR2_CVAL_INPUT_TV);
433 }
434 }
435 fv = vf->frequency;
436 if (vt.capability & V4L2_TUNER_CAP_LOW) {
Mike Iselyc0e69312006-12-27 23:25:06 -0300437 fv = (fv * 125) / 2;
438 } else {
439 fv = fv * 62500;
440 }
Mike Iselyd8554972006-06-26 20:58:46 -0300441 ret = pvr2_ctrl_set_value(
Mike Iselyc0e69312006-12-27 23:25:06 -0300442 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),fv);
Mike Iselyd8554972006-06-26 20:58:46 -0300443 break;
444 }
445
446 case VIDIOC_G_FREQUENCY:
447 {
448 struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
449 int val = 0;
Mike Isely18103c52007-01-20 00:09:47 -0300450 int cur_input;
451 struct v4l2_tuner vt;
452 ret = pvr2_hdw_get_tuner_status(hdw,&vt);
453 if (ret != 0) break;
Mike Iselyd8554972006-06-26 20:58:46 -0300454 ret = pvr2_ctrl_get_value(
455 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),
456 &val);
Mike Iselyc0e69312006-12-27 23:25:06 -0300457 if (ret != 0) break;
458 pvr2_ctrl_get_value(
459 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
460 &cur_input);
461 if (cur_input == PVR2_CVAL_INPUT_RADIO) {
Mike Iselyc0e69312006-12-27 23:25:06 -0300462 vf->type = V4L2_TUNER_RADIO;
463 } else {
Mike Iselyc0e69312006-12-27 23:25:06 -0300464 vf->type = V4L2_TUNER_ANALOG_TV;
465 }
Mike Isely18103c52007-01-20 00:09:47 -0300466 if (vt.capability & V4L2_TUNER_CAP_LOW) {
467 val = (val * 2) / 125;
468 } else {
469 val /= 62500;
470 }
471 vf->frequency = val;
Mike Iselyd8554972006-06-26 20:58:46 -0300472 break;
473 }
474
475 case VIDIOC_ENUM_FMT:
476 {
477 struct v4l2_fmtdesc *fd = (struct v4l2_fmtdesc *)arg;
478
479 /* Only one format is supported : mpeg.*/
480 if (fd->index != 0)
481 break;
482
483 memcpy(fd, pvr_fmtdesc, sizeof(struct v4l2_fmtdesc));
484 ret = 0;
485 break;
486 }
487
488 case VIDIOC_G_FMT:
489 {
490 struct v4l2_format *vf = (struct v4l2_format *)arg;
491 int val;
492 switch(vf->type) {
493 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
494 memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
495 sizeof(struct v4l2_format));
496 val = 0;
497 pvr2_ctrl_get_value(
498 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES),
499 &val);
500 vf->fmt.pix.width = val;
501 val = 0;
502 pvr2_ctrl_get_value(
Mike Iselyd8554972006-06-26 20:58:46 -0300503 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES),
504 &val);
505 vf->fmt.pix.height = val;
506 ret = 0;
507 break;
508 case V4L2_BUF_TYPE_VBI_CAPTURE:
509 // ????? Still need to figure out to do VBI correctly
510 ret = -EINVAL;
511 break;
512 default:
513 ret = -EINVAL;
514 break;
515 }
516 break;
517 }
518
519 case VIDIOC_TRY_FMT:
520 case VIDIOC_S_FMT:
521 {
522 struct v4l2_format *vf = (struct v4l2_format *)arg;
523
524 ret = 0;
525 switch(vf->type) {
526 case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
Pantelis Koukousoulasfd694962007-01-20 01:59:54 -0300527 int lmin,lmax,ldef;
Mike Iselye95a1912006-08-08 09:10:07 -0300528 struct pvr2_ctrl *hcp,*vcp;
Mike Iselyd8554972006-06-26 20:58:46 -0300529 int h = vf->fmt.pix.height;
530 int w = vf->fmt.pix.width;
Mike Iselye95a1912006-08-08 09:10:07 -0300531 hcp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES);
532 vcp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES);
Mike Iselyd8554972006-06-26 20:58:46 -0300533
Mike Iselye95a1912006-08-08 09:10:07 -0300534 lmin = pvr2_ctrl_get_min(hcp);
535 lmax = pvr2_ctrl_get_max(hcp);
Mike Isely26dd1c52008-08-31 20:55:03 -0300536 pvr2_ctrl_get_def(hcp, &ldef);
Pantelis Koukousoulasfd694962007-01-20 01:59:54 -0300537 if (w == -1) {
538 w = ldef;
539 } else if (w < lmin) {
Mike Iselye95a1912006-08-08 09:10:07 -0300540 w = lmin;
541 } else if (w > lmax) {
542 w = lmax;
Mike Isely039c4302006-06-25 20:04:16 -0300543 }
Hans Verkuilb31e3412006-09-01 18:36:10 -0300544 lmin = pvr2_ctrl_get_min(vcp);
545 lmax = pvr2_ctrl_get_max(vcp);
Mike Isely26dd1c52008-08-31 20:55:03 -0300546 pvr2_ctrl_get_def(vcp, &ldef);
Pantelis Koukousoulasfd694962007-01-20 01:59:54 -0300547 if (h == -1) {
548 h = ldef;
549 } else if (h < lmin) {
Hans Verkuilb31e3412006-09-01 18:36:10 -0300550 h = lmin;
551 } else if (h > lmax) {
552 h = lmax;
553 }
Mike Iselyd8554972006-06-26 20:58:46 -0300554
555 memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
556 sizeof(struct v4l2_format));
Mike Isely039c4302006-06-25 20:04:16 -0300557 vf->fmt.pix.width = w;
558 vf->fmt.pix.height = h;
Mike Iselyd8554972006-06-26 20:58:46 -0300559
560 if (cmd == VIDIOC_S_FMT) {
Mike Iselye95a1912006-08-08 09:10:07 -0300561 pvr2_ctrl_set_value(hcp,vf->fmt.pix.width);
562 pvr2_ctrl_set_value(vcp,vf->fmt.pix.height);
Mike Iselyd8554972006-06-26 20:58:46 -0300563 }
564 } break;
565 case V4L2_BUF_TYPE_VBI_CAPTURE:
566 // ????? Still need to figure out to do VBI correctly
567 ret = -EINVAL;
568 break;
569 default:
570 ret = -EINVAL;
571 break;
572 }
573 break;
574 }
575
576 case VIDIOC_STREAMON:
577 {
Mike Isely16eb40d2006-12-30 18:27:32 -0300578 if (!fh->dev_info->stream) {
579 /* No stream defined for this node. This means
580 that we're not currently allowed to stream from
581 this node. */
582 ret = -EPERM;
583 break;
584 }
Mike Iselyd8554972006-06-26 20:58:46 -0300585 ret = pvr2_hdw_set_stream_type(hdw,dev_info->config);
586 if (ret < 0) return ret;
587 ret = pvr2_hdw_set_streaming(hdw,!0);
588 break;
589 }
590
591 case VIDIOC_STREAMOFF:
592 {
Mike Isely16eb40d2006-12-30 18:27:32 -0300593 if (!fh->dev_info->stream) {
594 /* No stream defined for this node. This means
595 that we're not currently allowed to stream from
596 this node. */
597 ret = -EPERM;
598 break;
599 }
Mike Iselyd8554972006-06-26 20:58:46 -0300600 ret = pvr2_hdw_set_streaming(hdw,0);
601 break;
602 }
603
604 case VIDIOC_QUERYCTRL:
605 {
606 struct pvr2_ctrl *cptr;
Mike Isely26dd1c52008-08-31 20:55:03 -0300607 int val;
Mike Iselyd8554972006-06-26 20:58:46 -0300608 struct v4l2_queryctrl *vc = (struct v4l2_queryctrl *)arg;
609 ret = 0;
Mike Isely1d9f8462006-06-25 20:04:58 -0300610 if (vc->id & V4L2_CTRL_FLAG_NEXT_CTRL) {
611 cptr = pvr2_hdw_get_ctrl_nextv4l(
612 hdw,(vc->id & ~V4L2_CTRL_FLAG_NEXT_CTRL));
613 if (cptr) vc->id = pvr2_ctrl_get_v4lid(cptr);
614 } else {
615 cptr = pvr2_hdw_get_ctrl_v4l(hdw,vc->id);
616 }
Mike Iselyd8554972006-06-26 20:58:46 -0300617 if (!cptr) {
Mike Isely0885ba12006-06-25 21:30:47 -0300618 pvr2_trace(PVR2_TRACE_V4LIOCTL,
Mike Iselya761f432006-06-25 20:04:44 -0300619 "QUERYCTRL id=0x%x not implemented here",
620 vc->id);
Mike Iselyd8554972006-06-26 20:58:46 -0300621 ret = -EINVAL;
622 break;
623 }
624
Mike Iselya761f432006-06-25 20:04:44 -0300625 pvr2_trace(PVR2_TRACE_V4LIOCTL,
626 "QUERYCTRL id=0x%x mapping name=%s (%s)",
627 vc->id,pvr2_ctrl_get_name(cptr),
628 pvr2_ctrl_get_desc(cptr));
629 strlcpy(vc->name,pvr2_ctrl_get_desc(cptr),sizeof(vc->name));
630 vc->flags = pvr2_ctrl_get_v4lflags(cptr);
Mike Isely26dd1c52008-08-31 20:55:03 -0300631 pvr2_ctrl_get_def(cptr, &val);
632 vc->default_value = val;
Mike Iselyd8554972006-06-26 20:58:46 -0300633 switch (pvr2_ctrl_get_type(cptr)) {
634 case pvr2_ctl_enum:
635 vc->type = V4L2_CTRL_TYPE_MENU;
636 vc->minimum = 0;
637 vc->maximum = pvr2_ctrl_get_cnt(cptr) - 1;
638 vc->step = 1;
639 break;
Mike Isely33213962006-06-25 20:04:40 -0300640 case pvr2_ctl_bool:
Mike Isely1d9f8462006-06-25 20:04:58 -0300641 vc->type = V4L2_CTRL_TYPE_BOOLEAN;
Mike Isely33213962006-06-25 20:04:40 -0300642 vc->minimum = 0;
643 vc->maximum = 1;
644 vc->step = 1;
645 break;
Mike Iselyd8554972006-06-26 20:58:46 -0300646 case pvr2_ctl_int:
647 vc->type = V4L2_CTRL_TYPE_INTEGER;
648 vc->minimum = pvr2_ctrl_get_min(cptr);
649 vc->maximum = pvr2_ctrl_get_max(cptr);
650 vc->step = 1;
651 break;
652 default:
Mike Isely0885ba12006-06-25 21:30:47 -0300653 pvr2_trace(PVR2_TRACE_V4LIOCTL,
Mike Iselya761f432006-06-25 20:04:44 -0300654 "QUERYCTRL id=0x%x name=%s not mappable",
655 vc->id,pvr2_ctrl_get_name(cptr));
Mike Iselyd8554972006-06-26 20:58:46 -0300656 ret = -EINVAL;
657 break;
658 }
659 break;
660 }
661
662 case VIDIOC_QUERYMENU:
663 {
664 struct v4l2_querymenu *vm = (struct v4l2_querymenu *)arg;
665 unsigned int cnt = 0;
666 ret = pvr2_ctrl_get_valname(pvr2_hdw_get_ctrl_v4l(hdw,vm->id),
667 vm->index,
668 vm->name,sizeof(vm->name)-1,
669 &cnt);
670 vm->name[cnt] = 0;
671 break;
672 }
673
674 case VIDIOC_G_CTRL:
675 {
676 struct v4l2_control *vc = (struct v4l2_control *)arg;
677 int val = 0;
678 ret = pvr2_ctrl_get_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id),
679 &val);
680 vc->value = val;
681 break;
682 }
683
684 case VIDIOC_S_CTRL:
685 {
686 struct v4l2_control *vc = (struct v4l2_control *)arg;
687 ret = pvr2_ctrl_set_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id),
688 vc->value);
689 break;
690 }
691
Mike Isely1d9f8462006-06-25 20:04:58 -0300692 case VIDIOC_G_EXT_CTRLS:
693 {
694 struct v4l2_ext_controls *ctls =
695 (struct v4l2_ext_controls *)arg;
696 struct v4l2_ext_control *ctrl;
697 unsigned int idx;
698 int val;
Mike Iselyc1c26802007-01-20 00:30:23 -0300699 ret = 0;
Mike Isely1d9f8462006-06-25 20:04:58 -0300700 for (idx = 0; idx < ctls->count; idx++) {
701 ctrl = ctls->controls + idx;
702 ret = pvr2_ctrl_get_value(
703 pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),&val);
704 if (ret) {
705 ctls->error_idx = idx;
706 break;
707 }
708 /* Ensure that if read as a 64 bit value, the user
709 will still get a hopefully sane value */
710 ctrl->value64 = 0;
711 ctrl->value = val;
712 }
713 break;
714 }
715
716 case VIDIOC_S_EXT_CTRLS:
717 {
718 struct v4l2_ext_controls *ctls =
719 (struct v4l2_ext_controls *)arg;
720 struct v4l2_ext_control *ctrl;
721 unsigned int idx;
Mike Iselyc1c26802007-01-20 00:30:23 -0300722 ret = 0;
Mike Isely1d9f8462006-06-25 20:04:58 -0300723 for (idx = 0; idx < ctls->count; idx++) {
724 ctrl = ctls->controls + idx;
725 ret = pvr2_ctrl_set_value(
726 pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),
727 ctrl->value);
728 if (ret) {
729 ctls->error_idx = idx;
730 break;
731 }
732 }
733 break;
734 }
735
736 case VIDIOC_TRY_EXT_CTRLS:
737 {
738 struct v4l2_ext_controls *ctls =
739 (struct v4l2_ext_controls *)arg;
740 struct v4l2_ext_control *ctrl;
741 struct pvr2_ctrl *pctl;
742 unsigned int idx;
743 /* For the moment just validate that the requested control
744 actually exists. */
Mike Iselyc1c26802007-01-20 00:30:23 -0300745 ret = 0;
Mike Isely1d9f8462006-06-25 20:04:58 -0300746 for (idx = 0; idx < ctls->count; idx++) {
747 ctrl = ctls->controls + idx;
748 pctl = pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id);
749 if (!pctl) {
750 ret = -EINVAL;
751 ctls->error_idx = idx;
752 break;
753 }
754 }
755 break;
756 }
757
Mike Isely432907f2008-08-31 21:02:20 -0300758 case VIDIOC_CROPCAP:
759 {
760 struct v4l2_cropcap *cap = (struct v4l2_cropcap *)arg;
761 if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
762 ret = -EINVAL;
763 break;
764 }
765 ret = pvr2_hdw_get_cropcap(hdw, cap);
766 cap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* paranoia */
767 break;
768 }
769 case VIDIOC_G_CROP:
770 {
771 struct v4l2_crop *crop = (struct v4l2_crop *)arg;
772 int val = 0;
773 if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
774 ret = -EINVAL;
775 break;
776 }
777 ret = pvr2_ctrl_get_value(
778 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL), &val);
779 if (ret != 0) {
780 ret = -EINVAL;
781 break;
782 }
783 crop->c.left = val;
784 ret = pvr2_ctrl_get_value(
785 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT), &val);
786 if (ret != 0) {
787 ret = -EINVAL;
788 break;
789 }
790 crop->c.top = val;
791 ret = pvr2_ctrl_get_value(
792 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW), &val);
793 if (ret != 0) {
794 ret = -EINVAL;
795 break;
796 }
797 crop->c.width = val;
798 ret = pvr2_ctrl_get_value(
799 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH), &val);
800 if (ret != 0) {
801 ret = -EINVAL;
802 break;
803 }
804 crop->c.height = val;
805 }
806 case VIDIOC_S_CROP:
807 {
808 struct v4l2_crop *crop = (struct v4l2_crop *)arg;
809 struct v4l2_cropcap cap;
810 if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
811 ret = -EINVAL;
812 break;
813 }
814 cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
815 ret = pvr2_ctrl_set_value(
816 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL),
817 crop->c.left);
818 if (ret != 0) {
819 ret = -EINVAL;
820 break;
821 }
822 ret = pvr2_ctrl_set_value(
823 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT),
824 crop->c.top);
825 if (ret != 0) {
826 ret = -EINVAL;
827 break;
828 }
829 ret = pvr2_ctrl_set_value(
830 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW),
831 crop->c.width);
832 if (ret != 0) {
833 ret = -EINVAL;
834 break;
835 }
836 ret = pvr2_ctrl_set_value(
837 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH),
838 crop->c.height);
839 if (ret != 0) {
840 ret = -EINVAL;
841 break;
842 }
843 }
Mike Iselyd8554972006-06-26 20:58:46 -0300844 case VIDIOC_LOG_STATUS:
845 {
Mike Iselyd8554972006-06-26 20:58:46 -0300846 pvr2_hdw_trigger_module_log(hdw);
Mike Iselyd8554972006-06-26 20:58:46 -0300847 ret = 0;
848 break;
849 }
Mike Isely32ffa9a2006-09-23 22:26:52 -0300850#ifdef CONFIG_VIDEO_ADV_DEBUG
Trent Piepho52ebc762007-01-23 22:38:13 -0300851 case VIDIOC_DBG_S_REGISTER:
Trent Piepho52ebc762007-01-23 22:38:13 -0300852 case VIDIOC_DBG_G_REGISTER:
Mike Isely32ffa9a2006-09-23 22:26:52 -0300853 {
Hans Verkuilf3d092b2007-02-23 20:55:14 -0300854 u64 val;
Mike Isely32ffa9a2006-09-23 22:26:52 -0300855 struct v4l2_register *req = (struct v4l2_register *)arg;
Trent Piepho52ebc762007-01-23 22:38:13 -0300856 if (cmd == VIDIOC_DBG_S_REGISTER) val = req->val;
Mike Isely32ffa9a2006-09-23 22:26:52 -0300857 ret = pvr2_hdw_register_access(
Hans Verkuilf3d092b2007-02-23 20:55:14 -0300858 hdw,req->match_type,req->match_chip,req->reg,
Trent Piepho52ebc762007-01-23 22:38:13 -0300859 cmd == VIDIOC_DBG_S_REGISTER,&val);
860 if (cmd == VIDIOC_DBG_G_REGISTER) req->val = val;
Mike Isely32ffa9a2006-09-23 22:26:52 -0300861 break;
862 }
863#endif
Mike Iselyd8554972006-06-26 20:58:46 -0300864
865 default :
Mauro Carvalho Chehabb1f88402008-10-21 11:27:20 -0300866 ret = v4l_compat_translate_ioctl(file, cmd,
867 arg, __pvr2_v4l2_do_ioctl);
Mike Iselyd8554972006-06-26 20:58:46 -0300868 }
869
870 pvr2_hdw_commit_ctl(hdw);
871
872 if (ret < 0) {
873 if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
Mike Isely0885ba12006-06-25 21:30:47 -0300874 pvr2_trace(PVR2_TRACE_V4LIOCTL,
Mike Iselyd8554972006-06-26 20:58:46 -0300875 "pvr2_v4l2_do_ioctl failure, ret=%d",ret);
876 } else {
Mike Isely0885ba12006-06-25 21:30:47 -0300877 if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
878 pvr2_trace(PVR2_TRACE_V4LIOCTL,
Mike Iselyd8554972006-06-26 20:58:46 -0300879 "pvr2_v4l2_do_ioctl failure, ret=%d"
880 " command was:",ret);
881 v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),
882 cmd);
883 }
884 }
885 } else {
886 pvr2_trace(PVR2_TRACE_V4LIOCTL,
887 "pvr2_v4l2_do_ioctl complete, ret=%d (0x%x)",
888 ret,ret);
889 }
890 return ret;
891}
892
Mauro Carvalho Chehabb1f88402008-10-21 11:27:20 -0300893static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
894 unsigned int cmd, void *arg)
895{
896 return __pvr2_v4l2_do_ioctl(file, cmd, arg);
897}
Mike Iselyd8554972006-06-26 20:58:46 -0300898
899static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
900{
Hans Verkuilc6330fb2008-10-19 18:54:26 -0300901 int num = dip->devbase.num;
Mike Isely0f0f2572006-12-27 23:19:42 -0300902 struct pvr2_hdw *hdw = dip->v4lp->channel.mc_head->hdw;
Mike Isely16eb40d2006-12-30 18:27:32 -0300903 enum pvr2_config cfg = dip->config;
904 int v4l_type = dip->v4l_type;
Mike Isely0f0f2572006-12-27 23:19:42 -0300905
Mike Isely16eb40d2006-12-30 18:27:32 -0300906 pvr2_hdw_v4l_store_minor_number(hdw,dip->minor_type,-1);
Mike Isely75910052006-09-23 22:30:50 -0300907
908 /* Paranoia */
Randy Dunlapc2625bf2006-10-29 11:12:27 -0300909 dip->v4lp = NULL;
910 dip->stream = NULL;
Mike Isely75910052006-09-23 22:30:50 -0300911
912 /* Actual deallocation happens later when all internal references
913 are gone. */
914 video_unregister_device(&dip->devbase);
Mike Isely0f0f2572006-12-27 23:19:42 -0300915
Mike Isely16eb40d2006-12-30 18:27:32 -0300916 printk(KERN_INFO "pvrusb2: unregistered device %s%u [%s]\n",
Hans Verkuilc6330fb2008-10-19 18:54:26 -0300917 get_v4l_name(v4l_type), num,
Mike Isely16eb40d2006-12-30 18:27:32 -0300918 pvr2_config_get_name(cfg));
Mike Isely0f0f2572006-12-27 23:19:42 -0300919
Mike Iselyd8554972006-06-26 20:58:46 -0300920}
921
922
923static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp)
924{
Mike Isely0f0f2572006-12-27 23:19:42 -0300925 if (vp->dev_video) {
926 pvr2_v4l2_dev_destroy(vp->dev_video);
Al Viro89952d12007-03-14 09:17:59 +0000927 vp->dev_video = NULL;
Mike Isely0f0f2572006-12-27 23:19:42 -0300928 }
929 if (vp->dev_radio) {
930 pvr2_v4l2_dev_destroy(vp->dev_radio);
Al Viro89952d12007-03-14 09:17:59 +0000931 vp->dev_radio = NULL;
Mike Isely0f0f2572006-12-27 23:19:42 -0300932 }
Mike Iselyd8554972006-06-26 20:58:46 -0300933
934 pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp);
935 pvr2_channel_done(&vp->channel);
936 kfree(vp);
937}
938
939
Mike Isely75910052006-09-23 22:30:50 -0300940static void pvr2_video_device_release(struct video_device *vdev)
941{
942 struct pvr2_v4l2_dev *dev;
943 dev = container_of(vdev,struct pvr2_v4l2_dev,devbase);
944 kfree(dev);
945}
946
947
Adrian Bunk07e337e2006-06-30 11:30:20 -0300948static void pvr2_v4l2_internal_check(struct pvr2_channel *chp)
Mike Iselyd8554972006-06-26 20:58:46 -0300949{
950 struct pvr2_v4l2 *vp;
951 vp = container_of(chp,struct pvr2_v4l2,channel);
952 if (!vp->channel.mc_head->disconnect_flag) return;
953 if (vp->vfirst) return;
954 pvr2_v4l2_destroy_no_lock(vp);
955}
956
957
Adrian Bunk07e337e2006-06-30 11:30:20 -0300958static int pvr2_v4l2_ioctl(struct inode *inode, struct file *file,
959 unsigned int cmd, unsigned long arg)
Mike Iselyd8554972006-06-26 20:58:46 -0300960{
961
962/* Temporary hack : use ivtv api until a v4l2 one is available. */
963#define IVTV_IOC_G_CODEC 0xFFEE7703
964#define IVTV_IOC_S_CODEC 0xFFEE7704
965 if (cmd == IVTV_IOC_G_CODEC || cmd == IVTV_IOC_S_CODEC) return 0;
966 return video_usercopy(inode, file, cmd, arg, pvr2_v4l2_do_ioctl);
967}
968
969
Adrian Bunk07e337e2006-06-30 11:30:20 -0300970static int pvr2_v4l2_release(struct inode *inode, struct file *file)
Mike Iselyd8554972006-06-26 20:58:46 -0300971{
972 struct pvr2_v4l2_fh *fhp = file->private_data;
973 struct pvr2_v4l2 *vp = fhp->vhead;
Mike Iselyc74e0062006-12-30 18:31:22 -0300974 struct pvr2_hdw *hdw = fhp->channel.mc_head->hdw;
Mike Iselyd8554972006-06-26 20:58:46 -0300975
976 pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_release");
977
978 if (fhp->rhp) {
979 struct pvr2_stream *sp;
Mike Iselyd8554972006-06-26 20:58:46 -0300980 pvr2_hdw_set_streaming(hdw,0);
981 sp = pvr2_ioread_get_stream(fhp->rhp);
Mike Iselya0fd1cb2006-06-30 11:35:28 -0300982 if (sp) pvr2_stream_set_callback(sp,NULL,NULL);
Mike Iselyd8554972006-06-26 20:58:46 -0300983 pvr2_ioread_destroy(fhp->rhp);
Mike Iselya0fd1cb2006-06-30 11:35:28 -0300984 fhp->rhp = NULL;
Mike Iselyd8554972006-06-26 20:58:46 -0300985 }
Pantelis Koukousoulasae2b9e22006-12-27 23:09:55 -0300986
Mike Iselyd8554972006-06-26 20:58:46 -0300987 v4l2_prio_close(&vp->prio, &fhp->prio);
988 file->private_data = NULL;
989
Mike Isely794b1602008-04-22 14:45:45 -0300990 if (fhp->vnext) {
991 fhp->vnext->vprev = fhp->vprev;
992 } else {
993 vp->vlast = fhp->vprev;
994 }
995 if (fhp->vprev) {
996 fhp->vprev->vnext = fhp->vnext;
997 } else {
998 vp->vfirst = fhp->vnext;
999 }
1000 fhp->vnext = NULL;
1001 fhp->vprev = NULL;
1002 fhp->vhead = NULL;
1003 pvr2_channel_done(&fhp->channel);
1004 pvr2_trace(PVR2_TRACE_STRUCT,
1005 "Destroying pvr_v4l2_fh id=%p",fhp);
Mike Iselye57b1c82008-04-21 03:52:34 -03001006 if (fhp->input_map) {
1007 kfree(fhp->input_map);
1008 fhp->input_map = NULL;
1009 }
Mike Isely794b1602008-04-22 14:45:45 -03001010 kfree(fhp);
1011 if (vp->channel.mc_head->disconnect_flag && !vp->vfirst) {
1012 pvr2_v4l2_destroy_no_lock(vp);
1013 }
Mike Iselyd8554972006-06-26 20:58:46 -03001014 return 0;
1015}
1016
1017
Adrian Bunk07e337e2006-06-30 11:30:20 -03001018static int pvr2_v4l2_open(struct inode *inode, struct file *file)
Mike Iselyd8554972006-06-26 20:58:46 -03001019{
Mike Isely75910052006-09-23 22:30:50 -03001020 struct pvr2_v4l2_dev *dip; /* Our own context pointer */
Mike Iselyd8554972006-06-26 20:58:46 -03001021 struct pvr2_v4l2_fh *fhp;
1022 struct pvr2_v4l2 *vp;
1023 struct pvr2_hdw *hdw;
Mike Isely1cb03b72008-04-21 03:47:43 -03001024 unsigned int input_mask = 0;
Mike Iselye57b1c82008-04-21 03:52:34 -03001025 unsigned int input_cnt,idx;
Mike Isely1cb03b72008-04-21 03:47:43 -03001026 int ret = 0;
Mike Iselyd8554972006-06-26 20:58:46 -03001027
Mike Isely75910052006-09-23 22:30:50 -03001028 dip = container_of(video_devdata(file),struct pvr2_v4l2_dev,devbase);
Mike Iselyd8554972006-06-26 20:58:46 -03001029
1030 vp = dip->v4lp;
1031 hdw = vp->channel.hdw;
1032
1033 pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_open");
1034
1035 if (!pvr2_hdw_dev_ok(hdw)) {
1036 pvr2_trace(PVR2_TRACE_OPEN_CLOSE,
1037 "pvr2_v4l2_open: hardware not ready");
1038 return -EIO;
1039 }
1040
Mike Isely4b85dee2007-01-20 00:03:32 -03001041 fhp = kzalloc(sizeof(*fhp),GFP_KERNEL);
Mike Iselyd8554972006-06-26 20:58:46 -03001042 if (!fhp) {
1043 return -ENOMEM;
1044 }
Mike Iselyd8554972006-06-26 20:58:46 -03001045
1046 init_waitqueue_head(&fhp->wait_data);
1047 fhp->dev_info = dip;
1048
Mike Isely794b1602008-04-22 14:45:45 -03001049 pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp);
1050 pvr2_channel_init(&fhp->channel,vp->channel.mc_head);
Pantelis Koukousoulasae2b9e22006-12-27 23:09:55 -03001051
Mike Isely1cb03b72008-04-21 03:47:43 -03001052 if (dip->v4l_type == VFL_TYPE_RADIO) {
1053 /* Opening device as a radio, legal input selection subset
1054 is just the radio. */
1055 input_mask = (1 << PVR2_CVAL_INPUT_RADIO);
1056 } else {
1057 /* Opening the main V4L device, legal input selection
1058 subset includes all analog inputs. */
1059 input_mask = ((1 << PVR2_CVAL_INPUT_RADIO) |
1060 (1 << PVR2_CVAL_INPUT_TV) |
1061 (1 << PVR2_CVAL_INPUT_COMPOSITE) |
1062 (1 << PVR2_CVAL_INPUT_SVIDEO));
1063 }
1064 ret = pvr2_channel_limit_inputs(&fhp->channel,input_mask);
1065 if (ret) {
1066 pvr2_channel_done(&fhp->channel);
1067 pvr2_trace(PVR2_TRACE_STRUCT,
1068 "Destroying pvr_v4l2_fh id=%p (input mask error)",
1069 fhp);
1070
1071 kfree(fhp);
1072 return ret;
1073 }
1074
Mike Iselye57b1c82008-04-21 03:52:34 -03001075 input_mask &= pvr2_hdw_get_input_available(hdw);
1076 input_cnt = 0;
1077 for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) {
1078 if (input_mask & (1 << idx)) input_cnt++;
1079 }
1080 fhp->input_cnt = input_cnt;
1081 fhp->input_map = kzalloc(input_cnt,GFP_KERNEL);
1082 if (!fhp->input_map) {
1083 pvr2_channel_done(&fhp->channel);
1084 pvr2_trace(PVR2_TRACE_STRUCT,
1085 "Destroying pvr_v4l2_fh id=%p (input map failure)",
1086 fhp);
1087 kfree(fhp);
1088 return -ENOMEM;
1089 }
1090 input_cnt = 0;
1091 for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) {
1092 if (!(input_mask & (1 << idx))) continue;
1093 fhp->input_map[input_cnt++] = idx;
1094 }
1095
Mike Isely794b1602008-04-22 14:45:45 -03001096 fhp->vnext = NULL;
1097 fhp->vprev = vp->vlast;
1098 if (vp->vlast) {
1099 vp->vlast->vnext = fhp;
1100 } else {
1101 vp->vfirst = fhp;
1102 }
1103 vp->vlast = fhp;
1104 fhp->vhead = vp;
Mike Iselyc74e0062006-12-30 18:31:22 -03001105
Mike Iselyd8554972006-06-26 20:58:46 -03001106 fhp->file = file;
1107 file->private_data = fhp;
1108 v4l2_prio_open(&vp->prio,&fhp->prio);
1109
1110 fhp->fw_mode_flag = pvr2_hdw_cpufw_get_enabled(hdw);
1111
1112 return 0;
1113}
1114
1115
1116static void pvr2_v4l2_notify(struct pvr2_v4l2_fh *fhp)
1117{
1118 wake_up(&fhp->wait_data);
1119}
1120
1121static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh)
1122{
1123 int ret;
1124 struct pvr2_stream *sp;
1125 struct pvr2_hdw *hdw;
1126 if (fh->rhp) return 0;
1127
Mike Isely16eb40d2006-12-30 18:27:32 -03001128 if (!fh->dev_info->stream) {
1129 /* No stream defined for this node. This means that we're
1130 not currently allowed to stream from this node. */
1131 return -EPERM;
1132 }
1133
Mike Iselyd8554972006-06-26 20:58:46 -03001134 /* First read() attempt. Try to claim the stream and start
1135 it... */
1136 if ((ret = pvr2_channel_claim_stream(&fh->channel,
1137 fh->dev_info->stream)) != 0) {
1138 /* Someone else must already have it */
1139 return ret;
1140 }
1141
1142 fh->rhp = pvr2_channel_create_mpeg_stream(fh->dev_info->stream);
1143 if (!fh->rhp) {
Mike Iselya0fd1cb2006-06-30 11:35:28 -03001144 pvr2_channel_claim_stream(&fh->channel,NULL);
Mike Iselyd8554972006-06-26 20:58:46 -03001145 return -ENOMEM;
1146 }
1147
1148 hdw = fh->channel.mc_head->hdw;
1149 sp = fh->dev_info->stream->stream;
1150 pvr2_stream_set_callback(sp,(pvr2_stream_callback)pvr2_v4l2_notify,fh);
1151 pvr2_hdw_set_stream_type(hdw,fh->dev_info->config);
Mike Isely681c7392007-11-26 01:48:52 -03001152 if ((ret = pvr2_hdw_set_streaming(hdw,!0)) < 0) return ret;
1153 return pvr2_ioread_set_enabled(fh->rhp,!0);
Mike Iselyd8554972006-06-26 20:58:46 -03001154}
1155
1156
1157static ssize_t pvr2_v4l2_read(struct file *file,
1158 char __user *buff, size_t count, loff_t *ppos)
1159{
1160 struct pvr2_v4l2_fh *fh = file->private_data;
1161 int ret;
1162
1163 if (fh->fw_mode_flag) {
1164 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
1165 char *tbuf;
1166 int c1,c2;
1167 int tcnt = 0;
1168 unsigned int offs = *ppos;
1169
1170 tbuf = kmalloc(PAGE_SIZE,GFP_KERNEL);
1171 if (!tbuf) return -ENOMEM;
1172
1173 while (count) {
1174 c1 = count;
1175 if (c1 > PAGE_SIZE) c1 = PAGE_SIZE;
1176 c2 = pvr2_hdw_cpufw_get(hdw,offs,tbuf,c1);
1177 if (c2 < 0) {
1178 tcnt = c2;
1179 break;
1180 }
1181 if (!c2) break;
1182 if (copy_to_user(buff,tbuf,c2)) {
1183 tcnt = -EFAULT;
1184 break;
1185 }
1186 offs += c2;
1187 tcnt += c2;
1188 buff += c2;
1189 count -= c2;
1190 *ppos += c2;
1191 }
1192 kfree(tbuf);
1193 return tcnt;
1194 }
1195
1196 if (!fh->rhp) {
1197 ret = pvr2_v4l2_iosetup(fh);
1198 if (ret) {
1199 return ret;
1200 }
1201 }
1202
1203 for (;;) {
1204 ret = pvr2_ioread_read(fh->rhp,buff,count);
1205 if (ret >= 0) break;
1206 if (ret != -EAGAIN) break;
1207 if (file->f_flags & O_NONBLOCK) break;
1208 /* Doing blocking I/O. Wait here. */
1209 ret = wait_event_interruptible(
1210 fh->wait_data,
1211 pvr2_ioread_avail(fh->rhp) >= 0);
1212 if (ret < 0) break;
1213 }
1214
1215 return ret;
1216}
1217
1218
1219static unsigned int pvr2_v4l2_poll(struct file *file, poll_table *wait)
1220{
1221 unsigned int mask = 0;
1222 struct pvr2_v4l2_fh *fh = file->private_data;
1223 int ret;
1224
1225 if (fh->fw_mode_flag) {
1226 mask |= POLLIN | POLLRDNORM;
1227 return mask;
1228 }
1229
1230 if (!fh->rhp) {
1231 ret = pvr2_v4l2_iosetup(fh);
1232 if (ret) return POLLERR;
1233 }
1234
1235 poll_wait(file,&fh->wait_data,wait);
1236
1237 if (pvr2_ioread_avail(fh->rhp) >= 0) {
1238 mask |= POLLIN | POLLRDNORM;
1239 }
1240
1241 return mask;
1242}
1243
1244
Arjan van de Venfa027c22007-02-12 00:55:33 -08001245static const struct file_operations vdev_fops = {
Mike Iselyd8554972006-06-26 20:58:46 -03001246 .owner = THIS_MODULE,
1247 .open = pvr2_v4l2_open,
1248 .release = pvr2_v4l2_release,
1249 .read = pvr2_v4l2_read,
1250 .ioctl = pvr2_v4l2_ioctl,
1251 .llseek = no_llseek,
1252 .poll = pvr2_v4l2_poll,
1253};
1254
1255
Mike Iselyd8554972006-06-26 20:58:46 -03001256static struct video_device vdev_template = {
Mike Iselyd8554972006-06-26 20:58:46 -03001257 .fops = &vdev_fops,
1258};
1259
1260
1261static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
1262 struct pvr2_v4l2 *vp,
Mike Isely16eb40d2006-12-30 18:27:32 -03001263 int v4l_type)
Mike Iselyd8554972006-06-26 20:58:46 -03001264{
1265 int mindevnum;
1266 int unit_number;
Al Viro89952d12007-03-14 09:17:59 +00001267 int *nr_ptr = NULL;
Mike Iselyd8554972006-06-26 20:58:46 -03001268 dip->v4lp = vp;
Mike Iselyd8554972006-06-26 20:58:46 -03001269
1270
Mike Isely16eb40d2006-12-30 18:27:32 -03001271 dip->v4l_type = v4l_type;
1272 switch (v4l_type) {
1273 case VFL_TYPE_GRABBER:
Mike Iselyd8554972006-06-26 20:58:46 -03001274 dip->stream = &vp->channel.mc_head->video_stream;
Mike Isely16eb40d2006-12-30 18:27:32 -03001275 dip->config = pvr2_config_mpeg;
1276 dip->minor_type = pvr2_v4l_type_video;
1277 nr_ptr = video_nr;
Mike Iselyc74e0062006-12-30 18:31:22 -03001278 if (!dip->stream) {
1279 err("Failed to set up pvrusb2 v4l video dev"
1280 " due to missing stream instance");
1281 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) */
1297 err("Failed to set up pvrusb2 v4l dev"
1298 " due to unrecognized config");
1299 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 Isely16eb40d2006-12-30 18:27:32 -03001310 if ((video_register_device(&dip->devbase,
1311 dip->v4l_type, mindevnum) < 0) &&
1312 (video_register_device(&dip->devbase,
1313 dip->v4l_type, -1) < 0)) {
Pantelis Koukousoulasae2b9e22006-12-27 23:09:55 -03001314 err("Failed to register pvrusb2 v4l device");
1315 }
Mike Isely16eb40d2006-12-30 18:27:32 -03001316
1317 printk(KERN_INFO "pvrusb2: registered device %s%u [%s]\n",
Hans Verkuilc6330fb2008-10-19 18:54:26 -03001318 get_v4l_name(dip->v4l_type), dip->devbase.num,
Mike Isely16eb40d2006-12-30 18:27:32 -03001319 pvr2_config_get_name(dip->config));
Mike Iselyd8554972006-06-26 20:58:46 -03001320
Mike Iselyd8554972006-06-26 20:58:46 -03001321 pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,
Mike Isely16eb40d2006-12-30 18:27:32 -03001322 dip->minor_type,dip->devbase.minor);
Mike Iselyd8554972006-06-26 20:58:46 -03001323}
1324
1325
1326struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
1327{
1328 struct pvr2_v4l2 *vp;
1329
Mike Isely4b85dee2007-01-20 00:03:32 -03001330 vp = kzalloc(sizeof(*vp),GFP_KERNEL);
Mike Iselyd8554972006-06-26 20:58:46 -03001331 if (!vp) return vp;
Mike Iselyd8554972006-06-26 20:58:46 -03001332 pvr2_channel_init(&vp->channel,mnp);
1333 pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp);
1334
1335 vp->channel.check_func = pvr2_v4l2_internal_check;
1336
1337 /* register streams */
Mike Iselybeb0ecd2008-04-22 14:45:38 -03001338 vp->dev_video = kzalloc(sizeof(*vp->dev_video),GFP_KERNEL);
1339 if (!vp->dev_video) goto fail;
Mike Isely16eb40d2006-12-30 18:27:32 -03001340 pvr2_v4l2_dev_init(vp->dev_video,vp,VFL_TYPE_GRABBER);
Mike Iselye57b1c82008-04-21 03:52:34 -03001341 if (pvr2_hdw_get_input_available(vp->channel.mc_head->hdw) &
1342 (1 << PVR2_CVAL_INPUT_RADIO)) {
Mike Iselybeb0ecd2008-04-22 14:45:38 -03001343 vp->dev_radio = kzalloc(sizeof(*vp->dev_radio),GFP_KERNEL);
1344 if (!vp->dev_radio) goto fail;
1345 pvr2_v4l2_dev_init(vp->dev_radio,vp,VFL_TYPE_RADIO);
1346 }
Mike Iselyd8554972006-06-26 20:58:46 -03001347
1348 return vp;
Mike Iselybeb0ecd2008-04-22 14:45:38 -03001349 fail:
1350 pvr2_trace(PVR2_TRACE_STRUCT,"Failure creating pvr2_v4l2 id=%p",vp);
1351 pvr2_v4l2_destroy_no_lock(vp);
Harvey Harrisona6a3a172008-04-28 16:50:03 -07001352 return NULL;
Mike Iselyd8554972006-06-26 20:58:46 -03001353}
1354
1355/*
1356 Stuff for Emacs to see, in order to encourage consistent editing style:
1357 *** Local Variables: ***
1358 *** mode: c ***
1359 *** fill-column: 75 ***
1360 *** tab-width: 8 ***
1361 *** c-basic-offset: 8 ***
1362 *** End: ***
1363 */