blob: 6aa48e0ae7312cb0324844099175bc8dc001fc9e [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
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 */
Hans Verkuil069b7472008-12-30 07:04:34 -0300171static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
Mike Iselyd8554972006-06-26 20:58:46 -0300172{
173 struct pvr2_v4l2_fh *fh = file->private_data;
174 struct pvr2_v4l2 *vp = fh->vhead;
175 struct pvr2_v4l2_dev *dev_info = fh->dev_info;
176 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
Hans Verkuil069b7472008-12-30 07:04:34 -0300177 long ret = -EINVAL;
Mike Iselyd8554972006-06-26 20:58:46 -0300178
179 if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
180 v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),cmd);
181 }
182
183 if (!pvr2_hdw_dev_ok(hdw)) {
184 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
185 "ioctl failed - bad or no context");
186 return -EFAULT;
187 }
188
189 /* check priority */
190 switch (cmd) {
191 case VIDIOC_S_CTRL:
192 case VIDIOC_S_STD:
193 case VIDIOC_S_INPUT:
194 case VIDIOC_S_TUNER:
195 case VIDIOC_S_FREQUENCY:
196 ret = v4l2_prio_check(&vp->prio, &fh->prio);
197 if (ret)
198 return ret;
199 }
200
201 switch (cmd) {
202 case VIDIOC_QUERYCAP:
203 {
204 struct v4l2_capability *cap = arg;
205
206 memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
Mike Isely31a18542007-04-08 01:11:47 -0300207 strlcpy(cap->bus_info,pvr2_hdw_get_bus_info(hdw),
208 sizeof(cap->bus_info));
Mike Isely78a47102007-11-26 01:58:20 -0300209 strlcpy(cap->card,pvr2_hdw_get_desc(hdw),sizeof(cap->card));
Mike Iselyd8554972006-06-26 20:58:46 -0300210
211 ret = 0;
212 break;
213 }
214
215 case VIDIOC_G_PRIORITY:
216 {
217 enum v4l2_priority *p = arg;
218
219 *p = v4l2_prio_max(&vp->prio);
220 ret = 0;
221 break;
222 }
223
224 case VIDIOC_S_PRIORITY:
225 {
226 enum v4l2_priority *prio = arg;
227
228 ret = v4l2_prio_change(&vp->prio, &fh->prio, *prio);
229 break;
230 }
231
232 case VIDIOC_ENUMSTD:
233 {
234 struct v4l2_standard *vs = (struct v4l2_standard *)arg;
235 int idx = vs->index;
236 ret = pvr2_hdw_get_stdenum_value(hdw,vs,idx+1);
237 break;
238 }
239
240 case VIDIOC_G_STD:
241 {
242 int val = 0;
243 ret = pvr2_ctrl_get_value(
244 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR),&val);
245 *(v4l2_std_id *)arg = val;
246 break;
247 }
248
249 case VIDIOC_S_STD:
250 {
251 ret = pvr2_ctrl_set_value(
252 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR),
253 *(v4l2_std_id *)arg);
254 break;
255 }
256
257 case VIDIOC_ENUMINPUT:
258 {
259 struct pvr2_ctrl *cptr;
260 struct v4l2_input *vi = (struct v4l2_input *)arg;
261 struct v4l2_input tmp;
262 unsigned int cnt;
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300263 int val;
Mike Iselyd8554972006-06-26 20:58:46 -0300264
265 cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
266
267 memset(&tmp,0,sizeof(tmp));
268 tmp.index = vi->index;
269 ret = 0;
Roel Kluin223ffe52009-05-02 16:38:47 -0300270 if (vi->index >= fh->input_cnt) {
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300271 ret = -EINVAL;
272 break;
273 }
Mike Iselye57b1c82008-04-21 03:52:34 -0300274 val = fh->input_map[vi->index];
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300275 switch (val) {
Mike Iselyd8554972006-06-26 20:58:46 -0300276 case PVR2_CVAL_INPUT_TV:
Mike Isely895c3e82008-04-22 14:45:37 -0300277 case PVR2_CVAL_INPUT_DTV:
Mike Iselyd8554972006-06-26 20:58:46 -0300278 case PVR2_CVAL_INPUT_RADIO:
279 tmp.type = V4L2_INPUT_TYPE_TUNER;
280 break;
281 case PVR2_CVAL_INPUT_SVIDEO:
282 case PVR2_CVAL_INPUT_COMPOSITE:
283 tmp.type = V4L2_INPUT_TYPE_CAMERA;
284 break;
285 default:
286 ret = -EINVAL;
287 break;
288 }
289 if (ret < 0) break;
290
291 cnt = 0;
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300292 pvr2_ctrl_get_valname(cptr,val,
Mike Iselyd8554972006-06-26 20:58:46 -0300293 tmp.name,sizeof(tmp.name)-1,&cnt);
294 tmp.name[cnt] = 0;
295
296 /* Don't bother with audioset, since this driver currently
297 always switches the audio whenever the video is
298 switched. */
299
300 /* Handling std is a tougher problem. It doesn't make
301 sense in cases where a device might be multi-standard.
302 We could just copy out the current value for the
303 standard, but it can change over time. For now just
304 leave it zero. */
305
306 memcpy(vi, &tmp, sizeof(tmp));
307
308 ret = 0;
309 break;
310 }
311
312 case VIDIOC_G_INPUT:
313 {
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300314 unsigned int idx;
Mike Iselyd8554972006-06-26 20:58:46 -0300315 struct pvr2_ctrl *cptr;
316 struct v4l2_input *vi = (struct v4l2_input *)arg;
317 int val;
318 cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
319 val = 0;
320 ret = pvr2_ctrl_get_value(cptr,&val);
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300321 vi->index = 0;
Mike Iselye57b1c82008-04-21 03:52:34 -0300322 for (idx = 0; idx < fh->input_cnt; idx++) {
323 if (fh->input_map[idx] == val) {
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300324 vi->index = idx;
325 break;
326 }
327 }
Mike Iselyd8554972006-06-26 20:58:46 -0300328 break;
329 }
330
331 case VIDIOC_S_INPUT:
332 {
333 struct v4l2_input *vi = (struct v4l2_input *)arg;
Roel Kluin223ffe52009-05-02 16:38:47 -0300334 if (vi->index >= fh->input_cnt) {
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300335 ret = -ERANGE;
336 break;
337 }
Mike Iselyd8554972006-06-26 20:58:46 -0300338 ret = pvr2_ctrl_set_value(
339 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
Mike Iselye57b1c82008-04-21 03:52:34 -0300340 fh->input_map[vi->index]);
Mike Iselyd8554972006-06-26 20:58:46 -0300341 break;
342 }
343
344 case VIDIOC_ENUMAUDIO:
345 {
Pantelis Koukousoulas848ed3c2007-01-20 01:57:36 -0300346 /* pkt: FIXME: We are returning one "fake" input here
347 which could very well be called "whatever_we_like".
348 This is for apps that want to see an audio input
349 just to feel comfortable, as well as to test if
350 it can do stereo or sth. There is actually no guarantee
351 that the actual audio input cannot change behind the app's
352 back, but most applications should not mind that either.
353
354 Hopefully, mplayer people will work with us on this (this
355 whole mess is to support mplayer pvr://), or Hans will come
356 up with a more standard way to say "we have inputs but we
357 don 't want you to change them independent of video" which
358 will sort this mess.
359 */
360 struct v4l2_audio *vin = arg;
Mike Iselyd8554972006-06-26 20:58:46 -0300361 ret = -EINVAL;
Pantelis Koukousoulas848ed3c2007-01-20 01:57:36 -0300362 if (vin->index > 0) break;
363 strncpy(vin->name, "PVRUSB2 Audio",14);
364 vin->capability = V4L2_AUDCAP_STEREO;
365 ret = 0;
366 break;
Mike Iselyd8554972006-06-26 20:58:46 -0300367 break;
368 }
369
370 case VIDIOC_G_AUDIO:
371 {
Pantelis Koukousoulas848ed3c2007-01-20 01:57:36 -0300372 /* pkt: FIXME: see above comment (VIDIOC_ENUMAUDIO) */
373 struct v4l2_audio *vin = arg;
374 memset(vin,0,sizeof(*vin));
375 vin->index = 0;
376 strncpy(vin->name, "PVRUSB2 Audio",14);
377 vin->capability = V4L2_AUDCAP_STEREO;
378 ret = 0;
Mike Iselyd8554972006-06-26 20:58:46 -0300379 break;
380 }
381
382 case VIDIOC_S_AUDIO:
383 {
384 ret = -EINVAL;
385 break;
386 }
387 case VIDIOC_G_TUNER:
388 {
389 struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
Mauro Carvalho Chehab5cc1dd82007-01-21 22:02:58 -0300390
Michael Krufky8d364362007-01-22 02:17:55 -0300391 if (vt->index != 0) break; /* Only answer for the 1st tuner */
Mauro Carvalho Chehab5cc1dd82007-01-21 22:02:58 -0300392
Mike Isely18103c572007-01-20 00:09:47 -0300393 pvr2_hdw_execute_tuner_poll(hdw);
394 ret = pvr2_hdw_get_tuner_status(hdw,vt);
Mike Iselyd8554972006-06-26 20:58:46 -0300395 break;
396 }
397
398 case VIDIOC_S_TUNER:
399 {
400 struct v4l2_tuner *vt=(struct v4l2_tuner *)arg;
401
402 if (vt->index != 0)
403 break;
404
405 ret = pvr2_ctrl_set_value(
406 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE),
407 vt->audmode);
Mike Isely11fc76c2007-01-20 00:24:52 -0300408 break;
Mike Iselyd8554972006-06-26 20:58:46 -0300409 }
410
411 case VIDIOC_S_FREQUENCY:
412 {
413 const struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
Mike Iselyc0e69312006-12-27 23:25:06 -0300414 unsigned long fv;
Mike Isely18103c572007-01-20 00:09:47 -0300415 struct v4l2_tuner vt;
416 int cur_input;
417 struct pvr2_ctrl *ctrlp;
418 ret = pvr2_hdw_get_tuner_status(hdw,&vt);
419 if (ret != 0) break;
420 ctrlp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
421 ret = pvr2_ctrl_get_value(ctrlp,&cur_input);
422 if (ret != 0) break;
Mike Iselyc0e69312006-12-27 23:25:06 -0300423 if (vf->type == V4L2_TUNER_RADIO) {
Mike Isely18103c572007-01-20 00:09:47 -0300424 if (cur_input != PVR2_CVAL_INPUT_RADIO) {
425 pvr2_ctrl_set_value(ctrlp,
426 PVR2_CVAL_INPUT_RADIO);
427 }
428 } else {
429 if (cur_input == PVR2_CVAL_INPUT_RADIO) {
430 pvr2_ctrl_set_value(ctrlp,
431 PVR2_CVAL_INPUT_TV);
432 }
433 }
434 fv = vf->frequency;
435 if (vt.capability & V4L2_TUNER_CAP_LOW) {
Mike Iselyc0e69312006-12-27 23:25:06 -0300436 fv = (fv * 125) / 2;
437 } else {
438 fv = fv * 62500;
439 }
Mike Iselyd8554972006-06-26 20:58:46 -0300440 ret = pvr2_ctrl_set_value(
Mike Iselyc0e69312006-12-27 23:25:06 -0300441 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),fv);
Mike Iselyd8554972006-06-26 20:58:46 -0300442 break;
443 }
444
445 case VIDIOC_G_FREQUENCY:
446 {
447 struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
448 int val = 0;
Mike Isely18103c572007-01-20 00:09:47 -0300449 int cur_input;
450 struct v4l2_tuner vt;
451 ret = pvr2_hdw_get_tuner_status(hdw,&vt);
452 if (ret != 0) break;
Mike Iselyd8554972006-06-26 20:58:46 -0300453 ret = pvr2_ctrl_get_value(
454 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),
455 &val);
Mike Iselyc0e69312006-12-27 23:25:06 -0300456 if (ret != 0) break;
457 pvr2_ctrl_get_value(
458 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
459 &cur_input);
460 if (cur_input == PVR2_CVAL_INPUT_RADIO) {
Mike Iselyc0e69312006-12-27 23:25:06 -0300461 vf->type = V4L2_TUNER_RADIO;
462 } else {
Mike Iselyc0e69312006-12-27 23:25:06 -0300463 vf->type = V4L2_TUNER_ANALOG_TV;
464 }
Mike Isely18103c572007-01-20 00:09:47 -0300465 if (vt.capability & V4L2_TUNER_CAP_LOW) {
466 val = (val * 2) / 125;
467 } else {
468 val /= 62500;
469 }
470 vf->frequency = val;
Mike Iselyd8554972006-06-26 20:58:46 -0300471 break;
472 }
473
474 case VIDIOC_ENUM_FMT:
475 {
476 struct v4l2_fmtdesc *fd = (struct v4l2_fmtdesc *)arg;
477
478 /* Only one format is supported : mpeg.*/
479 if (fd->index != 0)
480 break;
481
482 memcpy(fd, pvr_fmtdesc, sizeof(struct v4l2_fmtdesc));
483 ret = 0;
484 break;
485 }
486
487 case VIDIOC_G_FMT:
488 {
489 struct v4l2_format *vf = (struct v4l2_format *)arg;
490 int val;
491 switch(vf->type) {
492 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
493 memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
494 sizeof(struct v4l2_format));
495 val = 0;
496 pvr2_ctrl_get_value(
497 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES),
498 &val);
499 vf->fmt.pix.width = val;
500 val = 0;
501 pvr2_ctrl_get_value(
Mike Iselyd8554972006-06-26 20:58:46 -0300502 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES),
503 &val);
504 vf->fmt.pix.height = val;
505 ret = 0;
506 break;
507 case V4L2_BUF_TYPE_VBI_CAPTURE:
508 // ????? Still need to figure out to do VBI correctly
509 ret = -EINVAL;
510 break;
511 default:
512 ret = -EINVAL;
513 break;
514 }
515 break;
516 }
517
518 case VIDIOC_TRY_FMT:
519 case VIDIOC_S_FMT:
520 {
521 struct v4l2_format *vf = (struct v4l2_format *)arg;
522
523 ret = 0;
524 switch(vf->type) {
525 case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
Pantelis Koukousoulasfd694962007-01-20 01:59:54 -0300526 int lmin,lmax,ldef;
Mike Iselye95a1912006-08-08 09:10:07 -0300527 struct pvr2_ctrl *hcp,*vcp;
Mike Iselyd8554972006-06-26 20:58:46 -0300528 int h = vf->fmt.pix.height;
529 int w = vf->fmt.pix.width;
Mike Iselye95a1912006-08-08 09:10:07 -0300530 hcp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES);
531 vcp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES);
Mike Iselyd8554972006-06-26 20:58:46 -0300532
Mike Iselye95a1912006-08-08 09:10:07 -0300533 lmin = pvr2_ctrl_get_min(hcp);
534 lmax = pvr2_ctrl_get_max(hcp);
Mike Isely26dd1c572008-08-31 20:55:03 -0300535 pvr2_ctrl_get_def(hcp, &ldef);
Pantelis Koukousoulasfd694962007-01-20 01:59:54 -0300536 if (w == -1) {
537 w = ldef;
538 } else if (w < lmin) {
Mike Iselye95a1912006-08-08 09:10:07 -0300539 w = lmin;
540 } else if (w > lmax) {
541 w = lmax;
Mike Isely039c4302006-06-25 20:04:16 -0300542 }
Hans Verkuilb31e3412006-09-01 18:36:10 -0300543 lmin = pvr2_ctrl_get_min(vcp);
544 lmax = pvr2_ctrl_get_max(vcp);
Mike Isely26dd1c572008-08-31 20:55:03 -0300545 pvr2_ctrl_get_def(vcp, &ldef);
Pantelis Koukousoulasfd694962007-01-20 01:59:54 -0300546 if (h == -1) {
547 h = ldef;
548 } else if (h < lmin) {
Hans Verkuilb31e3412006-09-01 18:36:10 -0300549 h = lmin;
550 } else if (h > lmax) {
551 h = lmax;
552 }
Mike Iselyd8554972006-06-26 20:58:46 -0300553
554 memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
555 sizeof(struct v4l2_format));
Mike Isely039c4302006-06-25 20:04:16 -0300556 vf->fmt.pix.width = w;
557 vf->fmt.pix.height = h;
Mike Iselyd8554972006-06-26 20:58:46 -0300558
559 if (cmd == VIDIOC_S_FMT) {
Mike Iselye95a1912006-08-08 09:10:07 -0300560 pvr2_ctrl_set_value(hcp,vf->fmt.pix.width);
561 pvr2_ctrl_set_value(vcp,vf->fmt.pix.height);
Mike Iselyd8554972006-06-26 20:58:46 -0300562 }
563 } break;
564 case V4L2_BUF_TYPE_VBI_CAPTURE:
565 // ????? Still need to figure out to do VBI correctly
566 ret = -EINVAL;
567 break;
568 default:
569 ret = -EINVAL;
570 break;
571 }
572 break;
573 }
574
575 case VIDIOC_STREAMON:
576 {
Mike Isely16eb40d2006-12-30 18:27:32 -0300577 if (!fh->dev_info->stream) {
578 /* No stream defined for this node. This means
579 that we're not currently allowed to stream from
580 this node. */
581 ret = -EPERM;
582 break;
583 }
Mike Iselyd8554972006-06-26 20:58:46 -0300584 ret = pvr2_hdw_set_stream_type(hdw,dev_info->config);
585 if (ret < 0) return ret;
586 ret = pvr2_hdw_set_streaming(hdw,!0);
587 break;
588 }
589
590 case VIDIOC_STREAMOFF:
591 {
Mike Isely16eb40d2006-12-30 18:27:32 -0300592 if (!fh->dev_info->stream) {
593 /* No stream defined for this node. This means
594 that we're not currently allowed to stream from
595 this node. */
596 ret = -EPERM;
597 break;
598 }
Mike Iselyd8554972006-06-26 20:58:46 -0300599 ret = pvr2_hdw_set_streaming(hdw,0);
600 break;
601 }
602
603 case VIDIOC_QUERYCTRL:
604 {
605 struct pvr2_ctrl *cptr;
Mike Isely26dd1c572008-08-31 20:55:03 -0300606 int val;
Mike Iselyd8554972006-06-26 20:58:46 -0300607 struct v4l2_queryctrl *vc = (struct v4l2_queryctrl *)arg;
608 ret = 0;
Mike Isely1d9f8462006-06-25 20:04:58 -0300609 if (vc->id & V4L2_CTRL_FLAG_NEXT_CTRL) {
610 cptr = pvr2_hdw_get_ctrl_nextv4l(
611 hdw,(vc->id & ~V4L2_CTRL_FLAG_NEXT_CTRL));
612 if (cptr) vc->id = pvr2_ctrl_get_v4lid(cptr);
613 } else {
614 cptr = pvr2_hdw_get_ctrl_v4l(hdw,vc->id);
615 }
Mike Iselyd8554972006-06-26 20:58:46 -0300616 if (!cptr) {
Mike Isely0885ba12006-06-25 21:30:47 -0300617 pvr2_trace(PVR2_TRACE_V4LIOCTL,
Mike Iselya761f432006-06-25 20:04:44 -0300618 "QUERYCTRL id=0x%x not implemented here",
619 vc->id);
Mike Iselyd8554972006-06-26 20:58:46 -0300620 ret = -EINVAL;
621 break;
622 }
623
Mike Iselya761f432006-06-25 20:04:44 -0300624 pvr2_trace(PVR2_TRACE_V4LIOCTL,
625 "QUERYCTRL id=0x%x mapping name=%s (%s)",
626 vc->id,pvr2_ctrl_get_name(cptr),
627 pvr2_ctrl_get_desc(cptr));
628 strlcpy(vc->name,pvr2_ctrl_get_desc(cptr),sizeof(vc->name));
629 vc->flags = pvr2_ctrl_get_v4lflags(cptr);
Mike Isely26dd1c572008-08-31 20:55:03 -0300630 pvr2_ctrl_get_def(cptr, &val);
631 vc->default_value = val;
Mike Iselyd8554972006-06-26 20:58:46 -0300632 switch (pvr2_ctrl_get_type(cptr)) {
633 case pvr2_ctl_enum:
634 vc->type = V4L2_CTRL_TYPE_MENU;
635 vc->minimum = 0;
636 vc->maximum = pvr2_ctrl_get_cnt(cptr) - 1;
637 vc->step = 1;
638 break;
Mike Isely33213962006-06-25 20:04:40 -0300639 case pvr2_ctl_bool:
Mike Isely1d9f8462006-06-25 20:04:58 -0300640 vc->type = V4L2_CTRL_TYPE_BOOLEAN;
Mike Isely33213962006-06-25 20:04:40 -0300641 vc->minimum = 0;
642 vc->maximum = 1;
643 vc->step = 1;
644 break;
Mike Iselyd8554972006-06-26 20:58:46 -0300645 case pvr2_ctl_int:
646 vc->type = V4L2_CTRL_TYPE_INTEGER;
647 vc->minimum = pvr2_ctrl_get_min(cptr);
648 vc->maximum = pvr2_ctrl_get_max(cptr);
649 vc->step = 1;
650 break;
651 default:
Mike Isely0885ba12006-06-25 21:30:47 -0300652 pvr2_trace(PVR2_TRACE_V4LIOCTL,
Mike Iselya761f432006-06-25 20:04:44 -0300653 "QUERYCTRL id=0x%x name=%s not mappable",
654 vc->id,pvr2_ctrl_get_name(cptr));
Mike Iselyd8554972006-06-26 20:58:46 -0300655 ret = -EINVAL;
656 break;
657 }
658 break;
659 }
660
661 case VIDIOC_QUERYMENU:
662 {
663 struct v4l2_querymenu *vm = (struct v4l2_querymenu *)arg;
664 unsigned int cnt = 0;
665 ret = pvr2_ctrl_get_valname(pvr2_hdw_get_ctrl_v4l(hdw,vm->id),
666 vm->index,
667 vm->name,sizeof(vm->name)-1,
668 &cnt);
669 vm->name[cnt] = 0;
670 break;
671 }
672
673 case VIDIOC_G_CTRL:
674 {
675 struct v4l2_control *vc = (struct v4l2_control *)arg;
676 int val = 0;
677 ret = pvr2_ctrl_get_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id),
678 &val);
679 vc->value = val;
680 break;
681 }
682
683 case VIDIOC_S_CTRL:
684 {
685 struct v4l2_control *vc = (struct v4l2_control *)arg;
686 ret = pvr2_ctrl_set_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id),
687 vc->value);
688 break;
689 }
690
Mike Isely1d9f8462006-06-25 20:04:58 -0300691 case VIDIOC_G_EXT_CTRLS:
692 {
693 struct v4l2_ext_controls *ctls =
694 (struct v4l2_ext_controls *)arg;
695 struct v4l2_ext_control *ctrl;
696 unsigned int idx;
697 int val;
Mike Iselyc1c26802007-01-20 00:30:23 -0300698 ret = 0;
Mike Isely1d9f8462006-06-25 20:04:58 -0300699 for (idx = 0; idx < ctls->count; idx++) {
700 ctrl = ctls->controls + idx;
701 ret = pvr2_ctrl_get_value(
702 pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),&val);
703 if (ret) {
704 ctls->error_idx = idx;
705 break;
706 }
707 /* Ensure that if read as a 64 bit value, the user
708 will still get a hopefully sane value */
709 ctrl->value64 = 0;
710 ctrl->value = val;
711 }
712 break;
713 }
714
715 case VIDIOC_S_EXT_CTRLS:
716 {
717 struct v4l2_ext_controls *ctls =
718 (struct v4l2_ext_controls *)arg;
719 struct v4l2_ext_control *ctrl;
720 unsigned int idx;
Mike Iselyc1c26802007-01-20 00:30:23 -0300721 ret = 0;
Mike Isely1d9f8462006-06-25 20:04:58 -0300722 for (idx = 0; idx < ctls->count; idx++) {
723 ctrl = ctls->controls + idx;
724 ret = pvr2_ctrl_set_value(
725 pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),
726 ctrl->value);
727 if (ret) {
728 ctls->error_idx = idx;
729 break;
730 }
731 }
732 break;
733 }
734
735 case VIDIOC_TRY_EXT_CTRLS:
736 {
737 struct v4l2_ext_controls *ctls =
738 (struct v4l2_ext_controls *)arg;
739 struct v4l2_ext_control *ctrl;
740 struct pvr2_ctrl *pctl;
741 unsigned int idx;
742 /* For the moment just validate that the requested control
743 actually exists. */
Mike Iselyc1c26802007-01-20 00:30:23 -0300744 ret = 0;
Mike Isely1d9f8462006-06-25 20:04:58 -0300745 for (idx = 0; idx < ctls->count; idx++) {
746 ctrl = ctls->controls + idx;
747 pctl = pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id);
748 if (!pctl) {
749 ret = -EINVAL;
750 ctls->error_idx = idx;
751 break;
752 }
753 }
754 break;
755 }
756
Mike Isely432907f2008-08-31 21:02:20 -0300757 case VIDIOC_CROPCAP:
758 {
759 struct v4l2_cropcap *cap = (struct v4l2_cropcap *)arg;
760 if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
761 ret = -EINVAL;
762 break;
763 }
764 ret = pvr2_hdw_get_cropcap(hdw, cap);
765 cap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* paranoia */
766 break;
767 }
768 case VIDIOC_G_CROP:
769 {
770 struct v4l2_crop *crop = (struct v4l2_crop *)arg;
771 int val = 0;
772 if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
773 ret = -EINVAL;
774 break;
775 }
776 ret = pvr2_ctrl_get_value(
777 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL), &val);
778 if (ret != 0) {
779 ret = -EINVAL;
780 break;
781 }
782 crop->c.left = val;
783 ret = pvr2_ctrl_get_value(
784 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT), &val);
785 if (ret != 0) {
786 ret = -EINVAL;
787 break;
788 }
789 crop->c.top = val;
790 ret = pvr2_ctrl_get_value(
791 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW), &val);
792 if (ret != 0) {
793 ret = -EINVAL;
794 break;
795 }
796 crop->c.width = val;
797 ret = pvr2_ctrl_get_value(
798 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH), &val);
799 if (ret != 0) {
800 ret = -EINVAL;
801 break;
802 }
803 crop->c.height = val;
804 }
805 case VIDIOC_S_CROP:
806 {
807 struct v4l2_crop *crop = (struct v4l2_crop *)arg;
808 struct v4l2_cropcap cap;
809 if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
810 ret = -EINVAL;
811 break;
812 }
813 cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
814 ret = pvr2_ctrl_set_value(
815 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL),
816 crop->c.left);
817 if (ret != 0) {
818 ret = -EINVAL;
819 break;
820 }
821 ret = pvr2_ctrl_set_value(
822 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT),
823 crop->c.top);
824 if (ret != 0) {
825 ret = -EINVAL;
826 break;
827 }
828 ret = pvr2_ctrl_set_value(
829 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW),
830 crop->c.width);
831 if (ret != 0) {
832 ret = -EINVAL;
833 break;
834 }
835 ret = pvr2_ctrl_set_value(
836 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH),
837 crop->c.height);
838 if (ret != 0) {
839 ret = -EINVAL;
840 break;
841 }
842 }
Mike Iselyd8554972006-06-26 20:58:46 -0300843 case VIDIOC_LOG_STATUS:
844 {
Mike Iselyd8554972006-06-26 20:58:46 -0300845 pvr2_hdw_trigger_module_log(hdw);
Mike Iselyd8554972006-06-26 20:58:46 -0300846 ret = 0;
847 break;
848 }
Mike Isely32ffa9a2006-09-23 22:26:52 -0300849#ifdef CONFIG_VIDEO_ADV_DEBUG
Trent Piepho52ebc762007-01-23 22:38:13 -0300850 case VIDIOC_DBG_S_REGISTER:
Trent Piepho52ebc762007-01-23 22:38:13 -0300851 case VIDIOC_DBG_G_REGISTER:
Mike Isely32ffa9a2006-09-23 22:26:52 -0300852 {
Hans Verkuilf3d092b2007-02-23 20:55:14 -0300853 u64 val;
Hans Verkuilaecde8b52008-12-30 07:14:19 -0300854 struct v4l2_dbg_register *req = (struct v4l2_dbg_register *)arg;
Trent Piepho52ebc762007-01-23 22:38:13 -0300855 if (cmd == VIDIOC_DBG_S_REGISTER) val = req->val;
Mike Isely32ffa9a2006-09-23 22:26:52 -0300856 ret = pvr2_hdw_register_access(
Hans Verkuilaecde8b52008-12-30 07:14:19 -0300857 hdw, &req->match, req->reg,
858 cmd == VIDIOC_DBG_S_REGISTER, &val);
Trent Piepho52ebc762007-01-23 22:38:13 -0300859 if (cmd == VIDIOC_DBG_G_REGISTER) req->val = val;
Mike Isely32ffa9a2006-09-23 22:26:52 -0300860 break;
861 }
862#endif
Mike Iselyd8554972006-06-26 20:58:46 -0300863
864 default :
Mauro Carvalho Chehabb1f88402008-10-21 11:27:20 -0300865 ret = v4l_compat_translate_ioctl(file, cmd,
Hans Verkuilf473bf72008-11-01 08:25:11 -0300866 arg, pvr2_v4l2_do_ioctl);
Mike Iselyd8554972006-06-26 20:58:46 -0300867 }
868
869 pvr2_hdw_commit_ctl(hdw);
870
871 if (ret < 0) {
872 if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
Mike Isely0885ba12006-06-25 21:30:47 -0300873 pvr2_trace(PVR2_TRACE_V4LIOCTL,
Hans Verkuil069b7472008-12-30 07:04:34 -0300874 "pvr2_v4l2_do_ioctl failure, ret=%ld", ret);
Mike Iselyd8554972006-06-26 20:58:46 -0300875 } else {
Mike Isely0885ba12006-06-25 21:30:47 -0300876 if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
877 pvr2_trace(PVR2_TRACE_V4LIOCTL,
Hans Verkuil069b7472008-12-30 07:04:34 -0300878 "pvr2_v4l2_do_ioctl failure, ret=%ld"
879 " command was:", ret);
Mike Iselyd8554972006-06-26 20:58:46 -0300880 v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),
881 cmd);
882 }
883 }
884 } else {
885 pvr2_trace(PVR2_TRACE_V4LIOCTL,
Hans Verkuil069b7472008-12-30 07:04:34 -0300886 "pvr2_v4l2_do_ioctl complete, ret=%ld (0x%lx)",
887 ret, ret);
Mike Iselyd8554972006-06-26 20:58:46 -0300888 }
889 return ret;
890}
891
Mike Iselyd8554972006-06-26 20:58:46 -0300892static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
893{
Hans Verkuilc6330fb2008-10-19 18:54:26 -0300894 int num = dip->devbase.num;
Mike Isely0f0f2572006-12-27 23:19:42 -0300895 struct pvr2_hdw *hdw = dip->v4lp->channel.mc_head->hdw;
Mike Isely16eb40d2006-12-30 18:27:32 -0300896 enum pvr2_config cfg = dip->config;
897 int v4l_type = dip->v4l_type;
Mike Isely0f0f2572006-12-27 23:19:42 -0300898
Mike Isely16eb40d2006-12-30 18:27:32 -0300899 pvr2_hdw_v4l_store_minor_number(hdw,dip->minor_type,-1);
Mike Isely75910052006-09-23 22:30:50 -0300900
901 /* Paranoia */
Randy Dunlapc2625bf2006-10-29 11:12:27 -0300902 dip->v4lp = NULL;
903 dip->stream = NULL;
Mike Isely75910052006-09-23 22:30:50 -0300904
905 /* Actual deallocation happens later when all internal references
906 are gone. */
907 video_unregister_device(&dip->devbase);
Mike Isely0f0f2572006-12-27 23:19:42 -0300908
Mike Isely16eb40d2006-12-30 18:27:32 -0300909 printk(KERN_INFO "pvrusb2: unregistered device %s%u [%s]\n",
Hans Verkuilc6330fb2008-10-19 18:54:26 -0300910 get_v4l_name(v4l_type), num,
Mike Isely16eb40d2006-12-30 18:27:32 -0300911 pvr2_config_get_name(cfg));
Mike Isely0f0f2572006-12-27 23:19:42 -0300912
Mike Iselyd8554972006-06-26 20:58:46 -0300913}
914
915
Mike Isely4a89baa2009-10-12 00:13:28 -0300916static void pvr2_v4l2_dev_disassociate_parent(struct pvr2_v4l2_dev *dip)
917{
918 if (!dip) return;
919 if (!dip->devbase.parent) return;
920 dip->devbase.parent = NULL;
921 device_move(&dip->devbase.dev, NULL, DPM_ORDER_NONE);
922}
923
924
Mike Iselyd8554972006-06-26 20:58:46 -0300925static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp)
926{
Mike Isely0f0f2572006-12-27 23:19:42 -0300927 if (vp->dev_video) {
928 pvr2_v4l2_dev_destroy(vp->dev_video);
Al Viro89952d12007-03-14 09:17:59 +0000929 vp->dev_video = NULL;
Mike Isely0f0f2572006-12-27 23:19:42 -0300930 }
931 if (vp->dev_radio) {
932 pvr2_v4l2_dev_destroy(vp->dev_radio);
Al Viro89952d12007-03-14 09:17:59 +0000933 vp->dev_radio = NULL;
Mike Isely0f0f2572006-12-27 23:19:42 -0300934 }
Mike Iselyd8554972006-06-26 20:58:46 -0300935
936 pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp);
937 pvr2_channel_done(&vp->channel);
938 kfree(vp);
939}
940
941
Mike Isely75910052006-09-23 22:30:50 -0300942static void pvr2_video_device_release(struct video_device *vdev)
943{
944 struct pvr2_v4l2_dev *dev;
945 dev = container_of(vdev,struct pvr2_v4l2_dev,devbase);
946 kfree(dev);
947}
948
949
Adrian Bunk07e337e2006-06-30 11:30:20 -0300950static void pvr2_v4l2_internal_check(struct pvr2_channel *chp)
Mike Iselyd8554972006-06-26 20:58:46 -0300951{
952 struct pvr2_v4l2 *vp;
953 vp = container_of(chp,struct pvr2_v4l2,channel);
954 if (!vp->channel.mc_head->disconnect_flag) return;
Mike Isely4a89baa2009-10-12 00:13:28 -0300955 pvr2_v4l2_dev_disassociate_parent(vp->dev_video);
956 pvr2_v4l2_dev_disassociate_parent(vp->dev_radio);
Mike Iselyd8554972006-06-26 20:58:46 -0300957 if (vp->vfirst) return;
958 pvr2_v4l2_destroy_no_lock(vp);
959}
960
961
Hans Verkuil069b7472008-12-30 07:04:34 -0300962static long pvr2_v4l2_ioctl(struct file *file,
Adrian Bunk07e337e2006-06-30 11:30:20 -0300963 unsigned int cmd, unsigned long arg)
Mike Iselyd8554972006-06-26 20:58:46 -0300964{
965
Hans Verkuilf473bf72008-11-01 08:25:11 -0300966 return video_usercopy(file, cmd, arg, pvr2_v4l2_do_ioctl);
Mike Iselyd8554972006-06-26 20:58:46 -0300967}
968
969
Hans Verkuilbec43662008-12-30 06:58:20 -0300970static int pvr2_v4l2_release(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
Hans Verkuilbec43662008-12-30 06:58:20 -03001018static int pvr2_v4l2_open(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
Hans Verkuilbec43662008-12-30 06:58:20 -03001245static const struct v4l2_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,
Mike Iselyd8554972006-06-26 20:58:46 -03001251 .poll = pvr2_v4l2_poll,
1252};
1253
1254
Mike Iselyd8554972006-06-26 20:58:46 -03001255static struct video_device vdev_template = {
Mike Iselyd8554972006-06-26 20:58:46 -03001256 .fops = &vdev_fops,
1257};
1258
1259
1260static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
1261 struct pvr2_v4l2 *vp,
Mike Isely16eb40d2006-12-30 18:27:32 -03001262 int v4l_type)
Mike Iselyd8554972006-06-26 20:58:46 -03001263{
Mike Isely4a89baa2009-10-12 00:13:28 -03001264 struct usb_device *usbdev;
Mike Iselyd8554972006-06-26 20:58:46 -03001265 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
Mike Isely4a89baa2009-10-12 00:13:28 -03001270 usbdev = pvr2_hdw_get_dev(vp->channel.mc_head->hdw);
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) {
Mauro Carvalho Chehabbe9ed512009-01-08 09:13:42 -03001279 pr_err(KBUILD_MODNAME
1280 ": Failed to set up pvrusb2 v4l video dev"
1281 " due to missing stream instance\n");
Mike Iselyc74e0062006-12-30 18:31:22 -03001282 return;
1283 }
Mike Iselyd8554972006-06-26 20:58:46 -03001284 break;
Mike Isely16eb40d2006-12-30 18:27:32 -03001285 case VFL_TYPE_VBI:
1286 dip->config = pvr2_config_vbi;
1287 dip->minor_type = pvr2_v4l_type_vbi;
1288 nr_ptr = vbi_nr;
Mike Iselyd8554972006-06-26 20:58:46 -03001289 break;
Mike Isely16eb40d2006-12-30 18:27:32 -03001290 case VFL_TYPE_RADIO:
Mike Iselyaf78a482007-01-20 00:04:31 -03001291 dip->stream = &vp->channel.mc_head->video_stream;
1292 dip->config = pvr2_config_mpeg;
Mike Isely16eb40d2006-12-30 18:27:32 -03001293 dip->minor_type = pvr2_v4l_type_radio;
1294 nr_ptr = radio_nr;
Mike Iselyd8554972006-06-26 20:58:46 -03001295 break;
1296 default:
1297 /* Bail out (this should be impossible) */
Mauro Carvalho Chehabbe9ed512009-01-08 09:13:42 -03001298 pr_err(KBUILD_MODNAME ": Failed to set up pvrusb2 v4l dev"
1299 " due to unrecognized config\n");
Mike Iselyd8554972006-06-26 20:58:46 -03001300 return;
1301 }
1302
Mike Isely75910052006-09-23 22:30:50 -03001303 memcpy(&dip->devbase,&vdev_template,sizeof(vdev_template));
1304 dip->devbase.release = pvr2_video_device_release;
Mike Iselyd8554972006-06-26 20:58:46 -03001305
1306 mindevnum = -1;
1307 unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw);
Mike Isely16eb40d2006-12-30 18:27:32 -03001308 if (nr_ptr && (unit_number >= 0) && (unit_number < PVR_NUM)) {
1309 mindevnum = nr_ptr[unit_number];
Mike Iselyd8554972006-06-26 20:58:46 -03001310 }
Mike Isely4a89baa2009-10-12 00:13:28 -03001311 dip->devbase.parent = &usbdev->dev;
Mike Isely16eb40d2006-12-30 18:27:32 -03001312 if ((video_register_device(&dip->devbase,
1313 dip->v4l_type, mindevnum) < 0) &&
1314 (video_register_device(&dip->devbase,
1315 dip->v4l_type, -1) < 0)) {
Mauro Carvalho Chehabbe9ed512009-01-08 09:13:42 -03001316 pr_err(KBUILD_MODNAME
1317 ": Failed to register pvrusb2 v4l device\n");
Pantelis Koukousoulasae2b9e22006-12-27 23:09:55 -03001318 }
Mike Isely16eb40d2006-12-30 18:27:32 -03001319
1320 printk(KERN_INFO "pvrusb2: registered device %s%u [%s]\n",
Hans Verkuilc6330fb2008-10-19 18:54:26 -03001321 get_v4l_name(dip->v4l_type), dip->devbase.num,
Mike Isely16eb40d2006-12-30 18:27:32 -03001322 pvr2_config_get_name(dip->config));
Mike Iselyd8554972006-06-26 20:58:46 -03001323
Mike Iselyd8554972006-06-26 20:58:46 -03001324 pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,
Mike Isely16eb40d2006-12-30 18:27:32 -03001325 dip->minor_type,dip->devbase.minor);
Mike Iselyd8554972006-06-26 20:58:46 -03001326}
1327
1328
1329struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
1330{
1331 struct pvr2_v4l2 *vp;
1332
Mike Isely4b85dee2007-01-20 00:03:32 -03001333 vp = kzalloc(sizeof(*vp),GFP_KERNEL);
Mike Iselyd8554972006-06-26 20:58:46 -03001334 if (!vp) return vp;
Mike Iselyd8554972006-06-26 20:58:46 -03001335 pvr2_channel_init(&vp->channel,mnp);
1336 pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp);
1337
1338 vp->channel.check_func = pvr2_v4l2_internal_check;
1339
1340 /* register streams */
Mike Iselybeb0ecd2008-04-22 14:45:38 -03001341 vp->dev_video = kzalloc(sizeof(*vp->dev_video),GFP_KERNEL);
1342 if (!vp->dev_video) goto fail;
Mike Isely16eb40d2006-12-30 18:27:32 -03001343 pvr2_v4l2_dev_init(vp->dev_video,vp,VFL_TYPE_GRABBER);
Mike Iselye57b1c82008-04-21 03:52:34 -03001344 if (pvr2_hdw_get_input_available(vp->channel.mc_head->hdw) &
1345 (1 << PVR2_CVAL_INPUT_RADIO)) {
Mike Iselybeb0ecd2008-04-22 14:45:38 -03001346 vp->dev_radio = kzalloc(sizeof(*vp->dev_radio),GFP_KERNEL);
1347 if (!vp->dev_radio) goto fail;
1348 pvr2_v4l2_dev_init(vp->dev_radio,vp,VFL_TYPE_RADIO);
1349 }
Mike Iselyd8554972006-06-26 20:58:46 -03001350
1351 return vp;
Mike Iselybeb0ecd2008-04-22 14:45:38 -03001352 fail:
1353 pvr2_trace(PVR2_TRACE_STRUCT,"Failure creating pvr2_v4l2 id=%p",vp);
1354 pvr2_v4l2_destroy_no_lock(vp);
Harvey Harrisona6a3a172008-04-28 16:50:03 -07001355 return NULL;
Mike Iselyd8554972006-06-26 20:58:46 -03001356}
1357
1358/*
1359 Stuff for Emacs to see, in order to encourage consistent editing style:
1360 *** Local Variables: ***
1361 *** mode: c ***
1362 *** fill-column: 75 ***
1363 *** tab-width: 8 ***
1364 *** c-basic-offset: 8 ***
1365 *** End: ***
1366 */