Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/media/video/cx18/cx18-ioctl.c
17686 views
1
/*
2
* cx18 ioctl system call
3
*
4
* Derived from ivtv-ioctl.c
5
*
6
* Copyright (C) 2007 Hans Verkuil <[email protected]>
7
* Copyright (C) 2008 Andy Walls <[email protected]>
8
*
9
* This program is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License as published by
11
* the Free Software Foundation; either version 2 of the License, or
12
* (at your option) any later version.
13
*
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
18
*
19
* You should have received a copy of the GNU General Public License
20
* along with this program; if not, write to the Free Software
21
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
22
* 02111-1307 USA
23
*/
24
25
#include "cx18-driver.h"
26
#include "cx18-io.h"
27
#include "cx18-version.h"
28
#include "cx18-mailbox.h"
29
#include "cx18-i2c.h"
30
#include "cx18-queue.h"
31
#include "cx18-fileops.h"
32
#include "cx18-vbi.h"
33
#include "cx18-audio.h"
34
#include "cx18-video.h"
35
#include "cx18-streams.h"
36
#include "cx18-ioctl.h"
37
#include "cx18-gpio.h"
38
#include "cx18-controls.h"
39
#include "cx18-cards.h"
40
#include "cx18-av-core.h"
41
#include <media/tveeprom.h>
42
#include <media/v4l2-chip-ident.h>
43
44
u16 cx18_service2vbi(int type)
45
{
46
switch (type) {
47
case V4L2_SLICED_TELETEXT_B:
48
return CX18_SLICED_TYPE_TELETEXT_B;
49
case V4L2_SLICED_CAPTION_525:
50
return CX18_SLICED_TYPE_CAPTION_525;
51
case V4L2_SLICED_WSS_625:
52
return CX18_SLICED_TYPE_WSS_625;
53
case V4L2_SLICED_VPS:
54
return CX18_SLICED_TYPE_VPS;
55
default:
56
return 0;
57
}
58
}
59
60
/* Check if VBI services are allowed on the (field, line) for the video std */
61
static int valid_service_line(int field, int line, int is_pal)
62
{
63
return (is_pal && line >= 6 &&
64
((field == 0 && line <= 23) || (field == 1 && line <= 22))) ||
65
(!is_pal && line >= 10 && line < 22);
66
}
67
68
/*
69
* For a (field, line, std) and inbound potential set of services for that line,
70
* return the first valid service of those passed in the incoming set for that
71
* line in priority order:
72
* CC, VPS, or WSS over TELETEXT for well known lines
73
* TELETEXT, before VPS, before CC, before WSS, for other lines
74
*/
75
static u16 select_service_from_set(int field, int line, u16 set, int is_pal)
76
{
77
u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525);
78
int i;
79
80
set = set & valid_set;
81
if (set == 0 || !valid_service_line(field, line, is_pal))
82
return 0;
83
if (!is_pal) {
84
if (line == 21 && (set & V4L2_SLICED_CAPTION_525))
85
return V4L2_SLICED_CAPTION_525;
86
} else {
87
if (line == 16 && field == 0 && (set & V4L2_SLICED_VPS))
88
return V4L2_SLICED_VPS;
89
if (line == 23 && field == 0 && (set & V4L2_SLICED_WSS_625))
90
return V4L2_SLICED_WSS_625;
91
if (line == 23)
92
return 0;
93
}
94
for (i = 0; i < 32; i++) {
95
if ((1 << i) & set)
96
return 1 << i;
97
}
98
return 0;
99
}
100
101
/*
102
* Expand the service_set of *fmt into valid service_lines for the std,
103
* and clear the passed in fmt->service_set
104
*/
105
void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
106
{
107
u16 set = fmt->service_set;
108
int f, l;
109
110
fmt->service_set = 0;
111
for (f = 0; f < 2; f++) {
112
for (l = 0; l < 24; l++)
113
fmt->service_lines[f][l] = select_service_from_set(f, l, set, is_pal);
114
}
115
}
116
117
/*
118
* Sanitize the service_lines in *fmt per the video std, and return 1
119
* if any service_line is left as valid after santization
120
*/
121
static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
122
{
123
int f, l;
124
u16 set = 0;
125
126
for (f = 0; f < 2; f++) {
127
for (l = 0; l < 24; l++) {
128
fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal);
129
set |= fmt->service_lines[f][l];
130
}
131
}
132
return set != 0;
133
}
134
135
/* Compute the service_set from the assumed valid service_lines of *fmt */
136
u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt)
137
{
138
int f, l;
139
u16 set = 0;
140
141
for (f = 0; f < 2; f++) {
142
for (l = 0; l < 24; l++)
143
set |= fmt->service_lines[f][l];
144
}
145
return set;
146
}
147
148
static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
149
struct v4l2_format *fmt)
150
{
151
struct cx18_open_id *id = fh2id(fh);
152
struct cx18 *cx = id->cx;
153
struct cx18_stream *s = &cx->streams[id->type];
154
struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
155
156
pixfmt->width = cx->cxhdl.width;
157
pixfmt->height = cx->cxhdl.height;
158
pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
159
pixfmt->field = V4L2_FIELD_INTERLACED;
160
pixfmt->priv = 0;
161
if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
162
pixfmt->pixelformat = s->pixelformat;
163
/* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
164
UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */
165
if (s->pixelformat == V4L2_PIX_FMT_HM12)
166
pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2;
167
else
168
pixfmt->sizeimage = pixfmt->height * 720 * 2;
169
pixfmt->bytesperline = 720;
170
} else {
171
pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
172
pixfmt->sizeimage = 128 * 1024;
173
pixfmt->bytesperline = 0;
174
}
175
return 0;
176
}
177
178
static int cx18_g_fmt_vbi_cap(struct file *file, void *fh,
179
struct v4l2_format *fmt)
180
{
181
struct cx18 *cx = fh2id(fh)->cx;
182
struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi;
183
184
vbifmt->sampling_rate = 27000000;
185
vbifmt->offset = 248; /* FIXME - slightly wrong for both 50 & 60 Hz */
186
vbifmt->samples_per_line = vbi_active_samples - 4;
187
vbifmt->sample_format = V4L2_PIX_FMT_GREY;
188
vbifmt->start[0] = cx->vbi.start[0];
189
vbifmt->start[1] = cx->vbi.start[1];
190
vbifmt->count[0] = vbifmt->count[1] = cx->vbi.count;
191
vbifmt->flags = 0;
192
vbifmt->reserved[0] = 0;
193
vbifmt->reserved[1] = 0;
194
return 0;
195
}
196
197
static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh,
198
struct v4l2_format *fmt)
199
{
200
struct cx18 *cx = fh2id(fh)->cx;
201
struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
202
203
/* sane, V4L2 spec compliant, defaults */
204
vbifmt->reserved[0] = 0;
205
vbifmt->reserved[1] = 0;
206
vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
207
memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
208
vbifmt->service_set = 0;
209
210
/*
211
* Fetch the configured service_lines and total service_set from the
212
* digitizer/slicer. Note, cx18_av_vbi() wipes the passed in
213
* fmt->fmt.sliced under valid calling conditions
214
*/
215
if (v4l2_subdev_call(cx->sd_av, vbi, g_sliced_fmt, &fmt->fmt.sliced))
216
return -EINVAL;
217
218
/* Ensure V4L2 spec compliant output */
219
vbifmt->reserved[0] = 0;
220
vbifmt->reserved[1] = 0;
221
vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
222
vbifmt->service_set = cx18_get_service_set(vbifmt);
223
return 0;
224
}
225
226
static int cx18_try_fmt_vid_cap(struct file *file, void *fh,
227
struct v4l2_format *fmt)
228
{
229
struct cx18_open_id *id = fh2id(fh);
230
struct cx18 *cx = id->cx;
231
int w = fmt->fmt.pix.width;
232
int h = fmt->fmt.pix.height;
233
int min_h = 2;
234
235
w = min(w, 720);
236
w = max(w, 2);
237
if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
238
/* YUV height must be a multiple of 32 */
239
h &= ~0x1f;
240
min_h = 32;
241
}
242
h = min(h, cx->is_50hz ? 576 : 480);
243
h = max(h, min_h);
244
245
fmt->fmt.pix.width = w;
246
fmt->fmt.pix.height = h;
247
return 0;
248
}
249
250
static int cx18_try_fmt_vbi_cap(struct file *file, void *fh,
251
struct v4l2_format *fmt)
252
{
253
return cx18_g_fmt_vbi_cap(file, fh, fmt);
254
}
255
256
static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh,
257
struct v4l2_format *fmt)
258
{
259
struct cx18 *cx = fh2id(fh)->cx;
260
struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
261
262
vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
263
vbifmt->reserved[0] = 0;
264
vbifmt->reserved[1] = 0;
265
266
/* If given a service set, expand it validly & clear passed in set */
267
if (vbifmt->service_set)
268
cx18_expand_service_set(vbifmt, cx->is_50hz);
269
/* Sanitize the service_lines, and compute the new set if any valid */
270
if (check_service_set(vbifmt, cx->is_50hz))
271
vbifmt->service_set = cx18_get_service_set(vbifmt);
272
return 0;
273
}
274
275
static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
276
struct v4l2_format *fmt)
277
{
278
struct cx18_open_id *id = fh2id(fh);
279
struct cx18 *cx = id->cx;
280
struct v4l2_mbus_framefmt mbus_fmt;
281
struct cx18_stream *s = &cx->streams[id->type];
282
int ret;
283
int w, h;
284
285
ret = cx18_try_fmt_vid_cap(file, fh, fmt);
286
if (ret)
287
return ret;
288
w = fmt->fmt.pix.width;
289
h = fmt->fmt.pix.height;
290
291
if (cx->cxhdl.width == w && cx->cxhdl.height == h &&
292
s->pixelformat == fmt->fmt.pix.pixelformat)
293
return 0;
294
295
if (atomic_read(&cx->ana_capturing) > 0)
296
return -EBUSY;
297
298
s->pixelformat = fmt->fmt.pix.pixelformat;
299
300
mbus_fmt.width = cx->cxhdl.width = w;
301
mbus_fmt.height = cx->cxhdl.height = h;
302
mbus_fmt.code = V4L2_MBUS_FMT_FIXED;
303
v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &mbus_fmt);
304
return cx18_g_fmt_vid_cap(file, fh, fmt);
305
}
306
307
static int cx18_s_fmt_vbi_cap(struct file *file, void *fh,
308
struct v4l2_format *fmt)
309
{
310
struct cx18_open_id *id = fh2id(fh);
311
struct cx18 *cx = id->cx;
312
int ret;
313
314
/*
315
* Changing the Encoder's Raw VBI parameters won't have any effect
316
* if any analog capture is ongoing
317
*/
318
if (!cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0)
319
return -EBUSY;
320
321
/*
322
* Set the digitizer registers for raw active VBI.
323
* Note cx18_av_vbi_wipes out a lot of the passed in fmt under valid
324
* calling conditions
325
*/
326
ret = v4l2_subdev_call(cx->sd_av, vbi, s_raw_fmt, &fmt->fmt.vbi);
327
if (ret)
328
return ret;
329
330
/* Store our new v4l2 (non-)sliced VBI state */
331
cx->vbi.sliced_in->service_set = 0;
332
cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
333
334
return cx18_g_fmt_vbi_cap(file, fh, fmt);
335
}
336
337
static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh,
338
struct v4l2_format *fmt)
339
{
340
struct cx18_open_id *id = fh2id(fh);
341
struct cx18 *cx = id->cx;
342
int ret;
343
struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
344
345
cx18_try_fmt_sliced_vbi_cap(file, fh, fmt);
346
347
/*
348
* Changing the Encoder's Raw VBI parameters won't have any effect
349
* if any analog capture is ongoing
350
*/
351
if (cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0)
352
return -EBUSY;
353
354
/*
355
* Set the service_lines requested in the digitizer/slicer registers.
356
* Note, cx18_av_vbi() wipes some "impossible" service lines in the
357
* passed in fmt->fmt.sliced under valid calling conditions
358
*/
359
ret = v4l2_subdev_call(cx->sd_av, vbi, s_sliced_fmt, &fmt->fmt.sliced);
360
if (ret)
361
return ret;
362
/* Store our current v4l2 sliced VBI settings */
363
cx->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
364
memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in));
365
return 0;
366
}
367
368
static int cx18_g_chip_ident(struct file *file, void *fh,
369
struct v4l2_dbg_chip_ident *chip)
370
{
371
struct cx18 *cx = fh2id(fh)->cx;
372
int err = 0;
373
374
chip->ident = V4L2_IDENT_NONE;
375
chip->revision = 0;
376
switch (chip->match.type) {
377
case V4L2_CHIP_MATCH_HOST:
378
switch (chip->match.addr) {
379
case 0:
380
chip->ident = V4L2_IDENT_CX23418;
381
chip->revision = cx18_read_reg(cx, 0xC72028);
382
break;
383
case 1:
384
/*
385
* The A/V decoder is always present, but in the rare
386
* case that the card doesn't have analog, we don't
387
* use it. We find it w/o using the cx->sd_av pointer
388
*/
389
cx18_call_hw(cx, CX18_HW_418_AV,
390
core, g_chip_ident, chip);
391
break;
392
default:
393
/*
394
* Could return ident = V4L2_IDENT_UNKNOWN if we had
395
* other host chips at higher addresses, but we don't
396
*/
397
err = -EINVAL; /* per V4L2 spec */
398
break;
399
}
400
break;
401
case V4L2_CHIP_MATCH_I2C_DRIVER:
402
/* If needed, returns V4L2_IDENT_AMBIGUOUS without extra work */
403
cx18_call_all(cx, core, g_chip_ident, chip);
404
break;
405
case V4L2_CHIP_MATCH_I2C_ADDR:
406
/*
407
* We could return V4L2_IDENT_UNKNOWN, but we don't do the work
408
* to look if a chip is at the address with no driver. That's a
409
* dangerous thing to do with EEPROMs anyway.
410
*/
411
cx18_call_all(cx, core, g_chip_ident, chip);
412
break;
413
default:
414
err = -EINVAL;
415
break;
416
}
417
return err;
418
}
419
420
#ifdef CONFIG_VIDEO_ADV_DEBUG
421
static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg)
422
{
423
struct v4l2_dbg_register *regs = arg;
424
425
if (!capable(CAP_SYS_ADMIN))
426
return -EPERM;
427
if (regs->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
428
return -EINVAL;
429
430
regs->size = 4;
431
if (cmd == VIDIOC_DBG_S_REGISTER)
432
cx18_write_enc(cx, regs->val, regs->reg);
433
else
434
regs->val = cx18_read_enc(cx, regs->reg);
435
return 0;
436
}
437
438
static int cx18_g_register(struct file *file, void *fh,
439
struct v4l2_dbg_register *reg)
440
{
441
struct cx18 *cx = fh2id(fh)->cx;
442
443
if (v4l2_chip_match_host(&reg->match))
444
return cx18_cxc(cx, VIDIOC_DBG_G_REGISTER, reg);
445
/* FIXME - errors shouldn't be ignored */
446
cx18_call_all(cx, core, g_register, reg);
447
return 0;
448
}
449
450
static int cx18_s_register(struct file *file, void *fh,
451
struct v4l2_dbg_register *reg)
452
{
453
struct cx18 *cx = fh2id(fh)->cx;
454
455
if (v4l2_chip_match_host(&reg->match))
456
return cx18_cxc(cx, VIDIOC_DBG_S_REGISTER, reg);
457
/* FIXME - errors shouldn't be ignored */
458
cx18_call_all(cx, core, s_register, reg);
459
return 0;
460
}
461
#endif
462
463
static int cx18_querycap(struct file *file, void *fh,
464
struct v4l2_capability *vcap)
465
{
466
struct cx18 *cx = fh2id(fh)->cx;
467
468
strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
469
strlcpy(vcap->card, cx->card_name, sizeof(vcap->card));
470
snprintf(vcap->bus_info, sizeof(vcap->bus_info),
471
"PCI:%s", pci_name(cx->pci_dev));
472
vcap->version = CX18_DRIVER_VERSION; /* version */
473
vcap->capabilities = cx->v4l2_cap; /* capabilities */
474
return 0;
475
}
476
477
static int cx18_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin)
478
{
479
struct cx18 *cx = fh2id(fh)->cx;
480
481
return cx18_get_audio_input(cx, vin->index, vin);
482
}
483
484
static int cx18_g_audio(struct file *file, void *fh, struct v4l2_audio *vin)
485
{
486
struct cx18 *cx = fh2id(fh)->cx;
487
488
vin->index = cx->audio_input;
489
return cx18_get_audio_input(cx, vin->index, vin);
490
}
491
492
static int cx18_s_audio(struct file *file, void *fh, struct v4l2_audio *vout)
493
{
494
struct cx18 *cx = fh2id(fh)->cx;
495
496
if (vout->index >= cx->nof_audio_inputs)
497
return -EINVAL;
498
cx->audio_input = vout->index;
499
cx18_audio_set_io(cx);
500
return 0;
501
}
502
503
static int cx18_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
504
{
505
struct cx18 *cx = fh2id(fh)->cx;
506
507
/* set it to defaults from our table */
508
return cx18_get_input(cx, vin->index, vin);
509
}
510
511
static int cx18_cropcap(struct file *file, void *fh,
512
struct v4l2_cropcap *cropcap)
513
{
514
struct cx18 *cx = fh2id(fh)->cx;
515
516
if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
517
return -EINVAL;
518
cropcap->bounds.top = cropcap->bounds.left = 0;
519
cropcap->bounds.width = 720;
520
cropcap->bounds.height = cx->is_50hz ? 576 : 480;
521
cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10;
522
cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11;
523
cropcap->defrect = cropcap->bounds;
524
return 0;
525
}
526
527
static int cx18_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
528
{
529
struct cx18_open_id *id = fh2id(fh);
530
struct cx18 *cx = id->cx;
531
532
if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
533
return -EINVAL;
534
CX18_DEBUG_WARN("VIDIOC_S_CROP not implemented\n");
535
return -EINVAL;
536
}
537
538
static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
539
{
540
struct cx18 *cx = fh2id(fh)->cx;
541
542
if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
543
return -EINVAL;
544
CX18_DEBUG_WARN("VIDIOC_G_CROP not implemented\n");
545
return -EINVAL;
546
}
547
548
static int cx18_enum_fmt_vid_cap(struct file *file, void *fh,
549
struct v4l2_fmtdesc *fmt)
550
{
551
static const struct v4l2_fmtdesc formats[] = {
552
{ 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0,
553
"HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 }
554
},
555
{ 1, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FMT_FLAG_COMPRESSED,
556
"MPEG", V4L2_PIX_FMT_MPEG, { 0, 0, 0, 0 }
557
},
558
{ 2, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0,
559
"UYVY 4:2:2", V4L2_PIX_FMT_UYVY, { 0, 0, 0, 0 }
560
},
561
};
562
563
if (fmt->index > ARRAY_SIZE(formats) - 1)
564
return -EINVAL;
565
*fmt = formats[fmt->index];
566
return 0;
567
}
568
569
static int cx18_g_input(struct file *file, void *fh, unsigned int *i)
570
{
571
struct cx18 *cx = fh2id(fh)->cx;
572
573
*i = cx->active_input;
574
return 0;
575
}
576
577
int cx18_s_input(struct file *file, void *fh, unsigned int inp)
578
{
579
struct cx18_open_id *id = fh2id(fh);
580
struct cx18 *cx = id->cx;
581
582
if (inp >= cx->nof_inputs)
583
return -EINVAL;
584
585
if (inp == cx->active_input) {
586
CX18_DEBUG_INFO("Input unchanged\n");
587
return 0;
588
}
589
590
CX18_DEBUG_INFO("Changing input from %d to %d\n",
591
cx->active_input, inp);
592
593
cx->active_input = inp;
594
/* Set the audio input to whatever is appropriate for the input type. */
595
cx->audio_input = cx->card->video_inputs[inp].audio_index;
596
597
/* prevent others from messing with the streams until
598
we're finished changing inputs. */
599
cx18_mute(cx);
600
cx18_video_set_io(cx);
601
cx18_audio_set_io(cx);
602
cx18_unmute(cx);
603
return 0;
604
}
605
606
static int cx18_g_frequency(struct file *file, void *fh,
607
struct v4l2_frequency *vf)
608
{
609
struct cx18 *cx = fh2id(fh)->cx;
610
611
if (vf->tuner != 0)
612
return -EINVAL;
613
614
cx18_call_all(cx, tuner, g_frequency, vf);
615
return 0;
616
}
617
618
int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
619
{
620
struct cx18_open_id *id = fh2id(fh);
621
struct cx18 *cx = id->cx;
622
623
if (vf->tuner != 0)
624
return -EINVAL;
625
626
cx18_mute(cx);
627
CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency);
628
cx18_call_all(cx, tuner, s_frequency, vf);
629
cx18_unmute(cx);
630
return 0;
631
}
632
633
static int cx18_g_std(struct file *file, void *fh, v4l2_std_id *std)
634
{
635
struct cx18 *cx = fh2id(fh)->cx;
636
637
*std = cx->std;
638
return 0;
639
}
640
641
int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std)
642
{
643
struct cx18_open_id *id = fh2id(fh);
644
struct cx18 *cx = id->cx;
645
646
if ((*std & V4L2_STD_ALL) == 0)
647
return -EINVAL;
648
649
if (*std == cx->std)
650
return 0;
651
652
if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ||
653
atomic_read(&cx->ana_capturing) > 0) {
654
/* Switching standard would turn off the radio or mess
655
with already running streams, prevent that by
656
returning EBUSY. */
657
return -EBUSY;
658
}
659
660
cx->std = *std;
661
cx->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0;
662
cx->is_50hz = !cx->is_60hz;
663
cx2341x_handler_set_50hz(&cx->cxhdl, cx->is_50hz);
664
cx->cxhdl.width = 720;
665
cx->cxhdl.height = cx->is_50hz ? 576 : 480;
666
cx->vbi.count = cx->is_50hz ? 18 : 12;
667
cx->vbi.start[0] = cx->is_50hz ? 6 : 10;
668
cx->vbi.start[1] = cx->is_50hz ? 318 : 273;
669
CX18_DEBUG_INFO("Switching standard to %llx.\n",
670
(unsigned long long) cx->std);
671
672
/* Tuner */
673
cx18_call_all(cx, core, s_std, cx->std);
674
return 0;
675
}
676
677
static int cx18_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
678
{
679
struct cx18_open_id *id = fh2id(fh);
680
struct cx18 *cx = id->cx;
681
682
if (vt->index != 0)
683
return -EINVAL;
684
685
cx18_call_all(cx, tuner, s_tuner, vt);
686
return 0;
687
}
688
689
static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
690
{
691
struct cx18 *cx = fh2id(fh)->cx;
692
693
if (vt->index != 0)
694
return -EINVAL;
695
696
cx18_call_all(cx, tuner, g_tuner, vt);
697
698
if (vt->type == V4L2_TUNER_RADIO)
699
strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name));
700
else
701
strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name));
702
return 0;
703
}
704
705
static int cx18_g_sliced_vbi_cap(struct file *file, void *fh,
706
struct v4l2_sliced_vbi_cap *cap)
707
{
708
struct cx18 *cx = fh2id(fh)->cx;
709
int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
710
int f, l;
711
712
if (cap->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
713
return -EINVAL;
714
715
cap->service_set = 0;
716
for (f = 0; f < 2; f++) {
717
for (l = 0; l < 24; l++) {
718
if (valid_service_line(f, l, cx->is_50hz)) {
719
/*
720
* We can find all v4l2 supported vbi services
721
* for the standard, on a valid line for the std
722
*/
723
cap->service_lines[f][l] = set;
724
cap->service_set |= set;
725
} else
726
cap->service_lines[f][l] = 0;
727
}
728
}
729
for (f = 0; f < 3; f++)
730
cap->reserved[f] = 0;
731
return 0;
732
}
733
734
static int _cx18_process_idx_data(struct cx18_buffer *buf,
735
struct v4l2_enc_idx *idx)
736
{
737
int consumed, remaining;
738
struct v4l2_enc_idx_entry *e_idx;
739
struct cx18_enc_idx_entry *e_buf;
740
741
/* Frame type lookup: 1=I, 2=P, 4=B */
742
const int mapping[8] = {
743
-1, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_P,
744
-1, V4L2_ENC_IDX_FRAME_B, -1, -1, -1
745
};
746
747
/*
748
* Assumption here is that a buf holds an integral number of
749
* struct cx18_enc_idx_entry objects and is properly aligned.
750
* This is enforced by the module options on IDX buffer sizes.
751
*/
752
remaining = buf->bytesused - buf->readpos;
753
consumed = 0;
754
e_idx = &idx->entry[idx->entries];
755
e_buf = (struct cx18_enc_idx_entry *) &buf->buf[buf->readpos];
756
757
while (remaining >= sizeof(struct cx18_enc_idx_entry) &&
758
idx->entries < V4L2_ENC_IDX_ENTRIES) {
759
760
e_idx->offset = (((u64) le32_to_cpu(e_buf->offset_high)) << 32)
761
| le32_to_cpu(e_buf->offset_low);
762
763
e_idx->pts = (((u64) (le32_to_cpu(e_buf->pts_high) & 1)) << 32)
764
| le32_to_cpu(e_buf->pts_low);
765
766
e_idx->length = le32_to_cpu(e_buf->length);
767
768
e_idx->flags = mapping[le32_to_cpu(e_buf->flags) & 0x7];
769
770
e_idx->reserved[0] = 0;
771
e_idx->reserved[1] = 0;
772
773
idx->entries++;
774
e_idx = &idx->entry[idx->entries];
775
e_buf++;
776
777
remaining -= sizeof(struct cx18_enc_idx_entry);
778
consumed += sizeof(struct cx18_enc_idx_entry);
779
}
780
781
/* Swallow any partial entries at the end, if there are any */
782
if (remaining > 0 && remaining < sizeof(struct cx18_enc_idx_entry))
783
consumed += remaining;
784
785
buf->readpos += consumed;
786
return consumed;
787
}
788
789
static int cx18_process_idx_data(struct cx18_stream *s, struct cx18_mdl *mdl,
790
struct v4l2_enc_idx *idx)
791
{
792
if (s->type != CX18_ENC_STREAM_TYPE_IDX)
793
return -EINVAL;
794
795
if (mdl->curr_buf == NULL)
796
mdl->curr_buf = list_first_entry(&mdl->buf_list,
797
struct cx18_buffer, list);
798
799
if (list_entry_is_past_end(mdl->curr_buf, &mdl->buf_list, list)) {
800
/*
801
* For some reason we've exhausted the buffers, but the MDL
802
* object still said some data was unread.
803
* Fix that and bail out.
804
*/
805
mdl->readpos = mdl->bytesused;
806
return 0;
807
}
808
809
list_for_each_entry_from(mdl->curr_buf, &mdl->buf_list, list) {
810
811
/* Skip any empty buffers in the MDL */
812
if (mdl->curr_buf->readpos >= mdl->curr_buf->bytesused)
813
continue;
814
815
mdl->readpos += _cx18_process_idx_data(mdl->curr_buf, idx);
816
817
/* exit when MDL drained or request satisfied */
818
if (idx->entries >= V4L2_ENC_IDX_ENTRIES ||
819
mdl->curr_buf->readpos < mdl->curr_buf->bytesused ||
820
mdl->readpos >= mdl->bytesused)
821
break;
822
}
823
return 0;
824
}
825
826
static int cx18_g_enc_index(struct file *file, void *fh,
827
struct v4l2_enc_idx *idx)
828
{
829
struct cx18 *cx = fh2id(fh)->cx;
830
struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];
831
s32 tmp;
832
struct cx18_mdl *mdl;
833
834
if (!cx18_stream_enabled(s)) /* Module options inhibited IDX stream */
835
return -EINVAL;
836
837
/* Compute the best case number of entries we can buffer */
838
tmp = s->buffers -
839
s->bufs_per_mdl * CX18_ENC_STREAM_TYPE_IDX_FW_MDL_MIN;
840
if (tmp <= 0)
841
tmp = 1;
842
tmp = tmp * s->buf_size / sizeof(struct cx18_enc_idx_entry);
843
844
/* Fill out the header of the return structure */
845
idx->entries = 0;
846
idx->entries_cap = tmp;
847
memset(idx->reserved, 0, sizeof(idx->reserved));
848
849
/* Pull IDX MDLs and buffers from q_full and populate the entries */
850
do {
851
mdl = cx18_dequeue(s, &s->q_full);
852
if (mdl == NULL) /* No more IDX data right now */
853
break;
854
855
/* Extract the Index entry data from the MDL and buffers */
856
cx18_process_idx_data(s, mdl, idx);
857
if (mdl->readpos < mdl->bytesused) {
858
/* We finished with data remaining, push the MDL back */
859
cx18_push(s, mdl, &s->q_full);
860
break;
861
}
862
863
/* We drained this MDL, schedule it to go to the firmware */
864
cx18_enqueue(s, mdl, &s->q_free);
865
866
} while (idx->entries < V4L2_ENC_IDX_ENTRIES);
867
868
/* Tell the work handler to send free IDX MDLs to the firmware */
869
cx18_stream_load_fw_queue(s);
870
return 0;
871
}
872
873
static struct videobuf_queue *cx18_vb_queue(struct cx18_open_id *id)
874
{
875
struct videobuf_queue *q = NULL;
876
struct cx18 *cx = id->cx;
877
struct cx18_stream *s = &cx->streams[id->type];
878
879
switch (s->vb_type) {
880
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
881
q = &s->vbuf_q;
882
break;
883
case V4L2_BUF_TYPE_VBI_CAPTURE:
884
break;
885
default:
886
break;
887
}
888
return q;
889
}
890
891
static int cx18_streamon(struct file *file, void *priv,
892
enum v4l2_buf_type type)
893
{
894
struct cx18_open_id *id = file->private_data;
895
struct cx18 *cx = id->cx;
896
struct cx18_stream *s = &cx->streams[id->type];
897
898
/* Start the hardware only if we're the video device */
899
if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
900
(s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
901
return -EINVAL;
902
903
if (id->type != CX18_ENC_STREAM_TYPE_YUV)
904
return -EINVAL;
905
906
/* Establish a buffer timeout */
907
mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies);
908
909
return videobuf_streamon(cx18_vb_queue(id));
910
}
911
912
static int cx18_streamoff(struct file *file, void *priv,
913
enum v4l2_buf_type type)
914
{
915
struct cx18_open_id *id = file->private_data;
916
struct cx18 *cx = id->cx;
917
struct cx18_stream *s = &cx->streams[id->type];
918
919
/* Start the hardware only if we're the video device */
920
if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
921
(s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
922
return -EINVAL;
923
924
if (id->type != CX18_ENC_STREAM_TYPE_YUV)
925
return -EINVAL;
926
927
return videobuf_streamoff(cx18_vb_queue(id));
928
}
929
930
static int cx18_reqbufs(struct file *file, void *priv,
931
struct v4l2_requestbuffers *rb)
932
{
933
struct cx18_open_id *id = file->private_data;
934
struct cx18 *cx = id->cx;
935
struct cx18_stream *s = &cx->streams[id->type];
936
937
if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
938
(s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
939
return -EINVAL;
940
941
return videobuf_reqbufs(cx18_vb_queue(id), rb);
942
}
943
944
static int cx18_querybuf(struct file *file, void *priv,
945
struct v4l2_buffer *b)
946
{
947
struct cx18_open_id *id = file->private_data;
948
struct cx18 *cx = id->cx;
949
struct cx18_stream *s = &cx->streams[id->type];
950
951
if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
952
(s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
953
return -EINVAL;
954
955
return videobuf_querybuf(cx18_vb_queue(id), b);
956
}
957
958
static int cx18_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
959
{
960
struct cx18_open_id *id = file->private_data;
961
struct cx18 *cx = id->cx;
962
struct cx18_stream *s = &cx->streams[id->type];
963
964
if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
965
(s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
966
return -EINVAL;
967
968
return videobuf_qbuf(cx18_vb_queue(id), b);
969
}
970
971
static int cx18_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
972
{
973
struct cx18_open_id *id = file->private_data;
974
struct cx18 *cx = id->cx;
975
struct cx18_stream *s = &cx->streams[id->type];
976
977
if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
978
(s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
979
return -EINVAL;
980
981
return videobuf_dqbuf(cx18_vb_queue(id), b, file->f_flags & O_NONBLOCK);
982
}
983
984
static int cx18_encoder_cmd(struct file *file, void *fh,
985
struct v4l2_encoder_cmd *enc)
986
{
987
struct cx18_open_id *id = fh2id(fh);
988
struct cx18 *cx = id->cx;
989
u32 h;
990
991
switch (enc->cmd) {
992
case V4L2_ENC_CMD_START:
993
CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
994
enc->flags = 0;
995
return cx18_start_capture(id);
996
997
case V4L2_ENC_CMD_STOP:
998
CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
999
enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
1000
cx18_stop_capture(id,
1001
enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
1002
break;
1003
1004
case V4L2_ENC_CMD_PAUSE:
1005
CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
1006
enc->flags = 0;
1007
if (!atomic_read(&cx->ana_capturing))
1008
return -EPERM;
1009
if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
1010
return 0;
1011
h = cx18_find_handle(cx);
1012
if (h == CX18_INVALID_TASK_HANDLE) {
1013
CX18_ERR("Can't find valid task handle for "
1014
"V4L2_ENC_CMD_PAUSE\n");
1015
return -EBADFD;
1016
}
1017
cx18_mute(cx);
1018
cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, h);
1019
break;
1020
1021
case V4L2_ENC_CMD_RESUME:
1022
CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
1023
enc->flags = 0;
1024
if (!atomic_read(&cx->ana_capturing))
1025
return -EPERM;
1026
if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
1027
return 0;
1028
h = cx18_find_handle(cx);
1029
if (h == CX18_INVALID_TASK_HANDLE) {
1030
CX18_ERR("Can't find valid task handle for "
1031
"V4L2_ENC_CMD_RESUME\n");
1032
return -EBADFD;
1033
}
1034
cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, h);
1035
cx18_unmute(cx);
1036
break;
1037
1038
default:
1039
CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
1040
return -EINVAL;
1041
}
1042
return 0;
1043
}
1044
1045
static int cx18_try_encoder_cmd(struct file *file, void *fh,
1046
struct v4l2_encoder_cmd *enc)
1047
{
1048
struct cx18 *cx = fh2id(fh)->cx;
1049
1050
switch (enc->cmd) {
1051
case V4L2_ENC_CMD_START:
1052
CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
1053
enc->flags = 0;
1054
break;
1055
1056
case V4L2_ENC_CMD_STOP:
1057
CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
1058
enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
1059
break;
1060
1061
case V4L2_ENC_CMD_PAUSE:
1062
CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
1063
enc->flags = 0;
1064
break;
1065
1066
case V4L2_ENC_CMD_RESUME:
1067
CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
1068
enc->flags = 0;
1069
break;
1070
1071
default:
1072
CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
1073
return -EINVAL;
1074
}
1075
return 0;
1076
}
1077
1078
static int cx18_log_status(struct file *file, void *fh)
1079
{
1080
struct cx18 *cx = fh2id(fh)->cx;
1081
struct v4l2_input vidin;
1082
struct v4l2_audio audin;
1083
int i;
1084
1085
CX18_INFO("================= START STATUS CARD #%d "
1086
"=================\n", cx->instance);
1087
CX18_INFO("Version: %s Card: %s\n", CX18_VERSION, cx->card_name);
1088
if (cx->hw_flags & CX18_HW_TVEEPROM) {
1089
struct tveeprom tv;
1090
1091
cx18_read_eeprom(cx, &tv);
1092
}
1093
cx18_call_all(cx, core, log_status);
1094
cx18_get_input(cx, cx->active_input, &vidin);
1095
cx18_get_audio_input(cx, cx->audio_input, &audin);
1096
CX18_INFO("Video Input: %s\n", vidin.name);
1097
CX18_INFO("Audio Input: %s\n", audin.name);
1098
mutex_lock(&cx->gpio_lock);
1099
CX18_INFO("GPIO: direction 0x%08x, value 0x%08x\n",
1100
cx->gpio_dir, cx->gpio_val);
1101
mutex_unlock(&cx->gpio_lock);
1102
CX18_INFO("Tuner: %s\n",
1103
test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ? "Radio" : "TV");
1104
v4l2_ctrl_handler_log_status(&cx->cxhdl.hdl, cx->v4l2_dev.name);
1105
CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags);
1106
for (i = 0; i < CX18_MAX_STREAMS; i++) {
1107
struct cx18_stream *s = &cx->streams[i];
1108
1109
if (s->video_dev == NULL || s->buffers == 0)
1110
continue;
1111
CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
1112
s->name, s->s_flags,
1113
atomic_read(&s->q_full.depth) * s->bufs_per_mdl * 100
1114
/ s->buffers,
1115
(s->buffers * s->buf_size) / 1024, s->buffers);
1116
}
1117
CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
1118
(long long)cx->mpg_data_received,
1119
(long long)cx->vbi_data_inserted);
1120
CX18_INFO("================== END STATUS CARD #%d "
1121
"==================\n", cx->instance);
1122
return 0;
1123
}
1124
1125
static long cx18_default(struct file *file, void *fh, bool valid_prio,
1126
int cmd, void *arg)
1127
{
1128
struct cx18 *cx = fh2id(fh)->cx;
1129
1130
switch (cmd) {
1131
case VIDIOC_INT_RESET: {
1132
u32 val = *(u32 *)arg;
1133
1134
if ((val == 0) || (val & 0x01))
1135
cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL, core, reset,
1136
(u32) CX18_GPIO_RESET_Z8F0811);
1137
break;
1138
}
1139
1140
default:
1141
return -EINVAL;
1142
}
1143
return 0;
1144
}
1145
1146
long cx18_v4l2_ioctl(struct file *filp, unsigned int cmd,
1147
unsigned long arg)
1148
{
1149
struct video_device *vfd = video_devdata(filp);
1150
struct cx18_open_id *id = file2id(filp);
1151
struct cx18 *cx = id->cx;
1152
long res;
1153
1154
mutex_lock(&cx->serialize_lock);
1155
1156
if (cx18_debug & CX18_DBGFLG_IOCTL)
1157
vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
1158
res = video_ioctl2(filp, cmd, arg);
1159
vfd->debug = 0;
1160
mutex_unlock(&cx->serialize_lock);
1161
return res;
1162
}
1163
1164
static const struct v4l2_ioctl_ops cx18_ioctl_ops = {
1165
.vidioc_querycap = cx18_querycap,
1166
.vidioc_s_audio = cx18_s_audio,
1167
.vidioc_g_audio = cx18_g_audio,
1168
.vidioc_enumaudio = cx18_enumaudio,
1169
.vidioc_enum_input = cx18_enum_input,
1170
.vidioc_cropcap = cx18_cropcap,
1171
.vidioc_s_crop = cx18_s_crop,
1172
.vidioc_g_crop = cx18_g_crop,
1173
.vidioc_g_input = cx18_g_input,
1174
.vidioc_s_input = cx18_s_input,
1175
.vidioc_g_frequency = cx18_g_frequency,
1176
.vidioc_s_frequency = cx18_s_frequency,
1177
.vidioc_s_tuner = cx18_s_tuner,
1178
.vidioc_g_tuner = cx18_g_tuner,
1179
.vidioc_g_enc_index = cx18_g_enc_index,
1180
.vidioc_g_std = cx18_g_std,
1181
.vidioc_s_std = cx18_s_std,
1182
.vidioc_log_status = cx18_log_status,
1183
.vidioc_enum_fmt_vid_cap = cx18_enum_fmt_vid_cap,
1184
.vidioc_encoder_cmd = cx18_encoder_cmd,
1185
.vidioc_try_encoder_cmd = cx18_try_encoder_cmd,
1186
.vidioc_g_fmt_vid_cap = cx18_g_fmt_vid_cap,
1187
.vidioc_g_fmt_vbi_cap = cx18_g_fmt_vbi_cap,
1188
.vidioc_g_fmt_sliced_vbi_cap = cx18_g_fmt_sliced_vbi_cap,
1189
.vidioc_s_fmt_vid_cap = cx18_s_fmt_vid_cap,
1190
.vidioc_s_fmt_vbi_cap = cx18_s_fmt_vbi_cap,
1191
.vidioc_s_fmt_sliced_vbi_cap = cx18_s_fmt_sliced_vbi_cap,
1192
.vidioc_try_fmt_vid_cap = cx18_try_fmt_vid_cap,
1193
.vidioc_try_fmt_vbi_cap = cx18_try_fmt_vbi_cap,
1194
.vidioc_try_fmt_sliced_vbi_cap = cx18_try_fmt_sliced_vbi_cap,
1195
.vidioc_g_sliced_vbi_cap = cx18_g_sliced_vbi_cap,
1196
.vidioc_g_chip_ident = cx18_g_chip_ident,
1197
#ifdef CONFIG_VIDEO_ADV_DEBUG
1198
.vidioc_g_register = cx18_g_register,
1199
.vidioc_s_register = cx18_s_register,
1200
#endif
1201
.vidioc_default = cx18_default,
1202
.vidioc_streamon = cx18_streamon,
1203
.vidioc_streamoff = cx18_streamoff,
1204
.vidioc_reqbufs = cx18_reqbufs,
1205
.vidioc_querybuf = cx18_querybuf,
1206
.vidioc_qbuf = cx18_qbuf,
1207
.vidioc_dqbuf = cx18_dqbuf,
1208
};
1209
1210
void cx18_set_funcs(struct video_device *vdev)
1211
{
1212
vdev->ioctl_ops = &cx18_ioctl_ops;
1213
}
1214
1215