Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
ac19ecc6 | 2 | * |
1da177e4 LT |
3 | * Video for Linux Two |
4 | * Backward Compatibility Layer | |
5 | * | |
6 | * Support subroutines for providing V4L2 drivers with backward | |
7 | * compatibility with applications using the old API. | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU General Public License | |
11 | * as published by the Free Software Foundation; either version | |
12 | * 2 of the License, or (at your option) any later version. | |
13 | * | |
43db48d3 | 14 | * Author: Bill Dirks <bill@thedirks.org> |
1da177e4 LT |
15 | * et al. |
16 | * | |
17 | */ | |
18 | ||
1da177e4 LT |
19 | |
20 | #include <linux/init.h> | |
21 | #include <linux/module.h> | |
22 | #include <linux/types.h> | |
23 | #include <linux/kernel.h> | |
24 | #include <linux/sched.h> | |
1da177e4 LT |
25 | #include <linux/mm.h> |
26 | #include <linux/fs.h> | |
27 | #include <linux/file.h> | |
28 | #include <linux/string.h> | |
29 | #include <linux/errno.h> | |
30 | #include <linux/slab.h> | |
31 | #include <linux/videodev.h> | |
5e87efa3 | 32 | #include <media/v4l2-common.h> |
1da177e4 LT |
33 | |
34 | #include <asm/uaccess.h> | |
35 | #include <asm/system.h> | |
36 | #include <asm/pgtable.h> | |
37 | ||
38 | #ifdef CONFIG_KMOD | |
39 | #include <linux/kmod.h> | |
40 | #endif | |
41 | ||
42 | static unsigned int debug = 0; | |
43 | module_param(debug, int, 0644); | |
44 | MODULE_PARM_DESC(debug,"enable debug messages"); | |
45 | MODULE_AUTHOR("Bill Dirks"); | |
46 | MODULE_DESCRIPTION("v4l(1) compatibility layer for v4l2 drivers."); | |
47 | MODULE_LICENSE("GPL"); | |
48 | ||
49 | #define dprintk(fmt, arg...) if (debug) \ | |
50 | printk(KERN_DEBUG "v4l1-compat: " fmt , ## arg) | |
51 | ||
52 | /* | |
53 | * I O C T L T R A N S L A T I O N | |
54 | * | |
55 | * From here on down is the code for translating the numerous | |
56 | * ioctl commands from the old API to the new API. | |
57 | */ | |
58 | ||
59 | static int | |
60 | get_v4l_control(struct inode *inode, | |
61 | struct file *file, | |
62 | int cid, | |
63 | v4l2_kioctl drv) | |
64 | { | |
65 | struct v4l2_queryctrl qctrl2; | |
66 | struct v4l2_control ctrl2; | |
67 | int err; | |
68 | ||
69 | qctrl2.id = cid; | |
70 | err = drv(inode, file, VIDIOC_QUERYCTRL, &qctrl2); | |
71 | if (err < 0) | |
72 | dprintk("VIDIOC_QUERYCTRL: %d\n",err); | |
73 | if (err == 0 && | |
74 | !(qctrl2.flags & V4L2_CTRL_FLAG_DISABLED)) | |
75 | { | |
76 | ctrl2.id = qctrl2.id; | |
77 | err = drv(inode, file, VIDIOC_G_CTRL, &ctrl2); | |
78 | if (err < 0) { | |
79 | dprintk("VIDIOC_G_CTRL: %d\n",err); | |
80 | return 0; | |
81 | } | |
82 | return ((ctrl2.value - qctrl2.minimum) * 65535 | |
83 | + (qctrl2.maximum - qctrl2.minimum) / 2) | |
84 | / (qctrl2.maximum - qctrl2.minimum); | |
85 | } | |
86 | return 0; | |
87 | } | |
88 | ||
89 | static int | |
90 | set_v4l_control(struct inode *inode, | |
91 | struct file *file, | |
92 | int cid, | |
93 | int value, | |
94 | v4l2_kioctl drv) | |
95 | { | |
96 | struct v4l2_queryctrl qctrl2; | |
97 | struct v4l2_control ctrl2; | |
98 | int err; | |
99 | ||
100 | qctrl2.id = cid; | |
101 | err = drv(inode, file, VIDIOC_QUERYCTRL, &qctrl2); | |
102 | if (err < 0) | |
103 | dprintk("VIDIOC_QUERYCTRL: %d\n",err); | |
104 | if (err == 0 && | |
105 | !(qctrl2.flags & V4L2_CTRL_FLAG_DISABLED) && | |
106 | !(qctrl2.flags & V4L2_CTRL_FLAG_GRABBED)) | |
107 | { | |
108 | if (value < 0) | |
109 | value = 0; | |
110 | if (value > 65535) | |
111 | value = 65535; | |
112 | if (value && qctrl2.type == V4L2_CTRL_TYPE_BOOLEAN) | |
113 | value = 65535; | |
114 | ctrl2.id = qctrl2.id; | |
115 | ctrl2.value = | |
116 | (value * (qctrl2.maximum - qctrl2.minimum) | |
117 | + 32767) | |
118 | / 65535; | |
119 | ctrl2.value += qctrl2.minimum; | |
120 | err = drv(inode, file, VIDIOC_S_CTRL, &ctrl2); | |
121 | if (err < 0) | |
122 | dprintk("VIDIOC_S_CTRL: %d\n",err); | |
123 | } | |
124 | return 0; | |
125 | } | |
126 | ||
127 | /* ----------------------------------------------------------------- */ | |
128 | ||
5f12491c | 129 | const static unsigned int palette2pixelformat[] = { |
1da177e4 LT |
130 | [VIDEO_PALETTE_GREY] = V4L2_PIX_FMT_GREY, |
131 | [VIDEO_PALETTE_RGB555] = V4L2_PIX_FMT_RGB555, | |
132 | [VIDEO_PALETTE_RGB565] = V4L2_PIX_FMT_RGB565, | |
133 | [VIDEO_PALETTE_RGB24] = V4L2_PIX_FMT_BGR24, | |
134 | [VIDEO_PALETTE_RGB32] = V4L2_PIX_FMT_BGR32, | |
135 | /* yuv packed pixel */ | |
136 | [VIDEO_PALETTE_YUYV] = V4L2_PIX_FMT_YUYV, | |
137 | [VIDEO_PALETTE_YUV422] = V4L2_PIX_FMT_YUYV, | |
138 | [VIDEO_PALETTE_UYVY] = V4L2_PIX_FMT_UYVY, | |
139 | /* yuv planar */ | |
140 | [VIDEO_PALETTE_YUV410P] = V4L2_PIX_FMT_YUV410, | |
141 | [VIDEO_PALETTE_YUV420] = V4L2_PIX_FMT_YUV420, | |
142 | [VIDEO_PALETTE_YUV420P] = V4L2_PIX_FMT_YUV420, | |
143 | [VIDEO_PALETTE_YUV411P] = V4L2_PIX_FMT_YUV411P, | |
144 | [VIDEO_PALETTE_YUV422P] = V4L2_PIX_FMT_YUV422P, | |
145 | }; | |
146 | ||
e8c44319 | 147 | static unsigned int __pure |
1da177e4 LT |
148 | palette_to_pixelformat(unsigned int palette) |
149 | { | |
150 | if (palette < ARRAY_SIZE(palette2pixelformat)) | |
151 | return palette2pixelformat[palette]; | |
152 | else | |
153 | return 0; | |
154 | } | |
155 | ||
5f12491c TP |
156 | static unsigned int __attribute_const__ |
157 | pixelformat_to_palette(unsigned int pixelformat) | |
1da177e4 LT |
158 | { |
159 | int palette = 0; | |
160 | switch (pixelformat) | |
161 | { | |
162 | case V4L2_PIX_FMT_GREY: | |
163 | palette = VIDEO_PALETTE_GREY; | |
164 | break; | |
165 | case V4L2_PIX_FMT_RGB555: | |
166 | palette = VIDEO_PALETTE_RGB555; | |
167 | break; | |
168 | case V4L2_PIX_FMT_RGB565: | |
169 | palette = VIDEO_PALETTE_RGB565; | |
170 | break; | |
171 | case V4L2_PIX_FMT_BGR24: | |
172 | palette = VIDEO_PALETTE_RGB24; | |
173 | break; | |
174 | case V4L2_PIX_FMT_BGR32: | |
175 | palette = VIDEO_PALETTE_RGB32; | |
176 | break; | |
177 | /* yuv packed pixel */ | |
178 | case V4L2_PIX_FMT_YUYV: | |
179 | palette = VIDEO_PALETTE_YUYV; | |
180 | break; | |
181 | case V4L2_PIX_FMT_UYVY: | |
182 | palette = VIDEO_PALETTE_UYVY; | |
183 | break; | |
184 | /* yuv planar */ | |
185 | case V4L2_PIX_FMT_YUV410: | |
186 | palette = VIDEO_PALETTE_YUV420; | |
187 | break; | |
188 | case V4L2_PIX_FMT_YUV420: | |
189 | palette = VIDEO_PALETTE_YUV420; | |
190 | break; | |
191 | case V4L2_PIX_FMT_YUV411P: | |
192 | palette = VIDEO_PALETTE_YUV411P; | |
193 | break; | |
194 | case V4L2_PIX_FMT_YUV422P: | |
195 | palette = VIDEO_PALETTE_YUV422P; | |
196 | break; | |
197 | } | |
198 | return palette; | |
199 | } | |
200 | ||
201 | /* ----------------------------------------------------------------- */ | |
202 | ||
203 | static int poll_one(struct file *file) | |
204 | { | |
205 | int retval = 1; | |
206 | poll_table *table; | |
207 | struct poll_wqueues pwq; | |
208 | ||
209 | poll_initwait(&pwq); | |
210 | table = &pwq.pt; | |
211 | for (;;) { | |
212 | int mask; | |
213 | set_current_state(TASK_INTERRUPTIBLE); | |
214 | mask = file->f_op->poll(file, table); | |
215 | if (mask & POLLIN) | |
216 | break; | |
217 | table = NULL; | |
218 | if (signal_pending(current)) { | |
219 | retval = -ERESTARTSYS; | |
220 | break; | |
221 | } | |
222 | schedule(); | |
223 | } | |
224 | set_current_state(TASK_RUNNING); | |
225 | poll_freewait(&pwq); | |
226 | return retval; | |
227 | } | |
228 | ||
229 | static int count_inputs(struct inode *inode, | |
230 | struct file *file, | |
231 | v4l2_kioctl drv) | |
232 | { | |
233 | struct v4l2_input input2; | |
234 | int i; | |
235 | ||
236 | for (i = 0;; i++) { | |
237 | memset(&input2,0,sizeof(input2)); | |
238 | input2.index = i; | |
239 | if (0 != drv(inode,file,VIDIOC_ENUMINPUT, &input2)) | |
240 | break; | |
241 | } | |
242 | return i; | |
243 | } | |
244 | ||
245 | static int check_size(struct inode *inode, | |
246 | struct file *file, | |
247 | v4l2_kioctl drv, | |
248 | int *maxw, int *maxh) | |
249 | { | |
250 | struct v4l2_fmtdesc desc2; | |
251 | struct v4l2_format fmt2; | |
252 | ||
253 | memset(&desc2,0,sizeof(desc2)); | |
254 | memset(&fmt2,0,sizeof(fmt2)); | |
255 | ||
256 | desc2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
257 | if (0 != drv(inode,file,VIDIOC_ENUM_FMT, &desc2)) | |
258 | goto done; | |
259 | ||
260 | fmt2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
261 | fmt2.fmt.pix.width = 10000; | |
262 | fmt2.fmt.pix.height = 10000; | |
263 | fmt2.fmt.pix.pixelformat = desc2.pixelformat; | |
264 | if (0 != drv(inode,file,VIDIOC_TRY_FMT, &fmt2)) | |
265 | goto done; | |
266 | ||
267 | *maxw = fmt2.fmt.pix.width; | |
268 | *maxh = fmt2.fmt.pix.height; | |
269 | ||
270 | done: | |
271 | return 0; | |
272 | } | |
273 | ||
274 | /* ----------------------------------------------------------------- */ | |
275 | ||
276 | /* | |
277 | * This function is exported. | |
278 | */ | |
279 | int | |
280 | v4l_compat_translate_ioctl(struct inode *inode, | |
281 | struct file *file, | |
282 | int cmd, | |
283 | void *arg, | |
284 | v4l2_kioctl drv) | |
285 | { | |
286 | struct v4l2_capability *cap2 = NULL; | |
287 | struct v4l2_format *fmt2 = NULL; | |
288 | enum v4l2_buf_type captype = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
289 | ||
290 | struct v4l2_framebuffer fbuf2; | |
291 | struct v4l2_input input2; | |
292 | struct v4l2_tuner tun2; | |
293 | struct v4l2_standard std2; | |
294 | struct v4l2_frequency freq2; | |
295 | struct v4l2_audio aud2; | |
296 | struct v4l2_queryctrl qctrl2; | |
297 | struct v4l2_buffer buf2; | |
298 | v4l2_std_id sid; | |
299 | int i, err = 0; | |
300 | ||
301 | switch (cmd) { | |
302 | case VIDIOCGCAP: /* capability */ | |
303 | { | |
304 | struct video_capability *cap = arg; | |
305 | ||
c77990e7 CG |
306 | cap2 = kzalloc(sizeof(*cap2), GFP_KERNEL); |
307 | if (!cap2) { | |
308 | err = -ENOMEM; | |
309 | break; | |
310 | } | |
1da177e4 | 311 | memset(cap, 0, sizeof(*cap)); |
1da177e4 LT |
312 | memset(&fbuf2, 0, sizeof(fbuf2)); |
313 | ||
314 | err = drv(inode, file, VIDIOC_QUERYCAP, cap2); | |
315 | if (err < 0) { | |
316 | dprintk("VIDIOCGCAP / VIDIOC_QUERYCAP: %d\n",err); | |
317 | break; | |
318 | } | |
319 | if (cap2->capabilities & V4L2_CAP_VIDEO_OVERLAY) { | |
320 | err = drv(inode, file, VIDIOC_G_FBUF, &fbuf2); | |
321 | if (err < 0) { | |
322 | dprintk("VIDIOCGCAP / VIDIOC_G_FBUF: %d\n",err); | |
323 | memset(&fbuf2, 0, sizeof(fbuf2)); | |
324 | } | |
325 | err = 0; | |
326 | } | |
327 | ||
328 | memcpy(cap->name, cap2->card, | |
329 | min(sizeof(cap->name), sizeof(cap2->card))); | |
330 | cap->name[sizeof(cap->name) - 1] = 0; | |
331 | if (cap2->capabilities & V4L2_CAP_VIDEO_CAPTURE) | |
332 | cap->type |= VID_TYPE_CAPTURE; | |
333 | if (cap2->capabilities & V4L2_CAP_TUNER) | |
334 | cap->type |= VID_TYPE_TUNER; | |
335 | if (cap2->capabilities & V4L2_CAP_VBI_CAPTURE) | |
336 | cap->type |= VID_TYPE_TELETEXT; | |
337 | if (cap2->capabilities & V4L2_CAP_VIDEO_OVERLAY) | |
338 | cap->type |= VID_TYPE_OVERLAY; | |
339 | if (fbuf2.capability & V4L2_FBUF_CAP_LIST_CLIPPING) | |
340 | cap->type |= VID_TYPE_CLIPPING; | |
341 | ||
342 | cap->channels = count_inputs(inode,file,drv); | |
343 | check_size(inode,file,drv, | |
344 | &cap->maxwidth,&cap->maxheight); | |
345 | cap->audios = 0; /* FIXME */ | |
346 | cap->minwidth = 48; /* FIXME */ | |
347 | cap->minheight = 32; /* FIXME */ | |
348 | break; | |
349 | } | |
350 | case VIDIOCGFBUF: /* get frame buffer */ | |
351 | { | |
352 | struct video_buffer *buffer = arg; | |
353 | ||
37026278 | 354 | memset(buffer, 0, sizeof(*buffer)); |
499c1869 | 355 | memset(&fbuf2, 0, sizeof(fbuf2)); |
37026278 | 356 | |
1da177e4 LT |
357 | err = drv(inode, file, VIDIOC_G_FBUF, &fbuf2); |
358 | if (err < 0) { | |
359 | dprintk("VIDIOCGFBUF / VIDIOC_G_FBUF: %d\n",err); | |
360 | break; | |
361 | } | |
362 | buffer->base = fbuf2.base; | |
363 | buffer->height = fbuf2.fmt.height; | |
364 | buffer->width = fbuf2.fmt.width; | |
365 | ||
366 | switch (fbuf2.fmt.pixelformat) { | |
367 | case V4L2_PIX_FMT_RGB332: | |
368 | buffer->depth = 8; | |
37026278 | 369 | break; |
1da177e4 LT |
370 | case V4L2_PIX_FMT_RGB555: |
371 | buffer->depth = 15; | |
372 | break; | |
373 | case V4L2_PIX_FMT_RGB565: | |
374 | buffer->depth = 16; | |
375 | break; | |
376 | case V4L2_PIX_FMT_BGR24: | |
377 | buffer->depth = 24; | |
378 | break; | |
379 | case V4L2_PIX_FMT_BGR32: | |
380 | buffer->depth = 32; | |
381 | break; | |
382 | default: | |
383 | buffer->depth = 0; | |
384 | } | |
37026278 | 385 | if (fbuf2.fmt.bytesperline) { |
1da177e4 | 386 | buffer->bytesperline = fbuf2.fmt.bytesperline; |
37026278 MCC |
387 | if (!buffer->depth && buffer->width) |
388 | buffer->depth = ((fbuf2.fmt.bytesperline<<3) | |
389 | + (buffer->width-1) ) | |
390 | /buffer->width; | |
391 | } else { | |
1da177e4 LT |
392 | buffer->bytesperline = |
393 | (buffer->width * buffer->depth + 7) & 7; | |
394 | buffer->bytesperline >>= 3; | |
395 | } | |
396 | break; | |
397 | } | |
398 | case VIDIOCSFBUF: /* set frame buffer */ | |
399 | { | |
400 | struct video_buffer *buffer = arg; | |
401 | ||
402 | memset(&fbuf2, 0, sizeof(fbuf2)); | |
403 | fbuf2.base = buffer->base; | |
404 | fbuf2.fmt.height = buffer->height; | |
405 | fbuf2.fmt.width = buffer->width; | |
406 | switch (buffer->depth) { | |
407 | case 8: | |
408 | fbuf2.fmt.pixelformat = V4L2_PIX_FMT_RGB332; | |
409 | break; | |
410 | case 15: | |
411 | fbuf2.fmt.pixelformat = V4L2_PIX_FMT_RGB555; | |
412 | break; | |
413 | case 16: | |
414 | fbuf2.fmt.pixelformat = V4L2_PIX_FMT_RGB565; | |
415 | break; | |
416 | case 24: | |
417 | fbuf2.fmt.pixelformat = V4L2_PIX_FMT_BGR24; | |
418 | break; | |
419 | case 32: | |
420 | fbuf2.fmt.pixelformat = V4L2_PIX_FMT_BGR32; | |
421 | break; | |
422 | } | |
423 | fbuf2.fmt.bytesperline = buffer->bytesperline; | |
424 | err = drv(inode, file, VIDIOC_S_FBUF, &fbuf2); | |
425 | if (err < 0) | |
426 | dprintk("VIDIOCSFBUF / VIDIOC_S_FBUF: %d\n",err); | |
427 | break; | |
428 | } | |
429 | case VIDIOCGWIN: /* get window or capture dimensions */ | |
430 | { | |
431 | struct video_window *win = arg; | |
432 | ||
c77990e7 CG |
433 | fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL); |
434 | if (!fmt2) { | |
435 | err = -ENOMEM; | |
436 | break; | |
437 | } | |
1da177e4 | 438 | memset(win,0,sizeof(*win)); |
1da177e4 LT |
439 | |
440 | fmt2->type = V4L2_BUF_TYPE_VIDEO_OVERLAY; | |
441 | err = drv(inode, file, VIDIOC_G_FMT, fmt2); | |
442 | if (err < 0) | |
443 | dprintk("VIDIOCGWIN / VIDIOC_G_WIN: %d\n",err); | |
444 | if (err == 0) { | |
445 | win->x = fmt2->fmt.win.w.left; | |
446 | win->y = fmt2->fmt.win.w.top; | |
447 | win->width = fmt2->fmt.win.w.width; | |
448 | win->height = fmt2->fmt.win.w.height; | |
449 | win->chromakey = fmt2->fmt.win.chromakey; | |
450 | win->clips = NULL; | |
451 | win->clipcount = 0; | |
452 | break; | |
453 | } | |
454 | ||
455 | fmt2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
456 | err = drv(inode, file, VIDIOC_G_FMT, fmt2); | |
457 | if (err < 0) { | |
458 | dprintk("VIDIOCGWIN / VIDIOC_G_FMT: %d\n",err); | |
459 | break; | |
460 | } | |
461 | win->x = 0; | |
462 | win->y = 0; | |
463 | win->width = fmt2->fmt.pix.width; | |
464 | win->height = fmt2->fmt.pix.height; | |
465 | win->chromakey = 0; | |
466 | win->clips = NULL; | |
467 | win->clipcount = 0; | |
468 | break; | |
469 | } | |
470 | case VIDIOCSWIN: /* set window and/or capture dimensions */ | |
471 | { | |
472 | struct video_window *win = arg; | |
473 | int err1,err2; | |
474 | ||
c77990e7 CG |
475 | fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL); |
476 | if (!fmt2) { | |
477 | err = -ENOMEM; | |
478 | break; | |
479 | } | |
1da177e4 LT |
480 | fmt2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
481 | drv(inode, file, VIDIOC_STREAMOFF, &fmt2->type); | |
482 | err1 = drv(inode, file, VIDIOC_G_FMT, fmt2); | |
483 | if (err1 < 0) | |
484 | dprintk("VIDIOCSWIN / VIDIOC_G_FMT: %d\n",err); | |
485 | if (err1 == 0) { | |
486 | fmt2->fmt.pix.width = win->width; | |
487 | fmt2->fmt.pix.height = win->height; | |
488 | fmt2->fmt.pix.field = V4L2_FIELD_ANY; | |
489 | fmt2->fmt.pix.bytesperline = 0; | |
490 | err = drv(inode, file, VIDIOC_S_FMT, fmt2); | |
491 | if (err < 0) | |
492 | dprintk("VIDIOCSWIN / VIDIOC_S_FMT #1: %d\n", | |
493 | err); | |
494 | win->width = fmt2->fmt.pix.width; | |
495 | win->height = fmt2->fmt.pix.height; | |
496 | } | |
497 | ||
498 | memset(fmt2,0,sizeof(*fmt2)); | |
499 | fmt2->type = V4L2_BUF_TYPE_VIDEO_OVERLAY; | |
500 | fmt2->fmt.win.w.left = win->x; | |
501 | fmt2->fmt.win.w.top = win->y; | |
502 | fmt2->fmt.win.w.width = win->width; | |
503 | fmt2->fmt.win.w.height = win->height; | |
504 | fmt2->fmt.win.chromakey = win->chromakey; | |
505 | fmt2->fmt.win.clips = (void __user *)win->clips; | |
506 | fmt2->fmt.win.clipcount = win->clipcount; | |
507 | err2 = drv(inode, file, VIDIOC_S_FMT, fmt2); | |
508 | if (err2 < 0) | |
509 | dprintk("VIDIOCSWIN / VIDIOC_S_FMT #2: %d\n",err); | |
510 | ||
511 | if (err1 != 0 && err2 != 0) | |
512 | err = err1; | |
513 | break; | |
514 | } | |
515 | case VIDIOCCAPTURE: /* turn on/off preview */ | |
516 | { | |
517 | int *on = arg; | |
518 | ||
519 | if (0 == *on) { | |
520 | /* dirty hack time. But v4l1 has no STREAMOFF | |
521 | * equivalent in the API, and this one at | |
522 | * least comes close ... */ | |
523 | drv(inode, file, VIDIOC_STREAMOFF, &captype); | |
524 | } | |
525 | err = drv(inode, file, VIDIOC_OVERLAY, arg); | |
526 | if (err < 0) | |
527 | dprintk("VIDIOCCAPTURE / VIDIOC_PREVIEW: %d\n",err); | |
528 | break; | |
529 | } | |
530 | case VIDIOCGCHAN: /* get input information */ | |
531 | { | |
532 | struct video_channel *chan = arg; | |
533 | ||
534 | memset(&input2,0,sizeof(input2)); | |
535 | input2.index = chan->channel; | |
536 | err = drv(inode, file, VIDIOC_ENUMINPUT, &input2); | |
537 | if (err < 0) { | |
538 | dprintk("VIDIOCGCHAN / VIDIOC_ENUMINPUT: " | |
539 | "channel=%d err=%d\n",chan->channel,err); | |
540 | break; | |
541 | } | |
542 | chan->channel = input2.index; | |
543 | memcpy(chan->name, input2.name, | |
544 | min(sizeof(chan->name), sizeof(input2.name))); | |
545 | chan->name[sizeof(chan->name) - 1] = 0; | |
546 | chan->tuners = (input2.type == V4L2_INPUT_TYPE_TUNER) ? 1 : 0; | |
547 | chan->flags = (chan->tuners) ? VIDEO_VC_TUNER : 0; | |
548 | switch (input2.type) { | |
549 | case V4L2_INPUT_TYPE_TUNER: | |
550 | chan->type = VIDEO_TYPE_TV; | |
551 | break; | |
552 | default: | |
553 | case V4L2_INPUT_TYPE_CAMERA: | |
554 | chan->type = VIDEO_TYPE_CAMERA; | |
555 | break; | |
556 | } | |
557 | chan->norm = 0; | |
558 | err = drv(inode, file, VIDIOC_G_STD, &sid); | |
559 | if (err < 0) | |
560 | dprintk("VIDIOCGCHAN / VIDIOC_G_STD: %d\n",err); | |
561 | if (err == 0) { | |
562 | if (sid & V4L2_STD_PAL) | |
563 | chan->norm = VIDEO_MODE_PAL; | |
564 | if (sid & V4L2_STD_NTSC) | |
565 | chan->norm = VIDEO_MODE_NTSC; | |
566 | if (sid & V4L2_STD_SECAM) | |
567 | chan->norm = VIDEO_MODE_SECAM; | |
568 | } | |
569 | break; | |
570 | } | |
571 | case VIDIOCSCHAN: /* set input */ | |
572 | { | |
573 | struct video_channel *chan = arg; | |
574 | ||
575 | sid = 0; | |
576 | err = drv(inode, file, VIDIOC_S_INPUT, &chan->channel); | |
577 | if (err < 0) | |
578 | dprintk("VIDIOCSCHAN / VIDIOC_S_INPUT: %d\n",err); | |
579 | switch (chan->norm) { | |
580 | case VIDEO_MODE_PAL: | |
581 | sid = V4L2_STD_PAL; | |
582 | break; | |
583 | case VIDEO_MODE_NTSC: | |
584 | sid = V4L2_STD_NTSC; | |
585 | break; | |
586 | case VIDEO_MODE_SECAM: | |
587 | sid = V4L2_STD_SECAM; | |
588 | break; | |
589 | } | |
590 | if (0 != sid) { | |
591 | err = drv(inode, file, VIDIOC_S_STD, &sid); | |
592 | if (err < 0) | |
593 | dprintk("VIDIOCSCHAN / VIDIOC_S_STD: %d\n",err); | |
594 | } | |
595 | break; | |
596 | } | |
597 | case VIDIOCGPICT: /* get tone controls & partial capture format */ | |
598 | { | |
599 | struct video_picture *pict = arg; | |
600 | ||
c77990e7 CG |
601 | fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL); |
602 | if (!fmt2) { | |
603 | err = -ENOMEM; | |
604 | break; | |
605 | } | |
606 | ||
1da177e4 LT |
607 | pict->brightness = get_v4l_control(inode, file, |
608 | V4L2_CID_BRIGHTNESS,drv); | |
609 | pict->hue = get_v4l_control(inode, file, | |
610 | V4L2_CID_HUE, drv); | |
611 | pict->contrast = get_v4l_control(inode, file, | |
612 | V4L2_CID_CONTRAST, drv); | |
613 | pict->colour = get_v4l_control(inode, file, | |
614 | V4L2_CID_SATURATION, drv); | |
615 | pict->whiteness = get_v4l_control(inode, file, | |
616 | V4L2_CID_WHITENESS, drv); | |
617 | ||
1da177e4 LT |
618 | fmt2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
619 | err = drv(inode, file, VIDIOC_G_FMT, fmt2); | |
620 | if (err < 0) { | |
621 | dprintk("VIDIOCGPICT / VIDIOC_G_FMT: %d\n",err); | |
622 | break; | |
623 | } | |
8a016dcc MCC |
624 | |
625 | pict->depth = ((fmt2->fmt.pix.bytesperline<<3) | |
626 | + (fmt2->fmt.pix.width-1) ) | |
627 | /fmt2->fmt.pix.width; | |
1da177e4 LT |
628 | pict->palette = pixelformat_to_palette( |
629 | fmt2->fmt.pix.pixelformat); | |
630 | break; | |
631 | } | |
632 | case VIDIOCSPICT: /* set tone controls & partial capture format */ | |
633 | { | |
634 | struct video_picture *pict = arg; | |
bbe2486f TP |
635 | int mem_err = 0, ovl_err = 0; |
636 | ||
c77990e7 CG |
637 | fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL); |
638 | if (!fmt2) { | |
639 | err = -ENOMEM; | |
640 | break; | |
641 | } | |
499c1869 | 642 | memset(&fbuf2, 0, sizeof(fbuf2)); |
1da177e4 LT |
643 | |
644 | set_v4l_control(inode, file, | |
645 | V4L2_CID_BRIGHTNESS, pict->brightness, drv); | |
646 | set_v4l_control(inode, file, | |
647 | V4L2_CID_HUE, pict->hue, drv); | |
648 | set_v4l_control(inode, file, | |
649 | V4L2_CID_CONTRAST, pict->contrast, drv); | |
650 | set_v4l_control(inode, file, | |
651 | V4L2_CID_SATURATION, pict->colour, drv); | |
652 | set_v4l_control(inode, file, | |
653 | V4L2_CID_WHITENESS, pict->whiteness, drv); | |
bbe2486f TP |
654 | /* |
655 | * V4L1 uses this ioctl to set both memory capture and overlay | |
656 | * pixel format, while V4L2 has two different ioctls for this. | |
657 | * Some cards may not support one or the other, and may support | |
658 | * different pixel formats for memory vs overlay. | |
659 | */ | |
1da177e4 | 660 | |
1da177e4 LT |
661 | fmt2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
662 | err = drv(inode, file, VIDIOC_G_FMT, fmt2); | |
bbe2486f TP |
663 | /* If VIDIOC_G_FMT failed, then the driver likely doesn't |
664 | support memory capture. Trying to set the memory capture | |
665 | parameters would be pointless. */ | |
666 | if (err < 0) { | |
1da177e4 | 667 | dprintk("VIDIOCSPICT / VIDIOC_G_FMT: %d\n",err); |
bbe2486f TP |
668 | mem_err = -1000; /* didn't even try */ |
669 | } else if (fmt2->fmt.pix.pixelformat != | |
670 | palette_to_pixelformat(pict->palette)) { | |
1da177e4 LT |
671 | fmt2->fmt.pix.pixelformat = palette_to_pixelformat( |
672 | pict->palette); | |
bbe2486f TP |
673 | mem_err = drv(inode, file, VIDIOC_S_FMT, fmt2); |
674 | if (mem_err < 0) | |
675 | dprintk("VIDIOCSPICT / VIDIOC_S_FMT: %d\n", | |
676 | mem_err); | |
1da177e4 LT |
677 | } |
678 | ||
679 | err = drv(inode, file, VIDIOC_G_FBUF, &fbuf2); | |
bbe2486f TP |
680 | /* If VIDIOC_G_FBUF failed, then the driver likely doesn't |
681 | support overlay. Trying to set the overlay parameters | |
682 | would be quite pointless. */ | |
683 | if (err < 0) { | |
1da177e4 | 684 | dprintk("VIDIOCSPICT / VIDIOC_G_FBUF: %d\n",err); |
bbe2486f TP |
685 | ovl_err = -1000; /* didn't even try */ |
686 | } else if (fbuf2.fmt.pixelformat != | |
687 | palette_to_pixelformat(pict->palette)) { | |
1da177e4 LT |
688 | fbuf2.fmt.pixelformat = palette_to_pixelformat( |
689 | pict->palette); | |
bbe2486f TP |
690 | ovl_err = drv(inode, file, VIDIOC_S_FBUF, &fbuf2); |
691 | if (ovl_err < 0) | |
692 | dprintk("VIDIOCSPICT / VIDIOC_S_FBUF: %d\n", | |
693 | ovl_err); | |
1da177e4 | 694 | } |
bbe2486f TP |
695 | if (ovl_err < 0 && mem_err < 0) |
696 | /* ioctl failed, couldn't set either parameter */ | |
697 | if (mem_err != -1000) { | |
698 | err = mem_err; | |
699 | } else if (ovl_err == -EPERM) { | |
700 | err = 0; | |
701 | } else { | |
702 | err = ovl_err; | |
703 | } | |
704 | else | |
705 | err = 0; | |
1da177e4 LT |
706 | break; |
707 | } | |
708 | case VIDIOCGTUNER: /* get tuner information */ | |
709 | { | |
710 | struct video_tuner *tun = arg; | |
711 | ||
712 | memset(&tun2,0,sizeof(tun2)); | |
713 | err = drv(inode, file, VIDIOC_G_TUNER, &tun2); | |
714 | if (err < 0) { | |
715 | dprintk("VIDIOCGTUNER / VIDIOC_G_TUNER: %d\n",err); | |
716 | break; | |
717 | } | |
718 | memcpy(tun->name, tun2.name, | |
719 | min(sizeof(tun->name), sizeof(tun2.name))); | |
720 | tun->name[sizeof(tun->name) - 1] = 0; | |
721 | tun->rangelow = tun2.rangelow; | |
722 | tun->rangehigh = tun2.rangehigh; | |
723 | tun->flags = 0; | |
724 | tun->mode = VIDEO_MODE_AUTO; | |
725 | ||
726 | for (i = 0; i < 64; i++) { | |
727 | memset(&std2,0,sizeof(std2)); | |
728 | std2.index = i; | |
729 | if (0 != drv(inode, file, VIDIOC_ENUMSTD, &std2)) | |
730 | break; | |
731 | if (std2.id & V4L2_STD_PAL) | |
732 | tun->flags |= VIDEO_TUNER_PAL; | |
733 | if (std2.id & V4L2_STD_NTSC) | |
734 | tun->flags |= VIDEO_TUNER_NTSC; | |
735 | if (std2.id & V4L2_STD_SECAM) | |
736 | tun->flags |= VIDEO_TUNER_SECAM; | |
737 | } | |
738 | ||
739 | err = drv(inode, file, VIDIOC_G_STD, &sid); | |
740 | if (err < 0) | |
741 | dprintk("VIDIOCGTUNER / VIDIOC_G_STD: %d\n",err); | |
742 | if (err == 0) { | |
743 | if (sid & V4L2_STD_PAL) | |
744 | tun->mode = VIDEO_MODE_PAL; | |
745 | if (sid & V4L2_STD_NTSC) | |
746 | tun->mode = VIDEO_MODE_NTSC; | |
747 | if (sid & V4L2_STD_SECAM) | |
748 | tun->mode = VIDEO_MODE_SECAM; | |
749 | } | |
750 | ||
751 | if (tun2.capability & V4L2_TUNER_CAP_LOW) | |
752 | tun->flags |= VIDEO_TUNER_LOW; | |
753 | if (tun2.rxsubchans & V4L2_TUNER_SUB_STEREO) | |
754 | tun->flags |= VIDEO_TUNER_STEREO_ON; | |
755 | tun->signal = tun2.signal; | |
756 | break; | |
757 | } | |
758 | case VIDIOCSTUNER: /* select a tuner input */ | |
759 | { | |
2aa92ffd MCC |
760 | struct video_tuner *tun = arg; |
761 | struct v4l2_tuner t; | |
762 | memset(&t,0,sizeof(t)); | |
763 | ||
764 | t.index=tun->tuner; | |
765 | ||
766 | err = drv(inode, file, VIDIOC_S_INPUT, &t); | |
767 | if (err < 0) | |
768 | dprintk("VIDIOCSTUNER / VIDIOC_S_INPUT: %d\n",err); | |
769 | ||
1da177e4 LT |
770 | break; |
771 | } | |
772 | case VIDIOCGFREQ: /* get frequency */ | |
773 | { | |
376f269e | 774 | unsigned long *freq = arg; |
c6aeb111 | 775 | memset(&freq2,0,sizeof(freq2)); |
1da177e4 LT |
776 | |
777 | freq2.tuner = 0; | |
778 | err = drv(inode, file, VIDIOC_G_FREQUENCY, &freq2); | |
779 | if (err < 0) | |
780 | dprintk("VIDIOCGFREQ / VIDIOC_G_FREQUENCY: %d\n",err); | |
781 | if (0 == err) | |
782 | *freq = freq2.frequency; | |
783 | break; | |
784 | } | |
785 | case VIDIOCSFREQ: /* set frequency */ | |
786 | { | |
376f269e | 787 | unsigned long *freq = arg; |
c6aeb111 | 788 | memset(&freq2,0,sizeof(freq2)); |
1da177e4 | 789 | |
1da177e4 LT |
790 | drv(inode, file, VIDIOC_G_FREQUENCY, &freq2); |
791 | freq2.frequency = *freq; | |
792 | err = drv(inode, file, VIDIOC_S_FREQUENCY, &freq2); | |
793 | if (err < 0) | |
794 | dprintk("VIDIOCSFREQ / VIDIOC_S_FREQUENCY: %d\n",err); | |
795 | break; | |
796 | } | |
797 | case VIDIOCGAUDIO: /* get audio properties/controls */ | |
798 | { | |
799 | struct video_audio *aud = arg; | |
c6aeb111 | 800 | memset(&aud2,0,sizeof(aud2)); |
1da177e4 LT |
801 | |
802 | err = drv(inode, file, VIDIOC_G_AUDIO, &aud2); | |
803 | if (err < 0) { | |
804 | dprintk("VIDIOCGAUDIO / VIDIOC_G_AUDIO: %d\n",err); | |
805 | break; | |
806 | } | |
807 | memcpy(aud->name, aud2.name, | |
808 | min(sizeof(aud->name), sizeof(aud2.name))); | |
809 | aud->name[sizeof(aud->name) - 1] = 0; | |
810 | aud->audio = aud2.index; | |
811 | aud->flags = 0; | |
812 | i = get_v4l_control(inode, file, V4L2_CID_AUDIO_VOLUME, drv); | |
813 | if (i >= 0) { | |
814 | aud->volume = i; | |
815 | aud->flags |= VIDEO_AUDIO_VOLUME; | |
816 | } | |
817 | i = get_v4l_control(inode, file, V4L2_CID_AUDIO_BASS, drv); | |
818 | if (i >= 0) { | |
819 | aud->bass = i; | |
820 | aud->flags |= VIDEO_AUDIO_BASS; | |
821 | } | |
822 | i = get_v4l_control(inode, file, V4L2_CID_AUDIO_TREBLE, drv); | |
823 | if (i >= 0) { | |
824 | aud->treble = i; | |
825 | aud->flags |= VIDEO_AUDIO_TREBLE; | |
826 | } | |
827 | i = get_v4l_control(inode, file, V4L2_CID_AUDIO_BALANCE, drv); | |
828 | if (i >= 0) { | |
829 | aud->balance = i; | |
830 | aud->flags |= VIDEO_AUDIO_BALANCE; | |
831 | } | |
832 | i = get_v4l_control(inode, file, V4L2_CID_AUDIO_MUTE, drv); | |
833 | if (i >= 0) { | |
834 | if (i) | |
835 | aud->flags |= VIDEO_AUDIO_MUTE; | |
836 | aud->flags |= VIDEO_AUDIO_MUTABLE; | |
837 | } | |
838 | aud->step = 1; | |
839 | qctrl2.id = V4L2_CID_AUDIO_VOLUME; | |
840 | if (drv(inode, file, VIDIOC_QUERYCTRL, &qctrl2) == 0 && | |
841 | !(qctrl2.flags & V4L2_CTRL_FLAG_DISABLED)) | |
842 | aud->step = qctrl2.step; | |
843 | aud->mode = 0; | |
ac19ecc6 MCC |
844 | |
845 | memset(&tun2,0,sizeof(tun2)); | |
1da177e4 LT |
846 | err = drv(inode, file, VIDIOC_G_TUNER, &tun2); |
847 | if (err < 0) { | |
848 | dprintk("VIDIOCGAUDIO / VIDIOC_G_TUNER: %d\n",err); | |
849 | err = 0; | |
850 | break; | |
851 | } | |
ac19ecc6 | 852 | |
1da177e4 LT |
853 | if (tun2.rxsubchans & V4L2_TUNER_SUB_LANG2) |
854 | aud->mode = VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; | |
855 | else if (tun2.rxsubchans & V4L2_TUNER_SUB_STEREO) | |
856 | aud->mode = VIDEO_SOUND_STEREO; | |
857 | else if (tun2.rxsubchans & V4L2_TUNER_SUB_MONO) | |
858 | aud->mode = VIDEO_SOUND_MONO; | |
859 | break; | |
860 | } | |
861 | case VIDIOCSAUDIO: /* set audio controls */ | |
862 | { | |
863 | struct video_audio *aud = arg; | |
864 | ||
865 | memset(&aud2,0,sizeof(aud2)); | |
866 | memset(&tun2,0,sizeof(tun2)); | |
867 | ||
868 | aud2.index = aud->audio; | |
869 | err = drv(inode, file, VIDIOC_S_AUDIO, &aud2); | |
870 | if (err < 0) { | |
871 | dprintk("VIDIOCSAUDIO / VIDIOC_S_AUDIO: %d\n",err); | |
872 | break; | |
873 | } | |
874 | ||
875 | set_v4l_control(inode, file, V4L2_CID_AUDIO_VOLUME, | |
876 | aud->volume, drv); | |
877 | set_v4l_control(inode, file, V4L2_CID_AUDIO_BASS, | |
878 | aud->bass, drv); | |
879 | set_v4l_control(inode, file, V4L2_CID_AUDIO_TREBLE, | |
880 | aud->treble, drv); | |
881 | set_v4l_control(inode, file, V4L2_CID_AUDIO_BALANCE, | |
882 | aud->balance, drv); | |
883 | set_v4l_control(inode, file, V4L2_CID_AUDIO_MUTE, | |
884 | !!(aud->flags & VIDEO_AUDIO_MUTE), drv); | |
885 | ||
886 | err = drv(inode, file, VIDIOC_G_TUNER, &tun2); | |
887 | if (err < 0) | |
888 | dprintk("VIDIOCSAUDIO / VIDIOC_G_TUNER: %d\n",err); | |
889 | if (err == 0) { | |
890 | switch (aud->mode) { | |
891 | default: | |
892 | case VIDEO_SOUND_MONO: | |
893 | case VIDEO_SOUND_LANG1: | |
894 | tun2.audmode = V4L2_TUNER_MODE_MONO; | |
895 | break; | |
896 | case VIDEO_SOUND_STEREO: | |
897 | tun2.audmode = V4L2_TUNER_MODE_STEREO; | |
898 | break; | |
899 | case VIDEO_SOUND_LANG2: | |
900 | tun2.audmode = V4L2_TUNER_MODE_LANG2; | |
901 | break; | |
902 | } | |
903 | err = drv(inode, file, VIDIOC_S_TUNER, &tun2); | |
904 | if (err < 0) | |
905 | dprintk("VIDIOCSAUDIO / VIDIOC_S_TUNER: %d\n",err); | |
906 | } | |
907 | err = 0; | |
908 | break; | |
909 | } | |
1da177e4 LT |
910 | case VIDIOCMCAPTURE: /* capture a frame */ |
911 | { | |
912 | struct video_mmap *mm = arg; | |
913 | ||
c77990e7 CG |
914 | fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL); |
915 | if (!fmt2) { | |
916 | err = -ENOMEM; | |
917 | break; | |
918 | } | |
1da177e4 | 919 | memset(&buf2,0,sizeof(buf2)); |
1da177e4 LT |
920 | |
921 | fmt2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
922 | err = drv(inode, file, VIDIOC_G_FMT, fmt2); | |
923 | if (err < 0) { | |
924 | dprintk("VIDIOCMCAPTURE / VIDIOC_G_FMT: %d\n",err); | |
925 | break; | |
926 | } | |
927 | if (mm->width != fmt2->fmt.pix.width || | |
928 | mm->height != fmt2->fmt.pix.height || | |
929 | palette_to_pixelformat(mm->format) != | |
930 | fmt2->fmt.pix.pixelformat) | |
931 | {/* New capture format... */ | |
932 | fmt2->fmt.pix.width = mm->width; | |
933 | fmt2->fmt.pix.height = mm->height; | |
934 | fmt2->fmt.pix.pixelformat = | |
935 | palette_to_pixelformat(mm->format); | |
936 | fmt2->fmt.pix.field = V4L2_FIELD_ANY; | |
937 | fmt2->fmt.pix.bytesperline = 0; | |
938 | err = drv(inode, file, VIDIOC_S_FMT, fmt2); | |
939 | if (err < 0) { | |
940 | dprintk("VIDIOCMCAPTURE / VIDIOC_S_FMT: %d\n",err); | |
941 | break; | |
942 | } | |
943 | } | |
944 | buf2.index = mm->frame; | |
945 | buf2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
946 | err = drv(inode, file, VIDIOC_QUERYBUF, &buf2); | |
947 | if (err < 0) { | |
948 | dprintk("VIDIOCMCAPTURE / VIDIOC_QUERYBUF: %d\n",err); | |
949 | break; | |
950 | } | |
951 | err = drv(inode, file, VIDIOC_QBUF, &buf2); | |
952 | if (err < 0) { | |
953 | dprintk("VIDIOCMCAPTURE / VIDIOC_QBUF: %d\n",err); | |
954 | break; | |
955 | } | |
956 | err = drv(inode, file, VIDIOC_STREAMON, &captype); | |
957 | if (err < 0) | |
958 | dprintk("VIDIOCMCAPTURE / VIDIOC_STREAMON: %d\n",err); | |
959 | break; | |
960 | } | |
961 | case VIDIOCSYNC: /* wait for a frame */ | |
962 | { | |
963 | int *i = arg; | |
964 | ||
c6aeb111 | 965 | memset(&buf2,0,sizeof(buf2)); |
1da177e4 LT |
966 | buf2.index = *i; |
967 | buf2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
968 | err = drv(inode, file, VIDIOC_QUERYBUF, &buf2); | |
969 | if (err < 0) { | |
970 | /* No such buffer */ | |
971 | dprintk("VIDIOCSYNC / VIDIOC_QUERYBUF: %d\n",err); | |
972 | break; | |
973 | } | |
974 | if (!(buf2.flags & V4L2_BUF_FLAG_MAPPED)) { | |
975 | /* Buffer is not mapped */ | |
976 | err = -EINVAL; | |
977 | break; | |
978 | } | |
979 | ||
980 | /* make sure capture actually runs so we don't block forever */ | |
981 | err = drv(inode, file, VIDIOC_STREAMON, &captype); | |
982 | if (err < 0) { | |
983 | dprintk("VIDIOCSYNC / VIDIOC_STREAMON: %d\n",err); | |
984 | break; | |
985 | } | |
986 | ||
987 | /* Loop as long as the buffer is queued, but not done */ | |
988 | while ((buf2.flags & | |
989 | (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE)) | |
990 | == V4L2_BUF_FLAG_QUEUED) | |
991 | { | |
992 | err = poll_one(file); | |
993 | if (err < 0 || /* error or sleep was interrupted */ | |
994 | err == 0) /* timeout? Shouldn't occur. */ | |
995 | break; | |
996 | err = drv(inode, file, VIDIOC_QUERYBUF, &buf2); | |
997 | if (err < 0) | |
998 | dprintk("VIDIOCSYNC / VIDIOC_QUERYBUF: %d\n",err); | |
999 | } | |
1000 | if (!(buf2.flags & V4L2_BUF_FLAG_DONE)) /* not done */ | |
1001 | break; | |
1002 | do { | |
1003 | err = drv(inode, file, VIDIOC_DQBUF, &buf2); | |
1004 | if (err < 0) | |
1005 | dprintk("VIDIOCSYNC / VIDIOC_DQBUF: %d\n",err); | |
1006 | } while (err == 0 && buf2.index != *i); | |
1007 | break; | |
1008 | } | |
1009 | ||
1010 | case VIDIOCGVBIFMT: /* query VBI data capture format */ | |
1011 | { | |
1012 | struct vbi_format *fmt = arg; | |
1013 | ||
c77990e7 CG |
1014 | fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL); |
1015 | if (!fmt2) { | |
1016 | err = -ENOMEM; | |
1017 | break; | |
1018 | } | |
1da177e4 LT |
1019 | fmt2->type = V4L2_BUF_TYPE_VBI_CAPTURE; |
1020 | ||
1021 | err = drv(inode, file, VIDIOC_G_FMT, fmt2); | |
1022 | if (err < 0) { | |
1023 | dprintk("VIDIOCGVBIFMT / VIDIOC_G_FMT: %d\n", err); | |
1024 | break; | |
1025 | } | |
67f1570a MS |
1026 | if (fmt2->fmt.vbi.sample_format != V4L2_PIX_FMT_GREY) { |
1027 | err = -EINVAL; | |
1028 | break; | |
1029 | } | |
1da177e4 LT |
1030 | memset(fmt, 0, sizeof(*fmt)); |
1031 | fmt->samples_per_line = fmt2->fmt.vbi.samples_per_line; | |
1032 | fmt->sampling_rate = fmt2->fmt.vbi.sampling_rate; | |
1033 | fmt->sample_format = VIDEO_PALETTE_RAW; | |
1034 | fmt->start[0] = fmt2->fmt.vbi.start[0]; | |
1035 | fmt->count[0] = fmt2->fmt.vbi.count[0]; | |
1036 | fmt->start[1] = fmt2->fmt.vbi.start[1]; | |
1037 | fmt->count[1] = fmt2->fmt.vbi.count[1]; | |
1038 | fmt->flags = fmt2->fmt.vbi.flags & 0x03; | |
4ac97914 | 1039 | break; |
1da177e4 LT |
1040 | } |
1041 | case VIDIOCSVBIFMT: | |
1042 | { | |
1043 | struct vbi_format *fmt = arg; | |
1044 | ||
67f1570a MS |
1045 | if (VIDEO_PALETTE_RAW != fmt->sample_format) { |
1046 | err = -EINVAL; | |
1047 | break; | |
1048 | } | |
1049 | ||
c77990e7 CG |
1050 | fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL); |
1051 | if (!fmt2) { | |
1052 | err = -ENOMEM; | |
1053 | break; | |
1054 | } | |
1da177e4 LT |
1055 | fmt2->type = V4L2_BUF_TYPE_VBI_CAPTURE; |
1056 | fmt2->fmt.vbi.samples_per_line = fmt->samples_per_line; | |
1057 | fmt2->fmt.vbi.sampling_rate = fmt->sampling_rate; | |
1058 | fmt2->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; | |
1059 | fmt2->fmt.vbi.start[0] = fmt->start[0]; | |
1060 | fmt2->fmt.vbi.count[0] = fmt->count[0]; | |
1061 | fmt2->fmt.vbi.start[1] = fmt->start[1]; | |
1062 | fmt2->fmt.vbi.count[1] = fmt->count[1]; | |
1063 | fmt2->fmt.vbi.flags = fmt->flags; | |
1064 | err = drv(inode, file, VIDIOC_TRY_FMT, fmt2); | |
1065 | if (err < 0) { | |
1066 | dprintk("VIDIOCSVBIFMT / VIDIOC_TRY_FMT: %d\n", err); | |
1067 | break; | |
1068 | } | |
1069 | ||
1070 | if (fmt2->fmt.vbi.samples_per_line != fmt->samples_per_line || | |
1071 | fmt2->fmt.vbi.sampling_rate != fmt->sampling_rate || | |
67f1570a | 1072 | fmt2->fmt.vbi.sample_format != V4L2_PIX_FMT_GREY || |
1da177e4 LT |
1073 | fmt2->fmt.vbi.start[0] != fmt->start[0] || |
1074 | fmt2->fmt.vbi.count[0] != fmt->count[0] || | |
1075 | fmt2->fmt.vbi.start[1] != fmt->start[1] || | |
1076 | fmt2->fmt.vbi.count[1] != fmt->count[1] || | |
1077 | fmt2->fmt.vbi.flags != fmt->flags) { | |
1078 | err = -EINVAL; | |
1079 | break; | |
1080 | } | |
1081 | err = drv(inode, file, VIDIOC_S_FMT, fmt2); | |
1082 | if (err < 0) | |
1083 | dprintk("VIDIOCSVBIFMT / VIDIOC_S_FMT: %d\n", err); | |
1084 | break; | |
1085 | } | |
1086 | ||
1087 | default: | |
1088 | err = -ENOIOCTLCMD; | |
1089 | break; | |
1090 | } | |
1091 | ||
2ea75330 JJ |
1092 | kfree(cap2); |
1093 | kfree(fmt2); | |
1da177e4 LT |
1094 | return err; |
1095 | } | |
1096 | ||
1097 | EXPORT_SYMBOL(v4l_compat_translate_ioctl); | |
1098 | ||
1099 | /* | |
1100 | * Local variables: | |
1101 | * c-basic-offset: 8 | |
1102 | * End: | |
1103 | */ |