blob: e27f8ab76966ccdebd9f1a11338b0006ea759a84 [file] [log] [blame]
Mike Iselyd8554972006-06-26 20:58:46 -03001/*
2 *
Mike Iselyd8554972006-06-26 20:58:46 -03003 *
4 * Copyright (C) 2005 Mike Isely <isely@pobox.com>
5 * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <linux/kernel.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090023#include <linux/slab.h>
Mauro Carvalho Chehabce4260c2006-06-26 22:26:08 -030024#include <linux/version.h>
Mike Iselyd8554972006-06-26 20:58:46 -030025#include "pvrusb2-context.h"
26#include "pvrusb2-hdw.h"
27#include "pvrusb2.h"
28#include "pvrusb2-debug.h"
29#include "pvrusb2-v4l2.h"
30#include "pvrusb2-ioread.h"
31#include <linux/videodev2.h>
Mike Isely43e06022006-09-23 23:47:50 -030032#include <media/v4l2-dev.h>
Mike Iselyd8554972006-06-26 20:58:46 -030033#include <media/v4l2-common.h>
Hans Verkuil35ea11f2008-07-20 08:12:02 -030034#include <media/v4l2-ioctl.h>
Mike Iselyd8554972006-06-26 20:58:46 -030035
36struct pvr2_v4l2_dev;
37struct pvr2_v4l2_fh;
38struct pvr2_v4l2;
39
Mike Iselyd8554972006-06-26 20:58:46 -030040struct pvr2_v4l2_dev {
Mike Isely75910052006-09-23 22:30:50 -030041 struct video_device devbase; /* MUST be first! */
Mike Iselyd8554972006-06-26 20:58:46 -030042 struct pvr2_v4l2 *v4lp;
Mike Iselyd8554972006-06-26 20:58:46 -030043 struct pvr2_context_stream *stream;
Mike Isely16eb40d2006-12-30 18:27:32 -030044 /* Information about this device: */
45 enum pvr2_config config; /* Expected stream format */
46 int v4l_type; /* V4L defined type for this device node */
47 enum pvr2_v4l_type minor_type; /* pvr2-understood minor device type */
Mike Iselyd8554972006-06-26 20:58:46 -030048};
49
50struct pvr2_v4l2_fh {
51 struct pvr2_channel channel;
Joe Perches108bdd72010-04-05 16:05:39 -030052 struct pvr2_v4l2_dev *pdi;
Mike Iselyd8554972006-06-26 20:58:46 -030053 enum v4l2_priority prio;
54 struct pvr2_ioread *rhp;
55 struct file *file;
56 struct pvr2_v4l2 *vhead;
57 struct pvr2_v4l2_fh *vnext;
58 struct pvr2_v4l2_fh *vprev;
59 wait_queue_head_t wait_data;
60 int fw_mode_flag;
Mike Iselye57b1c82008-04-21 03:52:34 -030061 /* Map contiguous ordinal value to input id */
62 unsigned char *input_map;
63 unsigned int input_cnt;
Mike Iselyd8554972006-06-26 20:58:46 -030064};
65
66struct pvr2_v4l2 {
67 struct pvr2_channel channel;
68 struct pvr2_v4l2_fh *vfirst;
69 struct pvr2_v4l2_fh *vlast;
70
71 struct v4l2_prio_state prio;
72
Mike Isely0f0f257b2006-12-27 23:19:42 -030073 /* streams - Note that these must be separately, individually,
74 * allocated pointers. This is because the v4l core is going to
75 * manage their deletion - separately, individually... */
76 struct pvr2_v4l2_dev *dev_video;
77 struct pvr2_v4l2_dev *dev_radio;
Mike Iselyd8554972006-06-26 20:58:46 -030078};
79
80static int video_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
81module_param_array(video_nr, int, NULL, 0444);
Mike Isely5e6862c2006-12-27 23:17:26 -030082MODULE_PARM_DESC(video_nr, "Offset for device's video dev minor");
83static int radio_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
84module_param_array(radio_nr, int, NULL, 0444);
85MODULE_PARM_DESC(radio_nr, "Offset for device's radio dev minor");
86static int vbi_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
87module_param_array(vbi_nr, int, NULL, 0444);
88MODULE_PARM_DESC(vbi_nr, "Offset for device's vbi dev minor");
Mike Iselyd8554972006-06-26 20:58:46 -030089
Adrian Bunk07e337e2006-06-30 11:30:20 -030090static struct v4l2_capability pvr_capability ={
Mike Iselyd8554972006-06-26 20:58:46 -030091 .driver = "pvrusb2",
92 .card = "Hauppauge WinTV pvr-usb2",
93 .bus_info = "usb",
Mauro Carvalho Chehab083774d2011-06-25 13:34:24 -030094 .version = LINUX_VERSION_CODE,
Mike Iselyd166b022009-01-14 04:21:29 -030095 .capabilities = (V4L2_CAP_VIDEO_CAPTURE |
Pantelis Koukousoulasae2b9e22006-12-27 23:09:55 -030096 V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
Mike Iselyd8554972006-06-26 20:58:46 -030097 V4L2_CAP_READWRITE),
98 .reserved = {0,0,0,0}
99};
100
Adrian Bunk07e337e2006-06-30 11:30:20 -0300101static struct v4l2_fmtdesc pvr_fmtdesc [] = {
Mike Iselyd8554972006-06-26 20:58:46 -0300102 {
103 .index = 0,
104 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
105 .flags = V4L2_FMT_FLAG_COMPRESSED,
106 .description = "MPEG1/2",
107 // This should really be V4L2_PIX_FMT_MPEG, but xawtv
108 // breaks when I do that.
109 .pixelformat = 0, // V4L2_PIX_FMT_MPEG,
110 .reserved = { 0, 0, 0, 0 }
111 }
112};
113
114#define PVR_FORMAT_PIX 0
115#define PVR_FORMAT_VBI 1
116
Adrian Bunk07e337e2006-06-30 11:30:20 -0300117static struct v4l2_format pvr_format [] = {
Mike Iselyd8554972006-06-26 20:58:46 -0300118 [PVR_FORMAT_PIX] = {
119 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
120 .fmt = {
121 .pix = {
122 .width = 720,
123 .height = 576,
124 // This should really be V4L2_PIX_FMT_MPEG,
125 // but xawtv breaks when I do that.
126 .pixelformat = 0, // V4L2_PIX_FMT_MPEG,
127 .field = V4L2_FIELD_INTERLACED,
128 .bytesperline = 0, // doesn't make sense
129 // here
130 //FIXME : Don't know what to put here...
131 .sizeimage = (32*1024),
132 .colorspace = 0, // doesn't make sense here
133 .priv = 0
134 }
135 }
136 },
137 [PVR_FORMAT_VBI] = {
138 .type = V4L2_BUF_TYPE_VBI_CAPTURE,
139 .fmt = {
140 .vbi = {
141 .sampling_rate = 27000000,
142 .offset = 248,
143 .samples_per_line = 1443,
144 .sample_format = V4L2_PIX_FMT_GREY,
145 .start = { 0, 0 },
146 .count = { 0, 0 },
147 .flags = 0,
148 .reserved = { 0, 0 }
149 }
150 }
151 }
152};
153
Mike Isely16eb40d2006-12-30 18:27:32 -0300154
Mike Iselyd8554972006-06-26 20:58:46 -0300155/*
156 * pvr_ioctl()
157 *
158 * This is part of Video 4 Linux API. The procedure handles ioctl() calls.
159 *
160 */
Hans Verkuil069b7472008-12-30 07:04:34 -0300161static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
Mike Iselyd8554972006-06-26 20:58:46 -0300162{
163 struct pvr2_v4l2_fh *fh = file->private_data;
164 struct pvr2_v4l2 *vp = fh->vhead;
Joe Perches108bdd72010-04-05 16:05:39 -0300165 struct pvr2_v4l2_dev *pdi = fh->pdi;
Mike Iselyd8554972006-06-26 20:58:46 -0300166 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
Hans Verkuil069b7472008-12-30 07:04:34 -0300167 long ret = -EINVAL;
Mike Iselyd8554972006-06-26 20:58:46 -0300168
169 if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
170 v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),cmd);
171 }
172
173 if (!pvr2_hdw_dev_ok(hdw)) {
174 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
175 "ioctl failed - bad or no context");
176 return -EFAULT;
177 }
178
179 /* check priority */
180 switch (cmd) {
181 case VIDIOC_S_CTRL:
182 case VIDIOC_S_STD:
183 case VIDIOC_S_INPUT:
184 case VIDIOC_S_TUNER:
185 case VIDIOC_S_FREQUENCY:
Hans Verkuilffb48772010-05-01 08:03:24 -0300186 ret = v4l2_prio_check(&vp->prio, fh->prio);
Mike Iselyd8554972006-06-26 20:58:46 -0300187 if (ret)
188 return ret;
189 }
190
191 switch (cmd) {
192 case VIDIOC_QUERYCAP:
193 {
194 struct v4l2_capability *cap = arg;
195
196 memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
Mike Isely31a18542007-04-08 01:11:47 -0300197 strlcpy(cap->bus_info,pvr2_hdw_get_bus_info(hdw),
198 sizeof(cap->bus_info));
Mike Isely78a47102007-11-26 01:58:20 -0300199 strlcpy(cap->card,pvr2_hdw_get_desc(hdw),sizeof(cap->card));
Mike Iselyd8554972006-06-26 20:58:46 -0300200
201 ret = 0;
202 break;
203 }
204
205 case VIDIOC_G_PRIORITY:
206 {
207 enum v4l2_priority *p = arg;
208
209 *p = v4l2_prio_max(&vp->prio);
210 ret = 0;
211 break;
212 }
213
214 case VIDIOC_S_PRIORITY:
215 {
216 enum v4l2_priority *prio = arg;
217
218 ret = v4l2_prio_change(&vp->prio, &fh->prio, *prio);
219 break;
220 }
221
222 case VIDIOC_ENUMSTD:
223 {
224 struct v4l2_standard *vs = (struct v4l2_standard *)arg;
225 int idx = vs->index;
226 ret = pvr2_hdw_get_stdenum_value(hdw,vs,idx+1);
227 break;
228 }
229
230 case VIDIOC_G_STD:
231 {
232 int val = 0;
233 ret = pvr2_ctrl_get_value(
234 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR),&val);
235 *(v4l2_std_id *)arg = val;
236 break;
237 }
238
239 case VIDIOC_S_STD:
240 {
241 ret = pvr2_ctrl_set_value(
242 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR),
243 *(v4l2_std_id *)arg);
244 break;
245 }
246
247 case VIDIOC_ENUMINPUT:
248 {
249 struct pvr2_ctrl *cptr;
250 struct v4l2_input *vi = (struct v4l2_input *)arg;
251 struct v4l2_input tmp;
252 unsigned int cnt;
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300253 int val;
Mike Iselyd8554972006-06-26 20:58:46 -0300254
255 cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
256
257 memset(&tmp,0,sizeof(tmp));
258 tmp.index = vi->index;
259 ret = 0;
Roel Kluin223ffe52009-05-02 16:38:47 -0300260 if (vi->index >= fh->input_cnt) {
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300261 ret = -EINVAL;
262 break;
263 }
Mike Iselye57b1c82008-04-21 03:52:34 -0300264 val = fh->input_map[vi->index];
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300265 switch (val) {
Mike Iselyd8554972006-06-26 20:58:46 -0300266 case PVR2_CVAL_INPUT_TV:
Mike Isely895c3e82008-04-22 14:45:37 -0300267 case PVR2_CVAL_INPUT_DTV:
Mike Iselyd8554972006-06-26 20:58:46 -0300268 case PVR2_CVAL_INPUT_RADIO:
269 tmp.type = V4L2_INPUT_TYPE_TUNER;
270 break;
271 case PVR2_CVAL_INPUT_SVIDEO:
272 case PVR2_CVAL_INPUT_COMPOSITE:
273 tmp.type = V4L2_INPUT_TYPE_CAMERA;
274 break;
275 default:
276 ret = -EINVAL;
277 break;
278 }
279 if (ret < 0) break;
280
281 cnt = 0;
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300282 pvr2_ctrl_get_valname(cptr,val,
Mike Iselyd8554972006-06-26 20:58:46 -0300283 tmp.name,sizeof(tmp.name)-1,&cnt);
284 tmp.name[cnt] = 0;
285
286 /* Don't bother with audioset, since this driver currently
287 always switches the audio whenever the video is
288 switched. */
289
290 /* Handling std is a tougher problem. It doesn't make
291 sense in cases where a device might be multi-standard.
292 We could just copy out the current value for the
293 standard, but it can change over time. For now just
294 leave it zero. */
295
296 memcpy(vi, &tmp, sizeof(tmp));
297
298 ret = 0;
299 break;
300 }
301
302 case VIDIOC_G_INPUT:
303 {
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300304 unsigned int idx;
Mike Iselyd8554972006-06-26 20:58:46 -0300305 struct pvr2_ctrl *cptr;
306 struct v4l2_input *vi = (struct v4l2_input *)arg;
307 int val;
308 cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
309 val = 0;
310 ret = pvr2_ctrl_get_value(cptr,&val);
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300311 vi->index = 0;
Mike Iselye57b1c82008-04-21 03:52:34 -0300312 for (idx = 0; idx < fh->input_cnt; idx++) {
313 if (fh->input_map[idx] == val) {
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300314 vi->index = idx;
315 break;
316 }
317 }
Mike Iselyd8554972006-06-26 20:58:46 -0300318 break;
319 }
320
321 case VIDIOC_S_INPUT:
322 {
323 struct v4l2_input *vi = (struct v4l2_input *)arg;
Roel Kluin223ffe52009-05-02 16:38:47 -0300324 if (vi->index >= fh->input_cnt) {
Mike Iselybeb0ecd2008-04-22 14:45:38 -0300325 ret = -ERANGE;
326 break;
327 }
Mike Iselyd8554972006-06-26 20:58:46 -0300328 ret = pvr2_ctrl_set_value(
329 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
Mike Iselye57b1c82008-04-21 03:52:34 -0300330 fh->input_map[vi->index]);
Mike Iselyd8554972006-06-26 20:58:46 -0300331 break;
332 }
333
334 case VIDIOC_ENUMAUDIO:
335 {
Pantelis Koukousoulas848ed3c2007-01-20 01:57:36 -0300336 /* pkt: FIXME: We are returning one "fake" input here
337 which could very well be called "whatever_we_like".
338 This is for apps that want to see an audio input
339 just to feel comfortable, as well as to test if
340 it can do stereo or sth. There is actually no guarantee
341 that the actual audio input cannot change behind the app's
342 back, but most applications should not mind that either.
343
344 Hopefully, mplayer people will work with us on this (this
345 whole mess is to support mplayer pvr://), or Hans will come
346 up with a more standard way to say "we have inputs but we
347 don 't want you to change them independent of video" which
348 will sort this mess.
349 */
350 struct v4l2_audio *vin = arg;
Mike Iselyd8554972006-06-26 20:58:46 -0300351 ret = -EINVAL;
Pantelis Koukousoulas848ed3c2007-01-20 01:57:36 -0300352 if (vin->index > 0) break;
353 strncpy(vin->name, "PVRUSB2 Audio",14);
354 vin->capability = V4L2_AUDCAP_STEREO;
355 ret = 0;
356 break;
Mike Iselyd8554972006-06-26 20:58:46 -0300357 break;
358 }
359
360 case VIDIOC_G_AUDIO:
361 {
Pantelis Koukousoulas848ed3c2007-01-20 01:57:36 -0300362 /* pkt: FIXME: see above comment (VIDIOC_ENUMAUDIO) */
363 struct v4l2_audio *vin = arg;
364 memset(vin,0,sizeof(*vin));
365 vin->index = 0;
366 strncpy(vin->name, "PVRUSB2 Audio",14);
367 vin->capability = V4L2_AUDCAP_STEREO;
368 ret = 0;
Mike Iselyd8554972006-06-26 20:58:46 -0300369 break;
370 }
371
Mike Iselyd8554972006-06-26 20:58:46 -0300372 case VIDIOC_G_TUNER:
373 {
374 struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
Mauro Carvalho Chehab5cc1dd82007-01-21 22:02:58 -0300375
Michael Krufky8d364362007-01-22 02:17:55 -0300376 if (vt->index != 0) break; /* Only answer for the 1st tuner */
Mauro Carvalho Chehab5cc1dd82007-01-21 22:02:58 -0300377
Mike Isely18103c572007-01-20 00:09:47 -0300378 pvr2_hdw_execute_tuner_poll(hdw);
379 ret = pvr2_hdw_get_tuner_status(hdw,vt);
Mike Iselyd8554972006-06-26 20:58:46 -0300380 break;
381 }
382
383 case VIDIOC_S_TUNER:
384 {
385 struct v4l2_tuner *vt=(struct v4l2_tuner *)arg;
386
387 if (vt->index != 0)
388 break;
389
390 ret = pvr2_ctrl_set_value(
391 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE),
392 vt->audmode);
Mike Isely11fc76c2007-01-20 00:24:52 -0300393 break;
Mike Iselyd8554972006-06-26 20:58:46 -0300394 }
395
396 case VIDIOC_S_FREQUENCY:
397 {
398 const struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
Mike Iselyc0e69312006-12-27 23:25:06 -0300399 unsigned long fv;
Mike Isely18103c572007-01-20 00:09:47 -0300400 struct v4l2_tuner vt;
401 int cur_input;
402 struct pvr2_ctrl *ctrlp;
403 ret = pvr2_hdw_get_tuner_status(hdw,&vt);
404 if (ret != 0) break;
405 ctrlp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
406 ret = pvr2_ctrl_get_value(ctrlp,&cur_input);
407 if (ret != 0) break;
Mike Iselyc0e69312006-12-27 23:25:06 -0300408 if (vf->type == V4L2_TUNER_RADIO) {
Mike Isely18103c572007-01-20 00:09:47 -0300409 if (cur_input != PVR2_CVAL_INPUT_RADIO) {
410 pvr2_ctrl_set_value(ctrlp,
411 PVR2_CVAL_INPUT_RADIO);
412 }
413 } else {
414 if (cur_input == PVR2_CVAL_INPUT_RADIO) {
415 pvr2_ctrl_set_value(ctrlp,
416 PVR2_CVAL_INPUT_TV);
417 }
418 }
419 fv = vf->frequency;
420 if (vt.capability & V4L2_TUNER_CAP_LOW) {
Mike Iselyc0e69312006-12-27 23:25:06 -0300421 fv = (fv * 125) / 2;
422 } else {
423 fv = fv * 62500;
424 }
Mike Iselyd8554972006-06-26 20:58:46 -0300425 ret = pvr2_ctrl_set_value(
Mike Iselyc0e69312006-12-27 23:25:06 -0300426 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),fv);
Mike Iselyd8554972006-06-26 20:58:46 -0300427 break;
428 }
429
430 case VIDIOC_G_FREQUENCY:
431 {
432 struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
433 int val = 0;
Mike Isely18103c572007-01-20 00:09:47 -0300434 int cur_input;
435 struct v4l2_tuner vt;
436 ret = pvr2_hdw_get_tuner_status(hdw,&vt);
437 if (ret != 0) break;
Mike Iselyd8554972006-06-26 20:58:46 -0300438 ret = pvr2_ctrl_get_value(
439 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),
440 &val);
Mike Iselyc0e69312006-12-27 23:25:06 -0300441 if (ret != 0) break;
442 pvr2_ctrl_get_value(
443 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
444 &cur_input);
445 if (cur_input == PVR2_CVAL_INPUT_RADIO) {
Mike Iselyc0e69312006-12-27 23:25:06 -0300446 vf->type = V4L2_TUNER_RADIO;
447 } else {
Mike Iselyc0e69312006-12-27 23:25:06 -0300448 vf->type = V4L2_TUNER_ANALOG_TV;
449 }
Mike Isely18103c572007-01-20 00:09:47 -0300450 if (vt.capability & V4L2_TUNER_CAP_LOW) {
451 val = (val * 2) / 125;
452 } else {
453 val /= 62500;
454 }
455 vf->frequency = val;
Mike Iselyd8554972006-06-26 20:58:46 -0300456 break;
457 }
458
459 case VIDIOC_ENUM_FMT:
460 {
461 struct v4l2_fmtdesc *fd = (struct v4l2_fmtdesc *)arg;
462
463 /* Only one format is supported : mpeg.*/
464 if (fd->index != 0)
465 break;
466
467 memcpy(fd, pvr_fmtdesc, sizeof(struct v4l2_fmtdesc));
468 ret = 0;
469 break;
470 }
471
472 case VIDIOC_G_FMT:
473 {
474 struct v4l2_format *vf = (struct v4l2_format *)arg;
475 int val;
476 switch(vf->type) {
477 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
478 memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
479 sizeof(struct v4l2_format));
480 val = 0;
481 pvr2_ctrl_get_value(
482 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES),
483 &val);
484 vf->fmt.pix.width = val;
485 val = 0;
486 pvr2_ctrl_get_value(
Mike Iselyd8554972006-06-26 20:58:46 -0300487 pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES),
488 &val);
489 vf->fmt.pix.height = val;
490 ret = 0;
491 break;
492 case V4L2_BUF_TYPE_VBI_CAPTURE:
493 // ????? Still need to figure out to do VBI correctly
494 ret = -EINVAL;
495 break;
496 default:
497 ret = -EINVAL;
498 break;
499 }
500 break;
501 }
502
503 case VIDIOC_TRY_FMT:
504 case VIDIOC_S_FMT:
505 {
506 struct v4l2_format *vf = (struct v4l2_format *)arg;
507
508 ret = 0;
509 switch(vf->type) {
510 case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
Pantelis Koukousoulasfd694962007-01-20 01:59:54 -0300511 int lmin,lmax,ldef;
Mike Iselye95a1912006-08-08 09:10:07 -0300512 struct pvr2_ctrl *hcp,*vcp;
Mike Iselyd8554972006-06-26 20:58:46 -0300513 int h = vf->fmt.pix.height;
514 int w = vf->fmt.pix.width;
Mike Iselye95a1912006-08-08 09:10:07 -0300515 hcp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES);
516 vcp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES);
Mike Iselyd8554972006-06-26 20:58:46 -0300517
Mike Iselye95a1912006-08-08 09:10:07 -0300518 lmin = pvr2_ctrl_get_min(hcp);
519 lmax = pvr2_ctrl_get_max(hcp);
Mike Isely26dd1c572008-08-31 20:55:03 -0300520 pvr2_ctrl_get_def(hcp, &ldef);
Pantelis Koukousoulasfd694962007-01-20 01:59:54 -0300521 if (w == -1) {
522 w = ldef;
523 } else if (w < lmin) {
Mike Iselye95a1912006-08-08 09:10:07 -0300524 w = lmin;
525 } else if (w > lmax) {
526 w = lmax;
Mike Isely039c4302006-06-25 20:04:16 -0300527 }
Hans Verkuilb31e3412006-09-01 18:36:10 -0300528 lmin = pvr2_ctrl_get_min(vcp);
529 lmax = pvr2_ctrl_get_max(vcp);
Mike Isely26dd1c572008-08-31 20:55:03 -0300530 pvr2_ctrl_get_def(vcp, &ldef);
Pantelis Koukousoulasfd694962007-01-20 01:59:54 -0300531 if (h == -1) {
532 h = ldef;
533 } else if (h < lmin) {
Hans Verkuilb31e3412006-09-01 18:36:10 -0300534 h = lmin;
535 } else if (h > lmax) {
536 h = lmax;
537 }
Mike Iselyd8554972006-06-26 20:58:46 -0300538
539 memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
540 sizeof(struct v4l2_format));
Mike Isely039c4302006-06-25 20:04:16 -0300541 vf->fmt.pix.width = w;
542 vf->fmt.pix.height = h;
Mike Iselyd8554972006-06-26 20:58:46 -0300543
544 if (cmd == VIDIOC_S_FMT) {
Mike Iselye95a1912006-08-08 09:10:07 -0300545 pvr2_ctrl_set_value(hcp,vf->fmt.pix.width);
546 pvr2_ctrl_set_value(vcp,vf->fmt.pix.height);
Mike Iselyd8554972006-06-26 20:58:46 -0300547 }
548 } break;
549 case V4L2_BUF_TYPE_VBI_CAPTURE:
550 // ????? Still need to figure out to do VBI correctly
551 ret = -EINVAL;
552 break;
553 default:
554 ret = -EINVAL;
555 break;
556 }
557 break;
558 }
559
560 case VIDIOC_STREAMON:
561 {
Joe Perches108bdd72010-04-05 16:05:39 -0300562 if (!fh->pdi->stream) {
Mike Isely16eb40d2006-12-30 18:27:32 -0300563 /* No stream defined for this node. This means
564 that we're not currently allowed to stream from
565 this node. */
566 ret = -EPERM;
567 break;
568 }
Joe Perches108bdd72010-04-05 16:05:39 -0300569 ret = pvr2_hdw_set_stream_type(hdw,pdi->config);
Mike Iselyd8554972006-06-26 20:58:46 -0300570 if (ret < 0) return ret;
571 ret = pvr2_hdw_set_streaming(hdw,!0);
572 break;
573 }
574
575 case VIDIOC_STREAMOFF:
576 {
Joe Perches108bdd72010-04-05 16:05:39 -0300577 if (!fh->pdi->stream) {
Mike Isely16eb40d2006-12-30 18:27:32 -0300578 /* 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_streaming(hdw,0);
585 break;
586 }
587
588 case VIDIOC_QUERYCTRL:
589 {
590 struct pvr2_ctrl *cptr;
Mike Isely26dd1c572008-08-31 20:55:03 -0300591 int val;
Mike Iselyd8554972006-06-26 20:58:46 -0300592 struct v4l2_queryctrl *vc = (struct v4l2_queryctrl *)arg;
593 ret = 0;
Mike Isely1d9f8462006-06-25 20:04:58 -0300594 if (vc->id & V4L2_CTRL_FLAG_NEXT_CTRL) {
595 cptr = pvr2_hdw_get_ctrl_nextv4l(
596 hdw,(vc->id & ~V4L2_CTRL_FLAG_NEXT_CTRL));
597 if (cptr) vc->id = pvr2_ctrl_get_v4lid(cptr);
598 } else {
599 cptr = pvr2_hdw_get_ctrl_v4l(hdw,vc->id);
600 }
Mike Iselyd8554972006-06-26 20:58:46 -0300601 if (!cptr) {
Mike Isely0885ba12006-06-25 21:30:47 -0300602 pvr2_trace(PVR2_TRACE_V4LIOCTL,
Mike Iselya761f432006-06-25 20:04:44 -0300603 "QUERYCTRL id=0x%x not implemented here",
604 vc->id);
Mike Iselyd8554972006-06-26 20:58:46 -0300605 ret = -EINVAL;
606 break;
607 }
608
Mike Iselya761f432006-06-25 20:04:44 -0300609 pvr2_trace(PVR2_TRACE_V4LIOCTL,
610 "QUERYCTRL id=0x%x mapping name=%s (%s)",
611 vc->id,pvr2_ctrl_get_name(cptr),
612 pvr2_ctrl_get_desc(cptr));
613 strlcpy(vc->name,pvr2_ctrl_get_desc(cptr),sizeof(vc->name));
614 vc->flags = pvr2_ctrl_get_v4lflags(cptr);
Mike Isely26dd1c572008-08-31 20:55:03 -0300615 pvr2_ctrl_get_def(cptr, &val);
616 vc->default_value = val;
Mike Iselyd8554972006-06-26 20:58:46 -0300617 switch (pvr2_ctrl_get_type(cptr)) {
618 case pvr2_ctl_enum:
619 vc->type = V4L2_CTRL_TYPE_MENU;
620 vc->minimum = 0;
621 vc->maximum = pvr2_ctrl_get_cnt(cptr) - 1;
622 vc->step = 1;
623 break;
Mike Isely33213962006-06-25 20:04:40 -0300624 case pvr2_ctl_bool:
Mike Isely1d9f8462006-06-25 20:04:58 -0300625 vc->type = V4L2_CTRL_TYPE_BOOLEAN;
Mike Isely33213962006-06-25 20:04:40 -0300626 vc->minimum = 0;
627 vc->maximum = 1;
628 vc->step = 1;
629 break;
Mike Iselyd8554972006-06-26 20:58:46 -0300630 case pvr2_ctl_int:
631 vc->type = V4L2_CTRL_TYPE_INTEGER;
632 vc->minimum = pvr2_ctrl_get_min(cptr);
633 vc->maximum = pvr2_ctrl_get_max(cptr);
634 vc->step = 1;
635 break;
636 default:
Mike Isely0885ba12006-06-25 21:30:47 -0300637 pvr2_trace(PVR2_TRACE_V4LIOCTL,
Mike Iselya761f432006-06-25 20:04:44 -0300638 "QUERYCTRL id=0x%x name=%s not mappable",
639 vc->id,pvr2_ctrl_get_name(cptr));
Mike Iselyd8554972006-06-26 20:58:46 -0300640 ret = -EINVAL;
641 break;
642 }
643 break;
644 }
645
646 case VIDIOC_QUERYMENU:
647 {
648 struct v4l2_querymenu *vm = (struct v4l2_querymenu *)arg;
649 unsigned int cnt = 0;
650 ret = pvr2_ctrl_get_valname(pvr2_hdw_get_ctrl_v4l(hdw,vm->id),
651 vm->index,
652 vm->name,sizeof(vm->name)-1,
653 &cnt);
654 vm->name[cnt] = 0;
655 break;
656 }
657
658 case VIDIOC_G_CTRL:
659 {
660 struct v4l2_control *vc = (struct v4l2_control *)arg;
661 int val = 0;
662 ret = pvr2_ctrl_get_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id),
663 &val);
664 vc->value = val;
665 break;
666 }
667
668 case VIDIOC_S_CTRL:
669 {
670 struct v4l2_control *vc = (struct v4l2_control *)arg;
671 ret = pvr2_ctrl_set_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id),
672 vc->value);
673 break;
674 }
675
Mike Isely1d9f8462006-06-25 20:04:58 -0300676 case VIDIOC_G_EXT_CTRLS:
677 {
678 struct v4l2_ext_controls *ctls =
679 (struct v4l2_ext_controls *)arg;
680 struct v4l2_ext_control *ctrl;
681 unsigned int idx;
682 int val;
Mike Iselyc1c26802007-01-20 00:30:23 -0300683 ret = 0;
Mike Isely1d9f8462006-06-25 20:04:58 -0300684 for (idx = 0; idx < ctls->count; idx++) {
685 ctrl = ctls->controls + idx;
686 ret = pvr2_ctrl_get_value(
687 pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),&val);
688 if (ret) {
689 ctls->error_idx = idx;
690 break;
691 }
692 /* Ensure that if read as a 64 bit value, the user
693 will still get a hopefully sane value */
694 ctrl->value64 = 0;
695 ctrl->value = val;
696 }
697 break;
698 }
699
700 case VIDIOC_S_EXT_CTRLS:
701 {
702 struct v4l2_ext_controls *ctls =
703 (struct v4l2_ext_controls *)arg;
704 struct v4l2_ext_control *ctrl;
705 unsigned int idx;
Mike Iselyc1c26802007-01-20 00:30:23 -0300706 ret = 0;
Mike Isely1d9f8462006-06-25 20:04:58 -0300707 for (idx = 0; idx < ctls->count; idx++) {
708 ctrl = ctls->controls + idx;
709 ret = pvr2_ctrl_set_value(
710 pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),
711 ctrl->value);
712 if (ret) {
713 ctls->error_idx = idx;
714 break;
715 }
716 }
717 break;
718 }
719
720 case VIDIOC_TRY_EXT_CTRLS:
721 {
722 struct v4l2_ext_controls *ctls =
723 (struct v4l2_ext_controls *)arg;
724 struct v4l2_ext_control *ctrl;
725 struct pvr2_ctrl *pctl;
726 unsigned int idx;
727 /* For the moment just validate that the requested control
728 actually exists. */
Mike Iselyc1c26802007-01-20 00:30:23 -0300729 ret = 0;
Mike Isely1d9f8462006-06-25 20:04:58 -0300730 for (idx = 0; idx < ctls->count; idx++) {
731 ctrl = ctls->controls + idx;
732 pctl = pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id);
733 if (!pctl) {
734 ret = -EINVAL;
735 ctls->error_idx = idx;
736 break;
737 }
738 }
739 break;
740 }
741
Mike Isely432907f2008-08-31 21:02:20 -0300742 case VIDIOC_CROPCAP:
743 {
744 struct v4l2_cropcap *cap = (struct v4l2_cropcap *)arg;
745 if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
746 ret = -EINVAL;
747 break;
748 }
749 ret = pvr2_hdw_get_cropcap(hdw, cap);
750 cap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* paranoia */
751 break;
752 }
753 case VIDIOC_G_CROP:
754 {
755 struct v4l2_crop *crop = (struct v4l2_crop *)arg;
756 int val = 0;
757 if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
758 ret = -EINVAL;
759 break;
760 }
761 ret = pvr2_ctrl_get_value(
762 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL), &val);
763 if (ret != 0) {
764 ret = -EINVAL;
765 break;
766 }
767 crop->c.left = val;
768 ret = pvr2_ctrl_get_value(
769 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT), &val);
770 if (ret != 0) {
771 ret = -EINVAL;
772 break;
773 }
774 crop->c.top = val;
775 ret = pvr2_ctrl_get_value(
776 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW), &val);
777 if (ret != 0) {
778 ret = -EINVAL;
779 break;
780 }
781 crop->c.width = val;
782 ret = pvr2_ctrl_get_value(
783 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH), &val);
784 if (ret != 0) {
785 ret = -EINVAL;
786 break;
787 }
788 crop->c.height = val;
789 }
790 case VIDIOC_S_CROP:
791 {
792 struct v4l2_crop *crop = (struct v4l2_crop *)arg;
Mike Isely432907f2008-08-31 21:02:20 -0300793 if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
794 ret = -EINVAL;
795 break;
796 }
Mike Isely432907f2008-08-31 21:02:20 -0300797 ret = pvr2_ctrl_set_value(
798 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL),
799 crop->c.left);
800 if (ret != 0) {
801 ret = -EINVAL;
802 break;
803 }
804 ret = pvr2_ctrl_set_value(
805 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT),
806 crop->c.top);
807 if (ret != 0) {
808 ret = -EINVAL;
809 break;
810 }
811 ret = pvr2_ctrl_set_value(
812 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW),
813 crop->c.width);
814 if (ret != 0) {
815 ret = -EINVAL;
816 break;
817 }
818 ret = pvr2_ctrl_set_value(
819 pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH),
820 crop->c.height);
821 if (ret != 0) {
822 ret = -EINVAL;
823 break;
824 }
825 }
Mike Iselyd8554972006-06-26 20:58:46 -0300826 case VIDIOC_LOG_STATUS:
827 {
Mike Iselyd8554972006-06-26 20:58:46 -0300828 pvr2_hdw_trigger_module_log(hdw);
Mike Iselyd8554972006-06-26 20:58:46 -0300829 ret = 0;
830 break;
831 }
Mike Isely32ffa9a2006-09-23 22:26:52 -0300832#ifdef CONFIG_VIDEO_ADV_DEBUG
Trent Piepho52ebc762007-01-23 22:38:13 -0300833 case VIDIOC_DBG_S_REGISTER:
Trent Piepho52ebc762007-01-23 22:38:13 -0300834 case VIDIOC_DBG_G_REGISTER:
Mike Isely32ffa9a2006-09-23 22:26:52 -0300835 {
Hans Verkuilf3d092b2007-02-23 20:55:14 -0300836 u64 val;
Hans Verkuilaecde8b52008-12-30 07:14:19 -0300837 struct v4l2_dbg_register *req = (struct v4l2_dbg_register *)arg;
Trent Piepho52ebc762007-01-23 22:38:13 -0300838 if (cmd == VIDIOC_DBG_S_REGISTER) val = req->val;
Mike Isely32ffa9a2006-09-23 22:26:52 -0300839 ret = pvr2_hdw_register_access(
Hans Verkuilaecde8b52008-12-30 07:14:19 -0300840 hdw, &req->match, req->reg,
841 cmd == VIDIOC_DBG_S_REGISTER, &val);
Trent Piepho52ebc762007-01-23 22:38:13 -0300842 if (cmd == VIDIOC_DBG_G_REGISTER) req->val = val;
Mike Isely32ffa9a2006-09-23 22:26:52 -0300843 break;
844 }
845#endif
Mike Iselyd8554972006-06-26 20:58:46 -0300846
847 default :
Mauro Carvalho Chehab7a286cc2011-06-26 10:18:03 -0300848 ret = -ENOTTY;
Hans Verkuil08af2452010-12-24 10:33:19 -0300849 break;
Mike Iselyd8554972006-06-26 20:58:46 -0300850 }
851
852 pvr2_hdw_commit_ctl(hdw);
853
854 if (ret < 0) {
855 if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
Mike Isely0885ba12006-06-25 21:30:47 -0300856 pvr2_trace(PVR2_TRACE_V4LIOCTL,
Hans Verkuil069b7472008-12-30 07:04:34 -0300857 "pvr2_v4l2_do_ioctl failure, ret=%ld", ret);
Mike Iselyd8554972006-06-26 20:58:46 -0300858 } else {
Mike Isely0885ba12006-06-25 21:30:47 -0300859 if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
860 pvr2_trace(PVR2_TRACE_V4LIOCTL,
Hans Verkuil069b7472008-12-30 07:04:34 -0300861 "pvr2_v4l2_do_ioctl failure, ret=%ld"
862 " command was:", ret);
Mike Iselyd8554972006-06-26 20:58:46 -0300863 v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),
864 cmd);
865 }
866 }
867 } else {
868 pvr2_trace(PVR2_TRACE_V4LIOCTL,
Hans Verkuil069b7472008-12-30 07:04:34 -0300869 "pvr2_v4l2_do_ioctl complete, ret=%ld (0x%lx)",
870 ret, ret);
Mike Iselyd8554972006-06-26 20:58:46 -0300871 }
872 return ret;
873}
874
Mike Iselyd8554972006-06-26 20:58:46 -0300875static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
876{
Mike Isely0f0f257b2006-12-27 23:19:42 -0300877 struct pvr2_hdw *hdw = dip->v4lp->channel.mc_head->hdw;
Mike Isely16eb40d2006-12-30 18:27:32 -0300878 enum pvr2_config cfg = dip->config;
Mike Iselyd72baad2010-05-15 00:15:38 -0300879 char msg[80];
880 unsigned int mcnt;
881
882 /* Construct the unregistration message *before* we actually
883 perform the unregistration step. By doing it this way we don't
884 have to worry about potentially touching deleted resources. */
885 mcnt = scnprintf(msg, sizeof(msg) - 1,
886 "pvrusb2: unregistered device %s [%s]",
887 video_device_node_name(&dip->devbase),
888 pvr2_config_get_name(cfg));
889 msg[mcnt] = 0;
Mike Isely0f0f257b2006-12-27 23:19:42 -0300890
Mike Isely16eb40d2006-12-30 18:27:32 -0300891 pvr2_hdw_v4l_store_minor_number(hdw,dip->minor_type,-1);
Mike Isely75910052006-09-23 22:30:50 -0300892
893 /* Paranoia */
Randy Dunlapc2625bf2006-10-29 11:12:27 -0300894 dip->v4lp = NULL;
895 dip->stream = NULL;
Mike Isely75910052006-09-23 22:30:50 -0300896
897 /* Actual deallocation happens later when all internal references
898 are gone. */
899 video_unregister_device(&dip->devbase);
Mike Isely0f0f257b2006-12-27 23:19:42 -0300900
Mike Iselyd72baad2010-05-15 00:15:38 -0300901 printk(KERN_INFO "%s\n", msg);
Mike Isely0f0f257b2006-12-27 23:19:42 -0300902
Mike Iselyd8554972006-06-26 20:58:46 -0300903}
904
905
Mike Isely4a89baa2009-10-12 00:13:28 -0300906static void pvr2_v4l2_dev_disassociate_parent(struct pvr2_v4l2_dev *dip)
907{
908 if (!dip) return;
909 if (!dip->devbase.parent) return;
910 dip->devbase.parent = NULL;
911 device_move(&dip->devbase.dev, NULL, DPM_ORDER_NONE);
912}
913
914
Mike Iselyd8554972006-06-26 20:58:46 -0300915static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp)
916{
Mike Isely0f0f257b2006-12-27 23:19:42 -0300917 if (vp->dev_video) {
918 pvr2_v4l2_dev_destroy(vp->dev_video);
Al Viro89952d12007-03-14 09:17:59 +0000919 vp->dev_video = NULL;
Mike Isely0f0f257b2006-12-27 23:19:42 -0300920 }
921 if (vp->dev_radio) {
922 pvr2_v4l2_dev_destroy(vp->dev_radio);
Al Viro89952d12007-03-14 09:17:59 +0000923 vp->dev_radio = NULL;
Mike Isely0f0f257b2006-12-27 23:19:42 -0300924 }
Mike Iselyd8554972006-06-26 20:58:46 -0300925
926 pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp);
927 pvr2_channel_done(&vp->channel);
928 kfree(vp);
929}
930
931
Mike Isely75910052006-09-23 22:30:50 -0300932static void pvr2_video_device_release(struct video_device *vdev)
933{
934 struct pvr2_v4l2_dev *dev;
935 dev = container_of(vdev,struct pvr2_v4l2_dev,devbase);
936 kfree(dev);
937}
938
939
Adrian Bunk07e337e2006-06-30 11:30:20 -0300940static void pvr2_v4l2_internal_check(struct pvr2_channel *chp)
Mike Iselyd8554972006-06-26 20:58:46 -0300941{
942 struct pvr2_v4l2 *vp;
943 vp = container_of(chp,struct pvr2_v4l2,channel);
944 if (!vp->channel.mc_head->disconnect_flag) return;
Mike Isely4a89baa2009-10-12 00:13:28 -0300945 pvr2_v4l2_dev_disassociate_parent(vp->dev_video);
946 pvr2_v4l2_dev_disassociate_parent(vp->dev_radio);
Mike Iselyd8554972006-06-26 20:58:46 -0300947 if (vp->vfirst) return;
948 pvr2_v4l2_destroy_no_lock(vp);
949}
950
951
Hans Verkuil069b7472008-12-30 07:04:34 -0300952static long pvr2_v4l2_ioctl(struct file *file,
Adrian Bunk07e337e2006-06-30 11:30:20 -0300953 unsigned int cmd, unsigned long arg)
Mike Iselyd8554972006-06-26 20:58:46 -0300954{
955
Hans Verkuilf473bf72008-11-01 08:25:11 -0300956 return video_usercopy(file, cmd, arg, pvr2_v4l2_do_ioctl);
Mike Iselyd8554972006-06-26 20:58:46 -0300957}
958
959
Hans Verkuilbec43662008-12-30 06:58:20 -0300960static int pvr2_v4l2_release(struct file *file)
Mike Iselyd8554972006-06-26 20:58:46 -0300961{
962 struct pvr2_v4l2_fh *fhp = file->private_data;
963 struct pvr2_v4l2 *vp = fhp->vhead;
Mike Iselyc74e00622006-12-30 18:31:22 -0300964 struct pvr2_hdw *hdw = fhp->channel.mc_head->hdw;
Mike Iselyd8554972006-06-26 20:58:46 -0300965
966 pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_release");
967
968 if (fhp->rhp) {
969 struct pvr2_stream *sp;
Mike Iselyd8554972006-06-26 20:58:46 -0300970 pvr2_hdw_set_streaming(hdw,0);
971 sp = pvr2_ioread_get_stream(fhp->rhp);
Mike Iselya0fd1cb2006-06-30 11:35:28 -0300972 if (sp) pvr2_stream_set_callback(sp,NULL,NULL);
Mike Iselyd8554972006-06-26 20:58:46 -0300973 pvr2_ioread_destroy(fhp->rhp);
Mike Iselya0fd1cb2006-06-30 11:35:28 -0300974 fhp->rhp = NULL;
Mike Iselyd8554972006-06-26 20:58:46 -0300975 }
Pantelis Koukousoulasae2b9e22006-12-27 23:09:55 -0300976
Hans Verkuilffb48772010-05-01 08:03:24 -0300977 v4l2_prio_close(&vp->prio, fhp->prio);
Mike Iselyd8554972006-06-26 20:58:46 -0300978 file->private_data = NULL;
979
Mike Isely794b1602008-04-22 14:45:45 -0300980 if (fhp->vnext) {
981 fhp->vnext->vprev = fhp->vprev;
982 } else {
983 vp->vlast = fhp->vprev;
984 }
985 if (fhp->vprev) {
986 fhp->vprev->vnext = fhp->vnext;
987 } else {
988 vp->vfirst = fhp->vnext;
989 }
990 fhp->vnext = NULL;
991 fhp->vprev = NULL;
992 fhp->vhead = NULL;
993 pvr2_channel_done(&fhp->channel);
994 pvr2_trace(PVR2_TRACE_STRUCT,
995 "Destroying pvr_v4l2_fh id=%p",fhp);
Mike Iselye57b1c82008-04-21 03:52:34 -0300996 if (fhp->input_map) {
997 kfree(fhp->input_map);
998 fhp->input_map = NULL;
999 }
Mike Isely794b1602008-04-22 14:45:45 -03001000 kfree(fhp);
1001 if (vp->channel.mc_head->disconnect_flag && !vp->vfirst) {
1002 pvr2_v4l2_destroy_no_lock(vp);
1003 }
Mike Iselyd8554972006-06-26 20:58:46 -03001004 return 0;
1005}
1006
1007
Hans Verkuilbec43662008-12-30 06:58:20 -03001008static int pvr2_v4l2_open(struct file *file)
Mike Iselyd8554972006-06-26 20:58:46 -03001009{
Mike Isely75910052006-09-23 22:30:50 -03001010 struct pvr2_v4l2_dev *dip; /* Our own context pointer */
Mike Iselyd8554972006-06-26 20:58:46 -03001011 struct pvr2_v4l2_fh *fhp;
1012 struct pvr2_v4l2 *vp;
1013 struct pvr2_hdw *hdw;
Mike Isely1cb03b72008-04-21 03:47:43 -03001014 unsigned int input_mask = 0;
Mike Iselye57b1c82008-04-21 03:52:34 -03001015 unsigned int input_cnt,idx;
Mike Isely1cb03b72008-04-21 03:47:43 -03001016 int ret = 0;
Mike Iselyd8554972006-06-26 20:58:46 -03001017
Mike Isely75910052006-09-23 22:30:50 -03001018 dip = container_of(video_devdata(file),struct pvr2_v4l2_dev,devbase);
Mike Iselyd8554972006-06-26 20:58:46 -03001019
1020 vp = dip->v4lp;
1021 hdw = vp->channel.hdw;
1022
1023 pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_open");
1024
1025 if (!pvr2_hdw_dev_ok(hdw)) {
1026 pvr2_trace(PVR2_TRACE_OPEN_CLOSE,
1027 "pvr2_v4l2_open: hardware not ready");
1028 return -EIO;
1029 }
1030
Mike Isely4b85dee2007-01-20 00:03:32 -03001031 fhp = kzalloc(sizeof(*fhp),GFP_KERNEL);
Mike Iselyd8554972006-06-26 20:58:46 -03001032 if (!fhp) {
1033 return -ENOMEM;
1034 }
Mike Iselyd8554972006-06-26 20:58:46 -03001035
1036 init_waitqueue_head(&fhp->wait_data);
Joe Perches108bdd72010-04-05 16:05:39 -03001037 fhp->pdi = dip;
Mike Iselyd8554972006-06-26 20:58:46 -03001038
Mike Isely794b1602008-04-22 14:45:45 -03001039 pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp);
1040 pvr2_channel_init(&fhp->channel,vp->channel.mc_head);
Pantelis Koukousoulasae2b9e22006-12-27 23:09:55 -03001041
Mike Isely1cb03b72008-04-21 03:47:43 -03001042 if (dip->v4l_type == VFL_TYPE_RADIO) {
1043 /* Opening device as a radio, legal input selection subset
1044 is just the radio. */
1045 input_mask = (1 << PVR2_CVAL_INPUT_RADIO);
1046 } else {
1047 /* Opening the main V4L device, legal input selection
1048 subset includes all analog inputs. */
1049 input_mask = ((1 << PVR2_CVAL_INPUT_RADIO) |
1050 (1 << PVR2_CVAL_INPUT_TV) |
1051 (1 << PVR2_CVAL_INPUT_COMPOSITE) |
1052 (1 << PVR2_CVAL_INPUT_SVIDEO));
1053 }
1054 ret = pvr2_channel_limit_inputs(&fhp->channel,input_mask);
1055 if (ret) {
1056 pvr2_channel_done(&fhp->channel);
1057 pvr2_trace(PVR2_TRACE_STRUCT,
1058 "Destroying pvr_v4l2_fh id=%p (input mask error)",
1059 fhp);
1060
1061 kfree(fhp);
1062 return ret;
1063 }
1064
Mike Iselye57b1c82008-04-21 03:52:34 -03001065 input_mask &= pvr2_hdw_get_input_available(hdw);
1066 input_cnt = 0;
1067 for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) {
1068 if (input_mask & (1 << idx)) input_cnt++;
1069 }
1070 fhp->input_cnt = input_cnt;
1071 fhp->input_map = kzalloc(input_cnt,GFP_KERNEL);
1072 if (!fhp->input_map) {
1073 pvr2_channel_done(&fhp->channel);
1074 pvr2_trace(PVR2_TRACE_STRUCT,
1075 "Destroying pvr_v4l2_fh id=%p (input map failure)",
1076 fhp);
1077 kfree(fhp);
1078 return -ENOMEM;
1079 }
1080 input_cnt = 0;
1081 for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) {
1082 if (!(input_mask & (1 << idx))) continue;
1083 fhp->input_map[input_cnt++] = idx;
1084 }
1085
Mike Isely794b1602008-04-22 14:45:45 -03001086 fhp->vnext = NULL;
1087 fhp->vprev = vp->vlast;
1088 if (vp->vlast) {
1089 vp->vlast->vnext = fhp;
1090 } else {
1091 vp->vfirst = fhp;
1092 }
1093 vp->vlast = fhp;
1094 fhp->vhead = vp;
Mike Iselyc74e00622006-12-30 18:31:22 -03001095
Mike Iselyd8554972006-06-26 20:58:46 -03001096 fhp->file = file;
1097 file->private_data = fhp;
Hans Verkuilffb48772010-05-01 08:03:24 -03001098 v4l2_prio_open(&vp->prio, &fhp->prio);
Mike Iselyd8554972006-06-26 20:58:46 -03001099
1100 fhp->fw_mode_flag = pvr2_hdw_cpufw_get_enabled(hdw);
1101
1102 return 0;
1103}
1104
1105
1106static void pvr2_v4l2_notify(struct pvr2_v4l2_fh *fhp)
1107{
1108 wake_up(&fhp->wait_data);
1109}
1110
1111static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh)
1112{
1113 int ret;
1114 struct pvr2_stream *sp;
1115 struct pvr2_hdw *hdw;
1116 if (fh->rhp) return 0;
1117
Joe Perches108bdd72010-04-05 16:05:39 -03001118 if (!fh->pdi->stream) {
Mike Isely16eb40d2006-12-30 18:27:32 -03001119 /* No stream defined for this node. This means that we're
1120 not currently allowed to stream from this node. */
1121 return -EPERM;
1122 }
1123
Mike Iselyd8554972006-06-26 20:58:46 -03001124 /* First read() attempt. Try to claim the stream and start
1125 it... */
1126 if ((ret = pvr2_channel_claim_stream(&fh->channel,
Joe Perches108bdd72010-04-05 16:05:39 -03001127 fh->pdi->stream)) != 0) {
Mike Iselyd8554972006-06-26 20:58:46 -03001128 /* Someone else must already have it */
1129 return ret;
1130 }
1131
Joe Perches108bdd72010-04-05 16:05:39 -03001132 fh->rhp = pvr2_channel_create_mpeg_stream(fh->pdi->stream);
Mike Iselyd8554972006-06-26 20:58:46 -03001133 if (!fh->rhp) {
Mike Iselya0fd1cb2006-06-30 11:35:28 -03001134 pvr2_channel_claim_stream(&fh->channel,NULL);
Mike Iselyd8554972006-06-26 20:58:46 -03001135 return -ENOMEM;
1136 }
1137
1138 hdw = fh->channel.mc_head->hdw;
Joe Perches108bdd72010-04-05 16:05:39 -03001139 sp = fh->pdi->stream->stream;
Mike Iselyd8554972006-06-26 20:58:46 -03001140 pvr2_stream_set_callback(sp,(pvr2_stream_callback)pvr2_v4l2_notify,fh);
Joe Perches108bdd72010-04-05 16:05:39 -03001141 pvr2_hdw_set_stream_type(hdw,fh->pdi->config);
Mike Isely681c7392007-11-26 01:48:52 -03001142 if ((ret = pvr2_hdw_set_streaming(hdw,!0)) < 0) return ret;
1143 return pvr2_ioread_set_enabled(fh->rhp,!0);
Mike Iselyd8554972006-06-26 20:58:46 -03001144}
1145
1146
1147static ssize_t pvr2_v4l2_read(struct file *file,
1148 char __user *buff, size_t count, loff_t *ppos)
1149{
1150 struct pvr2_v4l2_fh *fh = file->private_data;
1151 int ret;
1152
1153 if (fh->fw_mode_flag) {
1154 struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
1155 char *tbuf;
1156 int c1,c2;
1157 int tcnt = 0;
1158 unsigned int offs = *ppos;
1159
1160 tbuf = kmalloc(PAGE_SIZE,GFP_KERNEL);
1161 if (!tbuf) return -ENOMEM;
1162
1163 while (count) {
1164 c1 = count;
1165 if (c1 > PAGE_SIZE) c1 = PAGE_SIZE;
1166 c2 = pvr2_hdw_cpufw_get(hdw,offs,tbuf,c1);
1167 if (c2 < 0) {
1168 tcnt = c2;
1169 break;
1170 }
1171 if (!c2) break;
1172 if (copy_to_user(buff,tbuf,c2)) {
1173 tcnt = -EFAULT;
1174 break;
1175 }
1176 offs += c2;
1177 tcnt += c2;
1178 buff += c2;
1179 count -= c2;
1180 *ppos += c2;
1181 }
1182 kfree(tbuf);
1183 return tcnt;
1184 }
1185
1186 if (!fh->rhp) {
1187 ret = pvr2_v4l2_iosetup(fh);
1188 if (ret) {
1189 return ret;
1190 }
1191 }
1192
1193 for (;;) {
1194 ret = pvr2_ioread_read(fh->rhp,buff,count);
1195 if (ret >= 0) break;
1196 if (ret != -EAGAIN) break;
1197 if (file->f_flags & O_NONBLOCK) break;
1198 /* Doing blocking I/O. Wait here. */
1199 ret = wait_event_interruptible(
1200 fh->wait_data,
1201 pvr2_ioread_avail(fh->rhp) >= 0);
1202 if (ret < 0) break;
1203 }
1204
1205 return ret;
1206}
1207
1208
1209static unsigned int pvr2_v4l2_poll(struct file *file, poll_table *wait)
1210{
1211 unsigned int mask = 0;
1212 struct pvr2_v4l2_fh *fh = file->private_data;
1213 int ret;
1214
1215 if (fh->fw_mode_flag) {
1216 mask |= POLLIN | POLLRDNORM;
1217 return mask;
1218 }
1219
1220 if (!fh->rhp) {
1221 ret = pvr2_v4l2_iosetup(fh);
1222 if (ret) return POLLERR;
1223 }
1224
1225 poll_wait(file,&fh->wait_data,wait);
1226
1227 if (pvr2_ioread_avail(fh->rhp) >= 0) {
1228 mask |= POLLIN | POLLRDNORM;
1229 }
1230
1231 return mask;
1232}
1233
1234
Hans Verkuilbec43662008-12-30 06:58:20 -03001235static const struct v4l2_file_operations vdev_fops = {
Mike Iselyd8554972006-06-26 20:58:46 -03001236 .owner = THIS_MODULE,
1237 .open = pvr2_v4l2_open,
1238 .release = pvr2_v4l2_release,
1239 .read = pvr2_v4l2_read,
1240 .ioctl = pvr2_v4l2_ioctl,
Mike Iselyd8554972006-06-26 20:58:46 -03001241 .poll = pvr2_v4l2_poll,
1242};
1243
1244
Mike Iselyd8554972006-06-26 20:58:46 -03001245static struct video_device vdev_template = {
Mike Iselyd8554972006-06-26 20:58:46 -03001246 .fops = &vdev_fops,
1247};
1248
1249
1250static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
1251 struct pvr2_v4l2 *vp,
Mike Isely16eb40d2006-12-30 18:27:32 -03001252 int v4l_type)
Mike Iselyd8554972006-06-26 20:58:46 -03001253{
Mike Isely4a89baa2009-10-12 00:13:28 -03001254 struct usb_device *usbdev;
Mike Iselyd8554972006-06-26 20:58:46 -03001255 int mindevnum;
1256 int unit_number;
Al Viro89952d12007-03-14 09:17:59 +00001257 int *nr_ptr = NULL;
Mike Iselyd8554972006-06-26 20:58:46 -03001258 dip->v4lp = vp;
Mike Iselyd8554972006-06-26 20:58:46 -03001259
Mike Isely4a89baa2009-10-12 00:13:28 -03001260 usbdev = pvr2_hdw_get_dev(vp->channel.mc_head->hdw);
Mike Isely16eb40d2006-12-30 18:27:32 -03001261 dip->v4l_type = v4l_type;
1262 switch (v4l_type) {
1263 case VFL_TYPE_GRABBER:
Mike Iselyd8554972006-06-26 20:58:46 -03001264 dip->stream = &vp->channel.mc_head->video_stream;
Mike Isely16eb40d2006-12-30 18:27:32 -03001265 dip->config = pvr2_config_mpeg;
1266 dip->minor_type = pvr2_v4l_type_video;
1267 nr_ptr = video_nr;
Mike Iselyc74e00622006-12-30 18:31:22 -03001268 if (!dip->stream) {
Mauro Carvalho Chehabbe9ed512009-01-08 09:13:42 -03001269 pr_err(KBUILD_MODNAME
1270 ": Failed to set up pvrusb2 v4l video dev"
1271 " due to missing stream instance\n");
Mike Iselyc74e00622006-12-30 18:31:22 -03001272 return;
1273 }
Mike Iselyd8554972006-06-26 20:58:46 -03001274 break;
Mike Isely16eb40d2006-12-30 18:27:32 -03001275 case VFL_TYPE_VBI:
1276 dip->config = pvr2_config_vbi;
1277 dip->minor_type = pvr2_v4l_type_vbi;
1278 nr_ptr = vbi_nr;
Mike Iselyd8554972006-06-26 20:58:46 -03001279 break;
Mike Isely16eb40d2006-12-30 18:27:32 -03001280 case VFL_TYPE_RADIO:
Mike Iselyaf78a482007-01-20 00:04:31 -03001281 dip->stream = &vp->channel.mc_head->video_stream;
1282 dip->config = pvr2_config_mpeg;
Mike Isely16eb40d2006-12-30 18:27:32 -03001283 dip->minor_type = pvr2_v4l_type_radio;
1284 nr_ptr = radio_nr;
Mike Iselyd8554972006-06-26 20:58:46 -03001285 break;
1286 default:
1287 /* Bail out (this should be impossible) */
Mauro Carvalho Chehabbe9ed512009-01-08 09:13:42 -03001288 pr_err(KBUILD_MODNAME ": Failed to set up pvrusb2 v4l dev"
1289 " due to unrecognized config\n");
Mike Iselyd8554972006-06-26 20:58:46 -03001290 return;
1291 }
1292
Mike Isely75910052006-09-23 22:30:50 -03001293 memcpy(&dip->devbase,&vdev_template,sizeof(vdev_template));
1294 dip->devbase.release = pvr2_video_device_release;
Mike Iselyd8554972006-06-26 20:58:46 -03001295
1296 mindevnum = -1;
1297 unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw);
Mike Isely16eb40d2006-12-30 18:27:32 -03001298 if (nr_ptr && (unit_number >= 0) && (unit_number < PVR_NUM)) {
1299 mindevnum = nr_ptr[unit_number];
Mike Iselyd8554972006-06-26 20:58:46 -03001300 }
Mike Isely4a89baa2009-10-12 00:13:28 -03001301 dip->devbase.parent = &usbdev->dev;
Mike Isely16eb40d2006-12-30 18:27:32 -03001302 if ((video_register_device(&dip->devbase,
1303 dip->v4l_type, mindevnum) < 0) &&
1304 (video_register_device(&dip->devbase,
1305 dip->v4l_type, -1) < 0)) {
Mauro Carvalho Chehabbe9ed512009-01-08 09:13:42 -03001306 pr_err(KBUILD_MODNAME
1307 ": Failed to register pvrusb2 v4l device\n");
Pantelis Koukousoulasae2b9e22006-12-27 23:09:55 -03001308 }
Mike Isely16eb40d2006-12-30 18:27:32 -03001309
Laurent Pinchart38c7c032009-11-27 13:57:15 -03001310 printk(KERN_INFO "pvrusb2: registered device %s [%s]\n",
1311 video_device_node_name(&dip->devbase),
Mike Isely16eb40d2006-12-30 18:27:32 -03001312 pvr2_config_get_name(dip->config));
Mike Iselyd8554972006-06-26 20:58:46 -03001313
Mike Iselyd8554972006-06-26 20:58:46 -03001314 pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,
Mike Isely16eb40d2006-12-30 18:27:32 -03001315 dip->minor_type,dip->devbase.minor);
Mike Iselyd8554972006-06-26 20:58:46 -03001316}
1317
1318
1319struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
1320{
1321 struct pvr2_v4l2 *vp;
1322
Mike Isely4b85dee2007-01-20 00:03:32 -03001323 vp = kzalloc(sizeof(*vp),GFP_KERNEL);
Mike Iselyd8554972006-06-26 20:58:46 -03001324 if (!vp) return vp;
Mike Iselyd8554972006-06-26 20:58:46 -03001325 pvr2_channel_init(&vp->channel,mnp);
1326 pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp);
1327
1328 vp->channel.check_func = pvr2_v4l2_internal_check;
1329
1330 /* register streams */
Mike Iselybeb0ecd2008-04-22 14:45:38 -03001331 vp->dev_video = kzalloc(sizeof(*vp->dev_video),GFP_KERNEL);
1332 if (!vp->dev_video) goto fail;
Mike Isely16eb40d2006-12-30 18:27:32 -03001333 pvr2_v4l2_dev_init(vp->dev_video,vp,VFL_TYPE_GRABBER);
Mike Iselye57b1c82008-04-21 03:52:34 -03001334 if (pvr2_hdw_get_input_available(vp->channel.mc_head->hdw) &
1335 (1 << PVR2_CVAL_INPUT_RADIO)) {
Mike Iselybeb0ecd2008-04-22 14:45:38 -03001336 vp->dev_radio = kzalloc(sizeof(*vp->dev_radio),GFP_KERNEL);
1337 if (!vp->dev_radio) goto fail;
1338 pvr2_v4l2_dev_init(vp->dev_radio,vp,VFL_TYPE_RADIO);
1339 }
Mike Iselyd8554972006-06-26 20:58:46 -03001340
1341 return vp;
Mike Iselybeb0ecd2008-04-22 14:45:38 -03001342 fail:
1343 pvr2_trace(PVR2_TRACE_STRUCT,"Failure creating pvr2_v4l2 id=%p",vp);
1344 pvr2_v4l2_destroy_no_lock(vp);
Harvey Harrisona6a3a172008-04-28 16:50:03 -07001345 return NULL;
Mike Iselyd8554972006-06-26 20:58:46 -03001346}
1347
1348/*
1349 Stuff for Emacs to see, in order to encourage consistent editing style:
1350 *** Local Variables: ***
1351 *** mode: c ***
1352 *** fill-column: 75 ***
1353 *** tab-width: 8 ***
1354 *** c-basic-offset: 8 ***
1355 *** End: ***
1356 */